Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Android: Fix write detection #727

Merged
merged 6 commits into from Jan 17, 2016
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
6 changes: 3 additions & 3 deletions builds/android/res/menu/game_browser_supported_key.xml
@@ -1,8 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android" >
<item android:id="@+id/Enter" android:title="Enter"/>
<item android:id="@+id/Cancel" android:title="Cancel"/>
<item android:id="@+id/Shift" android:title="Shift"/>
<item android:id="@+id/Enter" android:title="@string/key_enter"/>
<item android:id="@+id/Cancel" android:title="@string/key_cancel"/>
<item android:id="@+id/Shift" android:title="@string/key_shift"/>
<item android:id="@+id/N0" android:title="0"/>
<item android:id="@+id/N1" android:title="1"/>
<item android:id="@+id/N2" android:title="2"/>
Expand Down
2 changes: 2 additions & 0 deletions builds/android/res/menu/player.xml
Expand Up @@ -4,6 +4,8 @@
android:title="@string/toggle_fps"/>
<item android:id="@+id/toggle_ui"
android:title="@string/toggle_ui" />
<item android:id="@+id/report_bug"
android:title="@string/report_bug" />
<item android:id="@+id/end_game"
android:title="@string/end_game" />
</menu>
21 changes: 17 additions & 4 deletions builds/android/res/values/strings.xml
Expand Up @@ -11,9 +11,6 @@

<!--GameBrowser Activity-->
<string name="app_name" translate="false">EasyRPG Player</string>
<string name="toggle_fps">Toggle FPS</string>
<string name="toggle_ui">Toggle Virtual Buttons</string>
<string name="end_game">End Game</string>
<string name="autodetect">Autodetect Region (Recommended)</string>
<string name="west_europe">Western European</string>
<string name="east_europe">Central/Eastern European</string>
Expand Down Expand Up @@ -61,6 +58,19 @@ Special features:\n
You can add additional on-screen buttons. Tap the menu button to edit screen buttons position.\n
Once there, tap the back button to access to an additional menu to add more buttons to the screen.
</string>

<!--Ingame menu-->
<string name="toggle_fps">Toggle FPS</string>
<string name="toggle_ui">Toggle Virtual Buttons</string>
<string name="end_game">End Game</string>
<string name="report_bug">Report a bug (via E-Mail)</string>
<string name="report_bug_text">Thank you for supporting EasyRPG Player.\n
A logfile and your savegames were attached to this E-Mail.\n
Please don\'t remove the logfile! We need a savegame that is close to the bug location.\n
We speak English, German and Spanish.\n
Please tell us in detail what went wrong.\n
[You can remove this instruction text]
</string>

<!--Settings Activity-->
<string name="settings">Settings</string>
Expand All @@ -85,5 +95,8 @@ Once there, tap the back button to access to an additional menu to add more butt
<string name="add_a_button">Add a button</string>
<string name="reset_button_mapping">Reset button mapping</string>
<string name="exit_without_saving">Exit without saving</string>
<string name="save_and_quit">Save and quit</string>
<string name="save_and_quit">Save and quit</string>
<string name="key_enter">Enter (Z)</string>
<string name="key_cancel">Cancel (X)</string>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please consider mentioning Esc too.

<string name="key_shift">Shift</string>
</resources>
Expand Up @@ -9,6 +9,7 @@

import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.res.Configuration;
Expand Down Expand Up @@ -128,7 +129,12 @@ public void save(){
}

public void showSupportedButton(){
final CharSequence[] items = {"Enter", "Cancel", "Shift", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "+", "-", "*", "/"};
Context ctx = getApplicationContext();
final CharSequence[] items = {
ctx.getString(R.string.key_enter),
ctx.getString(R.string.key_cancel),
ctx.getString(R.string.key_shift),
"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "+", "-", "*", "/"};
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle(getResources().getString(R.string.add_a_button));
builder.setItems(items, new DialogInterface.OnClickListener() {
Expand Down
@@ -1,7 +1,12 @@
package org.easyrpg.player.game_browser;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.nio.channels.FileChannel;
import java.util.ArrayList;
import java.util.LinkedList;

Expand Down Expand Up @@ -149,7 +154,116 @@ public static File getIniOfGame(String path, boolean create) {
return null;
}

public static void launchGame(Context context, ProjectInformation project){
public static Boolean canWrite(File f) {
if (f.isDirectory()) {
FileWriter w = null;
String testFilename = f.getPath() + "/.EASYRPG_WRITE_TEST";
try {
w = new FileWriter(testFilename);
// Permissions are checked on open, but it is Android, better be save
w.write("Android >.<");
} catch (IOException e) {
return false;
} finally {
try {
if (w != null) {
w.close();
}
} catch (IOException e) {}
}

File testFile = new File(testFilename);
if (testFile.exists()) {
// Does not throw
testFile.delete();
}
} else {
boolean deleteAfter = f.exists();
try {
FileWriter w = new FileWriter(f, true);
w.close();
} catch (IOException e) {
return false;
}

if (deleteAfter) {
f.delete();
}
}

return true;
}

// https://stackoverflow.com/q/106770/
public static void copyFile(File sourceFile, File destFile) throws IOException {
if(!destFile.exists()) {
destFile.createNewFile();
}

FileChannel source = null;
FileChannel destination = null;

try {
source = new FileInputStream(sourceFile).getChannel();
destination = new FileOutputStream(destFile).getChannel();
destination.transferFrom(source, 0, source.size());
}
finally {
if(source != null) {
source.close();
}
if(destination != null) {
destination.close();
}
}
}

private static boolean saveDirectoryContainsSave(ProjectInformation project) {
if (project.getPath().equals(project.getSavePath())) {
// Doesn't matter because this is used for the copying logic to the save directory
return true;
}

File[] files = getSavegames(new File(project.getSavePath()));
return files.length > 0;
}

private static void copySavesFromGameDirectoryToSaveDirectory(ProjectInformation project) {
if (project.getPath().equals(project.getSavePath())) {
return;
}

File[] files = getSavegames(new File(project.getPath()));
for (final File fileEntry : files) {
try {
copyFile(fileEntry, new File(project.getSavePath() + "/" + fileEntry.getName()));
} catch (IOException e) {
}
}
}

public static File[] getSavegames(File folder) {
File[] files = folder.listFiles();
ArrayList<File> saveFiles = new ArrayList<File>();
if (files != null) {
for (final File fileEntry : files) {
if (fileEntry.isFile()) {
if (fileEntry.getName().toLowerCase().endsWith(".lsd")) {
saveFiles.add(fileEntry);
}
}
}
}
return saveFiles.toArray(new File[saveFiles.size()]);
}

public static void launchGame(Context context, ProjectInformation project) {
// Prepare savegames, copy them to the save directory on launch to prevent unwanted side effects
// e.g. games copied from PC with savegames, or from internal storage.
if (!saveDirectoryContainsSave(project)) {
copySavesFromGameDirectoryToSaveDirectory(project);
}

String path = project.getPath();

// Test again in case somebody messed with the file system
Expand All @@ -172,6 +286,7 @@ public static void launchGame(Context context, ProjectInformation project){
args.add(project.getEncoding());
}

intent.putExtra(EasyRpgPlayerActivity.TAG_SAVE_PATH, project.getSavePath());
intent.putExtra(EasyRpgPlayerActivity.TAG_PROJECT_PATH, path);
intent.putExtra(EasyRpgPlayerActivity.TAG_COMMAND_LINE, args.toArray(new String[args.size()]));
context.startActivity(intent);
Expand Down
Expand Up @@ -24,7 +24,7 @@ public ProjectInformation(String path) {
this.path = path;
File f = new File(path);

if (f.canWrite()) {
if (GameBrowserHelper.canWrite(f)) {
this.save_path = path;
} else {
// Not writable, redirect to a different path
Expand Down
Expand Up @@ -25,19 +25,23 @@
package org.easyrpg.player.player;

import java.io.File;
import java.util.ArrayList;

import org.easyrpg.player.Helper;
import org.easyrpg.player.R;
import org.easyrpg.player.SettingsActivity;
import org.easyrpg.player.button_mapping.ButtonMappingModel;
import org.easyrpg.player.button_mapping.ButtonMappingModel.InputLayout;
import org.easyrpg.player.button_mapping.VirtualButton;
import org.easyrpg.player.game_browser.GameBrowserHelper;
import org.easyrpg.player.game_browser.ProjectInformation;
import org.libsdl.app.SDLActivity;

import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.res.Configuration;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.util.DisplayMetrics;
Expand All @@ -55,6 +59,7 @@

public class EasyRpgPlayerActivity extends SDLActivity {
public static final String TAG_PROJECT_PATH = "project_path";
public static final String TAG_SAVE_PATH = "save_path";
public static final String TAG_COMMAND_LINE = "command_line";

ButtonMappingModel bmm;
Expand Down Expand Up @@ -122,6 +127,9 @@ public boolean onOptionsItemSelected(MenuItem item) {
}
uiVisible = !uiVisible;
return true;
case R.id.report_bug:
reportBug();
return true;
case R.id.end_game:
showEndGameDialog();
return true;
Expand All @@ -130,6 +138,26 @@ public boolean onOptionsItemSelected(MenuItem item) {
}
}

private void reportBug() {
ArrayList<Uri> files = new ArrayList<Uri>();
String savepath = getIntent().getStringExtra(TAG_SAVE_PATH);
files.add(Uri.fromFile(new File(savepath + "/easyrpg_log.txt")));
for (File f : GameBrowserHelper.getSavegames(new File(savepath))) {
files.add(Uri.fromFile(f));
}

Intent intent = new Intent(Intent.ACTION_SEND_MULTIPLE);
intent.setData(Uri.parse("mailto:"));
intent.setType("*/*");
intent.putExtra(Intent.EXTRA_EMAIL, new String[] {"easyrpg@easy-rpg.org"});
intent.putExtra(Intent.EXTRA_SUBJECT, "Bug report");
intent.putExtra(Intent.EXTRA_TEXT, getApplicationContext().getString(R.string.report_bug_text));
intent.putExtra(Intent.EXTRA_STREAM, files);
if (intent.resolveActivity(getPackageManager()) != null) {
startActivity(intent);
}
}

@Override
public void onBackPressed() {
openOptionsMenu();
Expand Down
10 changes: 10 additions & 0 deletions src/output.cpp
Expand Up @@ -93,6 +93,8 @@ namespace {
assert(0 <= result && result < int(sizeof(buf)));
return std::string(buf, result);
}

std::vector<std::string> log_buffer;
}

void Output::IgnorePause(bool const val) {
Expand All @@ -103,7 +105,15 @@ static void WriteLog(std::string const& type, std::string const& msg, Color cons
if (!Main_Data::GetSavePath().empty()) {
// Only write to file when project path is initialized
// (happens after parsing the command line)
for (std::string& log : log_buffer) {
output_time() << log << std::endl;
}
log_buffer.clear();

output_time() << type << ": " << msg << std::endl;
} else {
// buffer log messages until file system is ready
log_buffer.push_back(type + ": " + msg);
}

#ifdef __ANDROID__
Expand Down