mirror of
https://github.com/mauiaaron/apple2.git
synced 2024-09-28 16:54:51 +00:00
Rename emulator.state to emulator.a2state and handle migration
This commit is contained in:
parent
dacf0de80e
commit
d98c4afa84
@ -23,12 +23,14 @@ import android.view.KeyEvent;
|
|||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.widget.FrameLayout;
|
import android.widget.FrameLayout;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
|
||||||
import org.deadc0de.apple2ix.basic.BuildConfig;
|
import org.deadc0de.apple2ix.basic.BuildConfig;
|
||||||
|
import org.deadc0de.apple2ix.basic.R;
|
||||||
|
|
||||||
public class Apple2Activity extends Activity implements Apple2DiskChooserActivity.Callback {
|
public class Apple2Activity extends Activity implements Apple2DiskChooserActivity.Callback {
|
||||||
|
|
||||||
@ -190,7 +192,20 @@ public class Apple2Activity extends Activity implements Apple2DiskChooserActivit
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDisksChosen(DiskArgs args) {
|
public void onDisksChosen(DiskArgs args) {
|
||||||
sDisksChosen = args;
|
if (Apple2DisksMenu.hasDiskExtension(args.name)) {
|
||||||
|
sDisksChosen = args;
|
||||||
|
} else {
|
||||||
|
if (args.name.equals("")) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Apple2DisksMenu.hasStateExtension(args.name)) {
|
||||||
|
////mMainMenu.restoreEmulatorState(args); FIXME TODO ...
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Toast.makeText(this, R.string.disk_insert_toast_cannot, Toast.LENGTH_SHORT).show();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -205,7 +220,8 @@ public class Apple2Activity extends Activity implements Apple2DiskChooserActivit
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (grantedPermissions) {
|
if (grantedPermissions) {
|
||||||
// this will force copying APK files (now that we have permission
|
// perform migration(s) and assets exposure now
|
||||||
|
Apple2Utils.migrateToExternalStorage(Apple2Activity.this);
|
||||||
Apple2Utils.exposeAPKAssetsToExternal(Apple2Activity.this);
|
Apple2Utils.exposeAPKAssetsToExternal(Apple2Activity.this);
|
||||||
} // else ... we keep nagging on app startup ...
|
} // else ... we keep nagging on app startup ...
|
||||||
} else {
|
} else {
|
||||||
|
@ -263,7 +263,11 @@ public class Apple2DisksMenu implements Apple2MenuView {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void dismiss() {
|
public void dismiss() {
|
||||||
String path = popPathStack();
|
String path = null;
|
||||||
|
if (!(boolean) Apple2Preferences.getJSONPref(SETTINGS.USE_NEWSCHOOL_DISK_SELECTION)) {
|
||||||
|
path = popPathStack();
|
||||||
|
}
|
||||||
|
|
||||||
if (path == null) {
|
if (path == null) {
|
||||||
mActivity.popApple2View(this);
|
mActivity.popApple2View(this);
|
||||||
} else {
|
} else {
|
||||||
@ -498,6 +502,20 @@ public class Apple2DisksMenu implements Apple2MenuView {
|
|||||||
return (suffix.equalsIgnoreCase(".dsk.gz") || suffix.equalsIgnoreCase(".nib.gz"));
|
return (suffix.equalsIgnoreCase(".dsk.gz") || suffix.equalsIgnoreCase(".nib.gz"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static boolean hasStateExtension(String name) {
|
||||||
|
|
||||||
|
// check file extensions ... sigh ... no String.endsWithIgnoreCase() ?
|
||||||
|
|
||||||
|
final int extLen = Apple2MainMenu.SAVE_FILE_EXTENSION.length();
|
||||||
|
final int len = name.length();
|
||||||
|
if (len <= extLen) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
final String suffix = name.substring(len - extLen, len);
|
||||||
|
return suffix.equalsIgnoreCase(Apple2MainMenu.SAVE_FILE_EXTENSION);
|
||||||
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
// internals ...
|
// internals ...
|
||||||
|
|
||||||
|
@ -40,7 +40,9 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
|||||||
|
|
||||||
public class Apple2MainMenu {
|
public class Apple2MainMenu {
|
||||||
|
|
||||||
public final static String SAVE_FILE = "emulator.state";
|
public final static String OLD_SAVE_FILE = "emulator.state";
|
||||||
|
public final static String SAVE_FILE_EXTENSION = ".a2state";
|
||||||
|
public final static String SAVE_FILE = "emulator" + SAVE_FILE_EXTENSION;
|
||||||
private final static String TAG = "Apple2MainMenu";
|
private final static String TAG = "Apple2MainMenu";
|
||||||
|
|
||||||
private Apple2Activity mActivity = null;
|
private Apple2Activity mActivity = null;
|
||||||
@ -296,8 +298,86 @@ public class Apple2MainMenu {
|
|||||||
mActivity.registerAndShowDialog(rebootQuitDialog);
|
mActivity.registerAndShowDialog(rebootQuitDialog);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void restoreEmulatorState(String quickSavePath) {
|
||||||
|
|
||||||
public void maybeSaveRestore() {
|
Apple2DisksMenu.ejectDisk(/*isDriveA:*/true);
|
||||||
|
Apple2DisksMenu.ejectDisk(/*isDriveA:*/false);
|
||||||
|
|
||||||
|
// First we extract and open the emulator.a2state disk paths (which could be in a restricted location)
|
||||||
|
String jsonString = mActivity.stateExtractDiskPaths(quickSavePath);
|
||||||
|
try {
|
||||||
|
|
||||||
|
JSONObject map = new JSONObject(jsonString);
|
||||||
|
map.put("stateFile", quickSavePath);
|
||||||
|
|
||||||
|
final String[] diskPathKeys = new String[]{"diskA", "diskB"};
|
||||||
|
final String[] readOnlyKeys = new String[]{"readOnlyA", "readOnlyB"};
|
||||||
|
final String[] fdKeys = new String[]{"fdA", "fdB"};
|
||||||
|
|
||||||
|
ParcelFileDescriptor[] pfds = {null, null};
|
||||||
|
|
||||||
|
for (int i = 0; i < 2; i++) {
|
||||||
|
|
||||||
|
String diskPath = map.getString(diskPathKeys[i]);
|
||||||
|
boolean readOnly = map.getBoolean(readOnlyKeys[i]);
|
||||||
|
|
||||||
|
Apple2Preferences.setJSONPref(i == 0 ? Apple2DisksMenu.SETTINGS.CURRENT_DISK_PATH_A : Apple2DisksMenu.SETTINGS.CURRENT_DISK_PATH_B, diskPath);
|
||||||
|
Apple2Preferences.setJSONPref(i == 0 ? Apple2DisksMenu.SETTINGS.CURRENT_DISK_PATH_A_RO : Apple2DisksMenu.SETTINGS.CURRENT_DISK_PATH_B_RO, readOnly);
|
||||||
|
|
||||||
|
if (diskPath.equals("")) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (diskPath.startsWith(Apple2DisksMenu.EXTERNAL_CHOOSER_SENTINEL)) {
|
||||||
|
String uriString = diskPath.substring(Apple2DisksMenu.EXTERNAL_CHOOSER_SENTINEL.length());
|
||||||
|
|
||||||
|
Uri uri = Uri.parse(uriString);
|
||||||
|
|
||||||
|
pfds[i] = Apple2DiskChooserActivity.openFileDescriptorFromUri(mActivity, uri);
|
||||||
|
if (pfds[i] == null) {
|
||||||
|
Log.e(TAG, "Did not find URI for drive #" + i + " specified in " + SAVE_FILE + " file : " + diskPath);
|
||||||
|
} else {
|
||||||
|
int fd = pfds[i].getFd();
|
||||||
|
map.put(fdKeys[i], fd);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
boolean exists = new File(diskPath).exists();
|
||||||
|
if (!exists) {
|
||||||
|
Log.e(TAG, "Did not find path for drive #" + i + " specified in " + SAVE_FILE + " file : " + diskPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
jsonString = mActivity.loadState(map.toString());
|
||||||
|
|
||||||
|
for (int i = 0; i < 2; i++) {
|
||||||
|
try {
|
||||||
|
if (pfds[i] != null) {
|
||||||
|
pfds[i].close();
|
||||||
|
}
|
||||||
|
} catch (IOException ioe) {
|
||||||
|
Log.e(TAG, "Error attempting to close PFD #" + i + " : " + ioe);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
map = new JSONObject(jsonString);
|
||||||
|
|
||||||
|
{
|
||||||
|
boolean wasGzippedA = map.getBoolean("wasGzippedA");
|
||||||
|
Apple2Preferences.setJSONPref(Apple2DisksMenu.SETTINGS.CURRENT_DISK_PATH_A_GZ, wasGzippedA);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
boolean wasGzippedB = map.getBoolean("wasGzippedB");
|
||||||
|
Apple2Preferences.setJSONPref(Apple2DisksMenu.SETTINGS.CURRENT_DISK_PATH_B_GZ, wasGzippedB);
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME TODO : what to do if state load failed?
|
||||||
|
|
||||||
|
} catch (Throwable t) {
|
||||||
|
Log.v(TAG, "OOPS : " + t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void maybeSaveRestore() {
|
||||||
mActivity.pauseEmulation();
|
mActivity.pauseEmulation();
|
||||||
|
|
||||||
final String quickSavePath;
|
final String quickSavePath;
|
||||||
@ -324,86 +404,13 @@ public class Apple2MainMenu {
|
|||||||
}).setNeutralButton(R.string.restore, new DialogInterface.OnClickListener() {
|
}).setNeutralButton(R.string.restore, new DialogInterface.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(DialogInterface dialog, int which) {
|
public void onClick(DialogInterface dialog, int which) {
|
||||||
|
|
||||||
if (!selectionAlreadyHandled.compareAndSet(false, true)) {
|
if (!selectionAlreadyHandled.compareAndSet(false, true)) {
|
||||||
Log.v(TAG, "OMG, avoiding nasty UI race in sync/restore onClick()");
|
Log.v(TAG, "OMG, avoiding nasty UI race in sync/restore onClick()");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Apple2DisksMenu.ejectDisk(/*isDriveA:*/true);
|
restoreEmulatorState(quickSavePath);
|
||||||
Apple2DisksMenu.ejectDisk(/*isDriveA:*/false);
|
|
||||||
|
|
||||||
// First we extract and open the emulator.state disk paths (which could be in a restricted location)
|
|
||||||
String jsonString = mActivity.stateExtractDiskPaths(quickSavePath);
|
|
||||||
try {
|
|
||||||
|
|
||||||
JSONObject map = new JSONObject(jsonString);
|
|
||||||
map.put("stateFile", quickSavePath);
|
|
||||||
|
|
||||||
final String[] diskPathKeys = new String[]{"diskA", "diskB"};
|
|
||||||
final String[] readOnlyKeys = new String[]{"readOnlyA", "readOnlyB"};
|
|
||||||
final String[] fdKeys = new String[]{"fdA", "fdB"};
|
|
||||||
|
|
||||||
ParcelFileDescriptor[] pfds = {null, null};
|
|
||||||
|
|
||||||
for (int i = 0; i < 2; i++) {
|
|
||||||
|
|
||||||
String diskPath = map.getString(diskPathKeys[i]);
|
|
||||||
boolean readOnly = map.getBoolean(readOnlyKeys[i]);
|
|
||||||
|
|
||||||
Apple2Preferences.setJSONPref(i == 0 ? Apple2DisksMenu.SETTINGS.CURRENT_DISK_PATH_A : Apple2DisksMenu.SETTINGS.CURRENT_DISK_PATH_B, diskPath);
|
|
||||||
Apple2Preferences.setJSONPref(i == 0 ? Apple2DisksMenu.SETTINGS.CURRENT_DISK_PATH_A_RO : Apple2DisksMenu.SETTINGS.CURRENT_DISK_PATH_B_RO, readOnly);
|
|
||||||
|
|
||||||
if (diskPath.equals("")) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (diskPath.startsWith(Apple2DisksMenu.EXTERNAL_CHOOSER_SENTINEL)) {
|
|
||||||
String uriString = diskPath.substring(Apple2DisksMenu.EXTERNAL_CHOOSER_SENTINEL.length());
|
|
||||||
|
|
||||||
Uri uri = Uri.parse(uriString);
|
|
||||||
|
|
||||||
pfds[i] = Apple2DiskChooserActivity.openFileDescriptorFromUri(mActivity, uri);
|
|
||||||
if (pfds[i] == null) {
|
|
||||||
Log.e(TAG, "Did not find URI for drive #" + i + " specified in emulator.state file : " + diskPath);
|
|
||||||
} else {
|
|
||||||
int fd = pfds[i].getFd();
|
|
||||||
map.put(fdKeys[i], fd);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
boolean exists = new File(diskPath).exists();
|
|
||||||
if (!exists) {
|
|
||||||
Log.e(TAG, "Did not find path for drive #" + i + " specified in emulator.state file : " + diskPath);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
jsonString = mActivity.loadState(map.toString());
|
|
||||||
|
|
||||||
for (int i = 0; i < 2; i++) {
|
|
||||||
try {
|
|
||||||
if (pfds[i] != null) {
|
|
||||||
pfds[i].close();
|
|
||||||
}
|
|
||||||
} catch (IOException ioe) {
|
|
||||||
Log.e(TAG, "Error attempting to close PFD #" + i + " : " + ioe);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
map = new JSONObject(jsonString);
|
|
||||||
|
|
||||||
{
|
|
||||||
boolean wasGzippedA = map.getBoolean("wasGzippedA");
|
|
||||||
Apple2Preferences.setJSONPref(Apple2DisksMenu.SETTINGS.CURRENT_DISK_PATH_A_GZ, wasGzippedA);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
boolean wasGzippedB = map.getBoolean("wasGzippedB");
|
|
||||||
Apple2Preferences.setJSONPref(Apple2DisksMenu.SETTINGS.CURRENT_DISK_PATH_B_GZ, wasGzippedB);
|
|
||||||
}
|
|
||||||
|
|
||||||
// FIXME TODO : what to do if state load failed?
|
|
||||||
|
|
||||||
} catch (Throwable t) {
|
|
||||||
Log.v(TAG, "OOPS : " + t);
|
|
||||||
}
|
|
||||||
Apple2MainMenu.this.dismiss();
|
Apple2MainMenu.this.dismiss();
|
||||||
}
|
}
|
||||||
}).setNegativeButton(R.string.cancel, null).create();
|
}).setNegativeButton(R.string.cancel, null).create();
|
||||||
|
@ -175,7 +175,7 @@ public class Apple2Preferences {
|
|||||||
Log.v(TAG, "Triggering migration to Apple2ix version : " + BuildConfig.VERSION_NAME);
|
Log.v(TAG, "Triggering migration to Apple2ix version : " + BuildConfig.VERSION_NAME);
|
||||||
setJSONPref(PREF_DOMAIN_INTERFACE, PREF_EMULATOR_VERSION, BuildConfig.VERSION_CODE);
|
setJSONPref(PREF_DOMAIN_INTERFACE, PREF_EMULATOR_VERSION, BuildConfig.VERSION_CODE);
|
||||||
|
|
||||||
Apple2Utils.migrate(activity);
|
Apple2Utils.migrateToExternalStorage(activity);
|
||||||
if (BuildConfig.VERSION_CODE >= 17) {
|
if (BuildConfig.VERSION_CODE >= 17) {
|
||||||
// FIXME TODO : remove this after most/all app users are on 18+
|
// FIXME TODO : remove this after most/all app users are on 18+
|
||||||
|
|
||||||
|
@ -29,6 +29,7 @@ import java.io.FileInputStream;
|
|||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
import java.io.FileReader;
|
import java.io.FileReader;
|
||||||
import java.io.FileWriter;
|
import java.io.FileWriter;
|
||||||
|
import java.io.FilenameFilter;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.InterruptedIOException;
|
import java.io.InterruptedIOException;
|
||||||
@ -102,49 +103,59 @@ public class Apple2Utils {
|
|||||||
return attempts < maxAttempts;
|
return attempts < maxAttempts;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void migrate(Apple2Activity activity) {
|
public static void migrateToExternalStorage(Apple2Activity activity) {
|
||||||
|
|
||||||
do {
|
do {
|
||||||
if (BuildConfig.VERSION_CODE >= 18) {
|
if (BuildConfig.VERSION_CODE >= 18) {
|
||||||
|
|
||||||
// Migrate emulator.state file from internal path to external storage to allow user manipulation
|
// Rename old emulator state file
|
||||||
// TODO FIXME : Remove this migration code when all/most users are on version >= 18
|
// TODO FIXME : Remove this migration code when all/most users are on version >= 18
|
||||||
|
|
||||||
final File extStorage = Apple2Utils.getExternalStorageDirectory(activity);
|
final File srcFile = new File(getDataDir(activity) + File.separator + Apple2MainMenu.OLD_SAVE_FILE);
|
||||||
if (extStorage == null) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
final String srcPath = getDataDir(activity) + File.separator + Apple2MainMenu.SAVE_FILE;
|
|
||||||
final File srcFile = new File(srcPath);
|
|
||||||
if (!srcFile.exists()) {
|
if (!srcFile.exists()) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
final String dstPath = extStorage + File.separator + Apple2MainMenu.SAVE_FILE;
|
final File dstFile = new File(getDataDir(activity) + File.separator + Apple2MainMenu.SAVE_FILE);
|
||||||
|
final boolean success = copyFile(srcFile, dstFile);
|
||||||
|
if (success) {
|
||||||
|
srcFile.delete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} while (false);
|
||||||
|
|
||||||
final int maxAttempts = 5;
|
|
||||||
int attempts = 0;
|
|
||||||
do {
|
|
||||||
try {
|
|
||||||
FileInputStream is = new FileInputStream(srcFile);
|
|
||||||
FileOutputStream os = new FileOutputStream(dstPath);
|
|
||||||
copyFile(is, os);
|
|
||||||
break;
|
|
||||||
} catch (InterruptedIOException e) {
|
|
||||||
// EINTR, EAGAIN ...
|
|
||||||
} catch (IOException e) {
|
|
||||||
Log.d(TAG, "OOPS exception attempting to copy emulator.state file : " + e);
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
final File extStorage = Apple2Utils.getExternalStorageDirectory(activity);
|
||||||
Thread.sleep(100, 0);
|
if (extStorage == null) {
|
||||||
} catch (InterruptedException ie) {
|
return;
|
||||||
// ...
|
}
|
||||||
}
|
|
||||||
++attempts;
|
|
||||||
} while (attempts < maxAttempts);
|
|
||||||
|
|
||||||
srcFile.delete();
|
do {
|
||||||
|
if (BuildConfig.VERSION_CODE >= 18) {
|
||||||
|
|
||||||
|
// Migrate old emulator state file from internal path to external storage to allow user manipulation
|
||||||
|
// TODO FIXME : Remove this migration code when all/most users are on version >= 18
|
||||||
|
|
||||||
|
final File srcFile = new File(getDataDir(activity) + File.separator + Apple2MainMenu.SAVE_FILE);
|
||||||
|
if (!srcFile.exists()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
final File dstFile = new File(extStorage + File.separator + Apple2MainMenu.SAVE_FILE);
|
||||||
|
final boolean success = copyFile(srcFile, dstFile);
|
||||||
|
if (success) {
|
||||||
|
srcFile.delete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} while (false);
|
||||||
|
|
||||||
|
do {
|
||||||
|
if (BuildConfig.VERSION_CODE >= 20) {
|
||||||
|
|
||||||
|
// Recursively rename all *.state files found in /sdcard/apple2ix
|
||||||
|
// TODO FIXME : Remove this migration code when all/most users are on version >= 20
|
||||||
|
|
||||||
|
recursivelyRenameEmulatorStateFiles(extStorage);
|
||||||
}
|
}
|
||||||
} while (false);
|
} while (false);
|
||||||
}
|
}
|
||||||
@ -402,6 +413,85 @@ public class Apple2Utils {
|
|||||||
} while (attempts < maxAttempts);
|
} while (attempts < maxAttempts);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void recursivelyRenameEmulatorStateFiles(File directory) {
|
||||||
|
try {
|
||||||
|
if (!directory.isDirectory()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final int oldSuffixLen = 6;
|
||||||
|
|
||||||
|
File[] files = directory.listFiles(new FilenameFilter() {
|
||||||
|
@Override
|
||||||
|
public boolean accept(File dir, String name) {
|
||||||
|
|
||||||
|
if (name.equals(".") || name.equals("..")) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
final File file = new File(dir, name);
|
||||||
|
if (file.isDirectory()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
final int len = name.length();
|
||||||
|
if (len < oldSuffixLen) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
final String suffix = name.substring(len - oldSuffixLen, len);
|
||||||
|
return suffix.equalsIgnoreCase(".state");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (files == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (File file : files) {
|
||||||
|
if (file.isDirectory()) {
|
||||||
|
recursivelyRenameEmulatorStateFiles(file);
|
||||||
|
} else {
|
||||||
|
final File srcFile = file;
|
||||||
|
final String oldName = file.getName();
|
||||||
|
final String newName = oldName.substring(0, oldName.length() - oldSuffixLen) + Apple2MainMenu.SAVE_FILE_EXTENSION;
|
||||||
|
boolean success = file.renameTo(new File(file.getParentFile(), newName));
|
||||||
|
if (success) {
|
||||||
|
srcFile.delete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.e(TAG, "OOPS : {e}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean copyFile(final File srcFile, final File dstFile) {
|
||||||
|
final int maxAttempts = 5;
|
||||||
|
int attempts = 0;
|
||||||
|
do {
|
||||||
|
try {
|
||||||
|
FileInputStream is = new FileInputStream(srcFile);
|
||||||
|
FileOutputStream os = new FileOutputStream(dstFile);
|
||||||
|
copyFile(is, os);
|
||||||
|
break;
|
||||||
|
} catch (InterruptedIOException e) {
|
||||||
|
// EINTR, EAGAIN ...
|
||||||
|
} catch (IOException e) {
|
||||||
|
Log.d(TAG, "OOPS exception attempting to copy emulator state file : " + e);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
Thread.sleep(100, 0);
|
||||||
|
} catch (InterruptedException ie) {
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
++attempts;
|
||||||
|
} while (attempts < maxAttempts);
|
||||||
|
|
||||||
|
return attempts < maxAttempts;
|
||||||
|
}
|
||||||
|
|
||||||
private static void copyFile(InputStream is, OutputStream os) throws IOException {
|
private static void copyFile(InputStream is, OutputStream os) throws IOException {
|
||||||
final int BUF_SZ = 4096;
|
final int BUF_SZ = 4096;
|
||||||
byte[] buf = new byte[BUF_SZ];
|
byte[] buf = new byte[BUF_SZ];
|
||||||
|
@ -32,8 +32,6 @@
|
|||||||
<string name="diskA">Laufwerk 1</string>
|
<string name="diskA">Laufwerk 1</string>
|
||||||
<string name="diskB">Laufwerk 2</string>
|
<string name="diskB">Laufwerk 2</string>
|
||||||
<string name="disk_eject">Auswerfen</string>
|
<string name="disk_eject">Auswerfen</string>
|
||||||
<string name="disk_insert_toast">Die eingelegte Diskette ist schreibgeschützt</string>
|
|
||||||
<string name="disk_insert_could_not_read">Entschuldigung, das Diskettenabbild konnte nicht gelesen werden!</string>
|
|
||||||
<string name="disk_read_only">Schreibgeschützt</string>
|
<string name="disk_read_only">Schreibgeschützt</string>
|
||||||
<string name="disk_read_write">Lesen/Schreiben</string>
|
<string name="disk_read_write">Lesen/Schreiben</string>
|
||||||
<string name="disk_show_operation">Zeige Disk ][ Aktivität</string>
|
<string name="disk_show_operation">Zeige Disk ][ Aktivität</string>
|
||||||
|
@ -32,8 +32,6 @@
|
|||||||
<string name="diskA">Disquetera 1</string>
|
<string name="diskA">Disquetera 1</string>
|
||||||
<string name="diskB">Disquetera 2</string>
|
<string name="diskB">Disquetera 2</string>
|
||||||
<string name="disk_eject">Eyectar</string>
|
<string name="disk_eject">Eyectar</string>
|
||||||
<string name="disk_insert_toast">Disco insertado en la disquetera de sólo lectura</string>
|
|
||||||
<string name="disk_insert_could_not_read">Lo sentimos, no se puede leer la imagen de disquete!</string>
|
|
||||||
<string name="disk_read_only">Sólo leer</string>
|
<string name="disk_read_only">Sólo leer</string>
|
||||||
<string name="disk_read_write">Leer y escribir</string>
|
<string name="disk_read_write">Leer y escribir</string>
|
||||||
<string name="disk_show_operation">Mostrar las operaciones de "Disk ]["</string>
|
<string name="disk_show_operation">Mostrar las operaciones de "Disk ]["</string>
|
||||||
|
@ -32,8 +32,6 @@
|
|||||||
<string name="diskA">Lecteur 1</string>
|
<string name="diskA">Lecteur 1</string>
|
||||||
<string name="diskB">Lecteur 2</string>
|
<string name="diskB">Lecteur 2</string>
|
||||||
<string name="disk_eject">Ejecter</string>
|
<string name="disk_eject">Ejecter</string>
|
||||||
<string name="disk_insert_toast">Insérer la disquette dans le drive en lecture seulement</string>
|
|
||||||
<string name="disk_insert_could_not_read">Désolé, impossible de lire l\'image disque!</string>
|
|
||||||
<string name="disk_read_only">Lecture seulement</string>
|
<string name="disk_read_only">Lecture seulement</string>
|
||||||
<string name="disk_read_write">Lecture/Ecriture</string>
|
<string name="disk_read_write">Lecture/Ecriture</string>
|
||||||
<string name="disk_show_operation">Afficher les opérations (disque) ][</string>
|
<string name="disk_show_operation">Afficher les opérations (disque) ][</string>
|
||||||
|
@ -36,8 +36,7 @@
|
|||||||
<string name="diskA">Drive 1</string>
|
<string name="diskA">Drive 1</string>
|
||||||
<string name="diskB">Drive 2</string>
|
<string name="diskB">Drive 2</string>
|
||||||
<string name="disk_eject">Eject</string>
|
<string name="disk_eject">Eject</string>
|
||||||
<string name="disk_insert_toast">Inserted disk in drive read-only</string>
|
<string name="disk_insert_toast_cannot">Cannot insert (not a disk image or state file)</string>
|
||||||
<string name="disk_insert_could_not_read">Sorry, could not read the disk image!</string>
|
|
||||||
<string name="disk_read_only">Read only</string>
|
<string name="disk_read_only">Read only</string>
|
||||||
<string name="disk_read_write">Read/write</string>
|
<string name="disk_read_write">Read/write</string>
|
||||||
<string name="disk_selection_newschoool">Use system file chooser</string>
|
<string name="disk_selection_newschoool">Use system file chooser</string>
|
||||||
@ -130,8 +129,8 @@
|
|||||||
<string name="keypad_preset_left_right_space">←,→, tap spacebar</string>
|
<string name="keypad_preset_left_right_space">←,→, tap spacebar</string>
|
||||||
<string name="keypad_preset_wadx_space">W,A,D,X, tap spacebar</string>
|
<string name="keypad_preset_wadx_space">W,A,D,X, tap spacebar</string>
|
||||||
<string name="keypad_repeat_summary">Key repeat threshold in secs</string>
|
<string name="keypad_repeat_summary">Key repeat threshold in secs</string>
|
||||||
<string name="menu_disks">Load disk image…</string>
|
<string name="menu_disks">Load image or state file…</string>
|
||||||
<string name="menu_disks_summary">Insert a Disk ][ image file</string>
|
<string name="menu_disks_summary">Insert Disk ][ image or state file</string>
|
||||||
<string name="menu_settings">Emulator settings…</string>
|
<string name="menu_settings">Emulator settings…</string>
|
||||||
<string name="menu_settings_summary">General settings, joystick, keyboard</string>
|
<string name="menu_settings_summary">General settings, joystick, keyboard</string>
|
||||||
<string name="mockingboard_disabled_title">Mockingboard disabled</string>
|
<string name="mockingboard_disabled_title">Mockingboard disabled</string>
|
||||||
@ -165,7 +164,7 @@
|
|||||||
<string name="save">Quick save</string>
|
<string name="save">Quick save</string>
|
||||||
<string name="saverestore">Save & restore…</string>
|
<string name="saverestore">Save & restore…</string>
|
||||||
<string name="saverestore_choice">Save current state or restore previous?</string>
|
<string name="saverestore_choice">Save current state or restore previous?</string>
|
||||||
<string name="saverestore_summary">Quick save and restore</string>
|
<string name="saverestore_summary">Save and restore emulator state</string>
|
||||||
<string name="skip">Skip→</string>
|
<string name="skip">Skip→</string>
|
||||||
<string name="speaker_volume">Speaker volume</string>
|
<string name="speaker_volume">Speaker volume</string>
|
||||||
<string name="speaker_volume_summary">Set the speaker volume</string>
|
<string name="speaker_volume_summary">Set the speaker volume</string>
|
||||||
|
@ -136,7 +136,7 @@ TEST test_save_state_1() {
|
|||||||
_assert_blank_boot();
|
_assert_blank_boot();
|
||||||
|
|
||||||
char *savData = NULL;
|
char *savData = NULL;
|
||||||
ASPRINTF(&savData, "%s/emulator-test.state", HOMEDIR);
|
ASPRINTF(&savData, "%s/emulator-test.a2state", HOMEDIR);
|
||||||
|
|
||||||
bool ret = emulator_saveState(savData);
|
bool ret = emulator_saveState(savData);
|
||||||
ASSERT(ret);
|
ASSERT(ret);
|
||||||
@ -155,7 +155,7 @@ TEST test_load_state_1() {
|
|||||||
c_debugger_set_timeout(0);
|
c_debugger_set_timeout(0);
|
||||||
|
|
||||||
char *savData = NULL;
|
char *savData = NULL;
|
||||||
ASPRINTF(&savData, "%s/emulator-test.state", HOMEDIR);
|
ASPRINTF(&savData, "%s/emulator-test.a2state", HOMEDIR);
|
||||||
|
|
||||||
bool ret = false;
|
bool ret = false;
|
||||||
int fdA = -1;
|
int fdA = -1;
|
||||||
|
Loading…
Reference in New Issue
Block a user