Various improvements to disk management

- Moves disk management form Apple2Activity to Apple2DisksMenu
    - Handle reading/writing disk images in /sdcard/...
    - Manage hirerarchical navigation
This commit is contained in:
Aaron Culliney 2015-08-07 23:00:08 -07:00
parent 2008c341d5
commit 2673777be7
12 changed files with 496 additions and 157 deletions

View File

@ -51,6 +51,10 @@ public abstract class Apple2AbstractMenu implements Apple2MenuView {
mActivity.popApple2View(this);
}
public void dismissAll() {
this.dismiss();
}
public boolean isShowing() {
return mSettingsView.isShown();
}

View File

@ -14,8 +14,6 @@ package org.deadc0de.apple2ix;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.graphics.Rect;
import android.media.AudioManager;
import android.os.Build;
@ -29,19 +27,13 @@ import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.widget.FrameLayout;
import java.io.File;
import java.io.InputStream;
import java.io.IOException;
import java.io.FileOutputStream;
import java.util.ArrayList;
public class Apple2Activity extends Activity {
private final static String TAG = "Apple2Activity";
private final static int BUF_SZ = 4096;
private final static int MAX_FINGERS = 32;// HACK ...
private String mDataDir = null;
private boolean mSetUncaughtExceptionHandler = false;
private Apple2View mView = null;
@ -104,70 +96,6 @@ public class Apple2Activity extends Activity {
public native void nativeChooseDisk(String path, boolean driveA, boolean readOnly);
// HACK NOTE 2015/02/22 : Apparently native code cannot easily access stuff in the APK ... so copy various resources
// out of the APK and into the /data/data/... for ease of access. Because this is FOSS software we don't care about
// security or DRM for these assets =)
private String _firstTimeInitialization() {
String dataDir = null;
try {
PackageManager pm = getPackageManager();
PackageInfo pi = pm.getPackageInfo(getPackageName(), 0);
dataDir = pi.applicationInfo.dataDir;
} catch (PackageManager.NameNotFoundException e) {
Log.e(TAG, "" + e);
System.exit(1);
}
if (Apple2Preferences.PREFS_CONFIGURED.booleanValue(this)) {
return dataDir;
}
Log.d(TAG, "First time copying stuff-n-things out of APK for ease-of-NDK access...");
try {
String[] shaders = getAssets().list("shaders");
for (String shader : shaders) {
_copyFile(dataDir, "shaders", shader);
}
String[] disks = getAssets().list("disks");
for (String disk : disks) {
_copyFile(dataDir, "disks", disk);
}
} catch (IOException e) {
Log.e(TAG, "problem copying resources : " + e);
System.exit(1);
}
Log.d(TAG, "Saving default preferences");
Apple2Preferences.PREFS_CONFIGURED.saveBoolean(this, true);
return dataDir;
}
private void _copyFile(String dataDir, String subdir, String assetName)
throws IOException {
String outputPath = dataDir + File.separator + subdir;
Log.d(TAG, "Copying " + subdir + File.separator + assetName + " to " + outputPath + File.separator + assetName + " ...");
new File(outputPath).mkdirs();
InputStream is = getAssets().open(subdir + File.separator + assetName);
File file = new File(outputPath + File.separator + assetName);
file.setWritable(true);
FileOutputStream os = new FileOutputStream(file);
byte[] buf = new byte[BUF_SZ];
while (true) {
int len = is.read(buf, 0, BUF_SZ);
if (len < 0) {
break;
}
os.write(buf, 0, len);
}
os.flush();
os.close();
}
private void _setCustomExceptionHandler() {
if (mSetUncaughtExceptionHandler) {
return;
@ -246,7 +174,7 @@ public class Apple2Activity extends Activity {
Log.e(TAG, "onCreate()");
_setCustomExceptionHandler();
mDataDir = _firstTimeInitialization();
String dataDir = Apple2DisksMenu.firstTimeAssetsInitialization(this);
// get device audio parameters for native OpenSLES
mSampleRate = DevicePropertyCalculator.getRecommendedSampleRate(this);
@ -254,7 +182,7 @@ public class Apple2Activity extends Activity {
mStereoBufferSize = DevicePropertyCalculator.getRecommendedBufferSize(this, /*isStereo:*/true);
Log.d(TAG, "Device sampleRate:" + mSampleRate + " mono bufferSize:" + mMonoBufferSize + " stereo bufferSize:" + mStereoBufferSize);
nativeOnCreate(mDataDir, mSampleRate, mMonoBufferSize, mStereoBufferSize);
nativeOnCreate(dataDir, mSampleRate, mMonoBufferSize, mStereoBufferSize);
// NOTE: load preferences after nativeOnCreate ... native CPU thread should still be paused
Apple2Preferences.loadPreferences(this);
@ -529,6 +457,19 @@ public class Apple2Activity extends Activity {
return mMenuStack.get(lastIndex);
}
public synchronized Apple2MenuView peekApple2View(int index) {
int lastIndex = mMenuStack.size() - 1;
if (lastIndex < 0) {
return null;
}
try {
return mMenuStack.get(index);
} catch (IndexOutOfBoundsException e) {
return null;
}
}
public void dismissAllMenus() {
if (mMainMenu != null) {
mMainMenu.dismiss();

View File

@ -11,73 +11,299 @@
package org.deadc0de.apple2ix;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.graphics.drawable.Drawable;
import android.os.Environment;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.CheckBox;
import android.widget.Button;
import android.widget.CompoundButton;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.RadioButton;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
public class Apple2DisksMenu implements Apple2MenuView {
private final static String TAG = "Apple2DisksMenu";
private static String sDataDir = null;
private Apple2Activity mActivity = null;
private View mDisksView = null;
private final ArrayList<String> mPathStack = new ArrayList<>();
private static File sExternalFilesDir = null;
private static boolean sExternalStorageAvailable = false;
private static boolean sInitializedPath = false;
public Apple2DisksMenu(Apple2Activity activity) {
mActivity = activity;
setup();
}
private void setup() {
if (!sInitializedPath) {
sInitializedPath = true;
Apple2Preferences.CURRENT_DISK_PATH.load(mActivity);
}
LayoutInflater inflater = (LayoutInflater) mActivity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
mDisksView = inflater.inflate(R.layout.activity_disks, null, false);
RadioButton diskA = (RadioButton) mDisksView.findViewById(R.id.radioButton_diskA);
diskA.setChecked(true);
final Button cancelButton = (Button) mDisksView.findViewById(R.id.cancelButton);
cancelButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Apple2DisksMenu.this.mActivity.dismissAllMenus();
}
});
CheckBox readWrite = (CheckBox) mDisksView.findViewById(R.id.checkBox_readWrite);
readWrite.setChecked(false);
if (!sExternalStorageAvailable) {
String storageState = Environment.getExternalStorageState();
File externalDir = new File(Environment.getExternalStorageDirectory().getPath() + File.separator + "apple2ix"); // /sdcard/apple2ix
sExternalFilesDir = null;
sExternalStorageAvailable = storageState.equals(Environment.MEDIA_MOUNTED);
if (sExternalStorageAvailable) {
sExternalFilesDir = externalDir;
boolean made = sExternalFilesDir.mkdirs();
if (!made) {
Log.d(TAG, "WARNING: could not make directory : " + sExternalFilesDir);
}
} else {
sExternalStorageAvailable = storageState.equals(Environment.MEDIA_MOUNTED_READ_ONLY) && externalDir.exists();
sExternalFilesDir = externalDir;
}
}
}
// HACK NOTE 2015/02/22 : Apparently native code cannot easily access stuff in the APK ... so copy various resources
// out of the APK and into the /data/data/... for ease of access. Because this is FOSS software we don't care about
// security or DRM for these assets =)
public static String firstTimeAssetsInitialization(Apple2Activity activity) {
try {
PackageManager pm = activity.getPackageManager();
PackageInfo pi = pm.getPackageInfo(activity.getPackageName(), 0);
sDataDir = pi.applicationInfo.dataDir;
} catch (PackageManager.NameNotFoundException e) {
Log.e(TAG, "" + e);
System.exit(1);
}
if (Apple2Preferences.ASSETS_CONFIGURED.booleanValue(activity)) {
return sDataDir;
}
Log.d(TAG, "First time copying stuff-n-things out of APK for ease-of-NDK access...");
try {
String[] shaders = activity.getAssets().list("shaders");
for (String shader : shaders) {
Apple2DisksMenu.copyFile(activity, "shaders", shader);
}
String[] disks = activity.getAssets().list("disks");
for (String disk : disks) {
Apple2DisksMenu.copyFile(activity, "disks", disk);
}
} catch (IOException e) {
Log.e(TAG, "problem copying resources : " + e);
System.exit(1);
}
Log.d(TAG, "Saving default preferences");
Apple2Preferences.ASSETS_CONFIGURED.saveBoolean(activity, true);
return sDataDir;
}
// ------------------------------------------------------------------------
// Apple2MenuView interface methods
public final boolean isCalibrating() {
return false;
}
public void show() {
if (isShowing()) {
return;
}
dynamicSetup();
mActivity.pushApple2View(this);
}
public void dismiss() {
String path = popPathStack();
if (path == null) {
mActivity.popApple2View(this);
} else {
dynamicSetup();
ListView disksList = (ListView) mDisksView.findViewById(R.id.listView_settings);
disksList.postInvalidate();
}
}
public void dismissAll() {
mActivity.popApple2View(this);
}
public boolean isShowing() {
return mDisksView.isShown();
}
public View getView() {
return mDisksView;
}
// ------------------------------------------------------------------------
// path stack methods
public String getPathStackJSON() {
JSONArray jsonArray = new JSONArray(Arrays.asList(mPathStack.toArray()));
return jsonArray.toString();
}
public void setPathStackJSON(String pathStackJSON) {
mPathStack.clear();
try {
JSONArray jsonArray = new JSONArray(pathStackJSON);
for (int i = 0, count = jsonArray.length(); i < count; i++) {
JSONObject jsonObject = jsonArray.getJSONObject(i);
mPathStack.add(jsonObject.toString());
}
} catch (JSONException e) {
e.printStackTrace();
}
}
public void pushPathStack(String path) {
mPathStack.add(path);
Apple2Preferences.CURRENT_DISK_PATH.saveString(mActivity, getPathStackJSON());
}
public String popPathStack() {
if (mPathStack.size() == 0) {
return null;
}
String path = mPathStack.remove(mPathStack.size() - 1);
Apple2Preferences.CURRENT_DISK_PATH.saveString(mActivity, getPathStackJSON());
return path;
}
// ------------------------------------------------------------------------
// internals ...
private String pathStackAsDirectory() {
if (mPathStack.size() == 0) {
return null;
}
StringBuilder pathBuffer = new StringBuilder();
for (String component : mPathStack) {
pathBuffer.append(component);
pathBuffer.append(File.separator);
}
return pathBuffer.toString();
}
private static void copyFile(Apple2Activity activity, String subdir, String assetName)
throws IOException {
String outputPath = sDataDir + File.separator + subdir;
Log.d(TAG, "Copying " + subdir + File.separator + assetName + " to " + outputPath + File.separator + assetName + " ...");
boolean made = new File(outputPath).mkdirs();
if (!made) {
Log.d(TAG, "WARNING, cannot mkdirs on path : " + outputPath);
}
InputStream is = activity.getAssets().open(subdir + File.separator + assetName);
File file = new File(outputPath + File.separator + assetName);
boolean madeWriteable = file.setWritable(true);
if (!madeWriteable) {
Log.d(TAG, "WARNING, cannot make a copied file writeable for asset : " + assetName);
}
FileOutputStream os = new FileOutputStream(file);
final int BUF_SZ = 4096;
byte[] buf = new byte[BUF_SZ];
while (true) {
int len = is.read(buf, 0, BUF_SZ);
if (len < 0) {
break;
}
os.write(buf, 0, len);
}
os.flush();
os.close();
}
private void dynamicSetup() {
final ListView disksList = (ListView)mDisksView.findViewById(R.id.listView_settings);
final ListView disksList = (ListView) mDisksView.findViewById(R.id.listView_settings);
disksList.setEnabled(true);
String dataDir = mActivity.getDataDir() + File.separator + "disks";
File dir = new File(dataDir);
String disksDir = pathStackAsDirectory();
boolean isRootPath = false;
if (disksDir == null) {
isRootPath = true;
disksDir = sDataDir + File.separator + "disks"; // default path
}
File dir = new File(disksDir);
final File[] files = dir.listFiles(new FilenameFilter() {
public boolean accept(File dir, String name) {
name = name.toLowerCase();
boolean acceptable = name.endsWith(".dsk") || name.endsWith(".do") || name.endsWith(".po") || name.endsWith(".nib") ||
name.endsWith(".dsk.gz") || name.endsWith(".do.gz") || name.endsWith(".po.gz") || name.endsWith(".nib.gz");
return acceptable;
if (name.equalsIgnoreCase(".")) {
return false;
}
if (name.equalsIgnoreCase("..")) {
return false;
}
if (name.endsWith(".dsk") || name.endsWith(".do") || name.endsWith(".po") || name.endsWith(".nib") || name.endsWith(".dsk.gz") || name.endsWith(".do.gz") || name.endsWith(".po.gz") || name.endsWith(".nib.gz")) {
return true;
}
File file = new File(dir, name);
return file.isDirectory();
}
});
Arrays.sort(files);
int len = files.length;
final String[] fileNames = new String[len];
final boolean[] isDirectory = new boolean[len];
for (int i=0; i<files.length; i++) {
File file = files[i];
fileNames[i] = file.getName();
isDirectory[i] = file.isDirectory();
final boolean includeExternalStoragePath = (sExternalStorageAvailable && isRootPath);
int idx = includeExternalStoragePath ? 1 : 0;
final String[] fileNames = new String[files.length + idx];
final boolean[] isDirectory = new boolean[files.length + idx];
if (includeExternalStoragePath) {
fileNames[0] = sExternalFilesDir.toString();
isDirectory[0] = true;
}
for (File file : files) {
isDirectory[idx] = file.isDirectory();
fileNames[idx] = file.getName();
if (isDirectory[idx]) {
fileNames[idx] += File.separator;
}
++idx;
}
ArrayAdapter<?> adapter = new ArrayAdapter<String>(mActivity, R.layout.a2disk, R.id.a2disk_title, fileNames) {
@ -85,11 +311,12 @@ public class Apple2DisksMenu implements Apple2MenuView {
public boolean areAllItemsEnabled() {
return true;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View view = super.getView(position, convertView, parent);
LinearLayout layout = (LinearLayout)view.findViewById(R.id.a2disk_widget_frame);
LinearLayout layout = (LinearLayout) view.findViewById(R.id.a2disk_widget_frame);
if (layout.getChildCount() > 0) {
// layout cells appear to be reused when scrolling into view ... make sure we start with clear hierarchy
layout.removeAllViews();
@ -105,43 +332,68 @@ public class Apple2DisksMenu implements Apple2MenuView {
}
};
final int offset = includeExternalStoragePath ? 1 : 0;
disksList.setAdapter(adapter);
disksList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
public void onItemClick(AdapterView<?> parent, View view, final int position, long id) {
if (isDirectory[position]) {
// TODO FIXME ...
Log.d(TAG, "Descending to path : " + fileNames[position]);
pushPathStack(fileNames[position]);
dynamicSetup();
ListView disksList = (ListView) mDisksView.findViewById(R.id.listView_settings);
disksList.postInvalidate();
} else {
RadioButton diskA = (RadioButton) mDisksView.findViewById(R.id.radioButton_diskA);
CheckBox readWrite = (CheckBox) mDisksView.findViewById(R.id.checkBox_readWrite);
Apple2DisksMenu.this.dismiss();
mActivity.nativeChooseDisk(files[position].getAbsolutePath(), diskA.isChecked(), !readWrite.isChecked());
String title = mActivity.getResources().getString(R.string.header_disks);
title = title + " " + fileNames[position];
AlertDialog.Builder builder = new AlertDialog.Builder(mActivity).setCancelable(true).setMessage(title);
LayoutInflater inflater = (LayoutInflater) mActivity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
final View diskConfirmationView = inflater.inflate(R.layout.a2disk_confirmation, null, false);
builder.setView(diskConfirmationView);
final RadioButton diskA = (RadioButton) diskConfirmationView.findViewById(R.id.radioButton_diskA);
diskA.setChecked(Apple2Preferences.CURRENT_DISK_A.booleanValue(mActivity));
diskA.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
Apple2Preferences.CURRENT_DISK_A.saveBoolean(mActivity, isChecked);
}
});
final RadioButton diskB = (RadioButton) diskConfirmationView.findViewById(R.id.radioButton_diskB);
diskB.setChecked(!Apple2Preferences.CURRENT_DISK_A.booleanValue(mActivity));
final RadioButton readOnly = (RadioButton) diskConfirmationView.findViewById(R.id.radioButton_readOnly);
readOnly.setChecked(Apple2Preferences.CURRENT_DISK_RO.booleanValue(mActivity));
readOnly.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
Apple2Preferences.CURRENT_DISK_RO.saveBoolean(mActivity, isChecked);
}
});
final RadioButton readWrite = (RadioButton) diskConfirmationView.findViewById(R.id.radioButton_readWrite);
readWrite.setChecked(!Apple2Preferences.CURRENT_DISK_RO.booleanValue(mActivity));
builder.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
});
builder.setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
mActivity.dismissAllMenus();
mActivity.nativeChooseDisk(files[position - offset].getAbsolutePath(), diskA.isChecked(), readOnly.isChecked());
}
});
builder.show();
}
}
});
}
public final boolean isCalibrating() {
return false;
}
public void show() {
if (isShowing()) {
return;
}
dynamicSetup();
mActivity.pushApple2View(this);
}
public void dismiss() {
mActivity.popApple2View(this);
}
public boolean isShowing() {
return mDisksView.isShown();
}
public View getView() {
return mDisksView;
}
}

View File

@ -87,7 +87,9 @@ public class Apple2JoystickCalibration implements Apple2MenuView {
public void dismiss() {
for (Apple2MenuView apple2MenuView : mViewStack) {
mActivity.pushApple2View(apple2MenuView);
if (apple2MenuView != this) {
mActivity.pushApple2View(apple2MenuView);
}
}
Apple2Preferences.nativeSetTouchMenuEnabled(mTouchMenuEnabled);
@ -97,6 +99,10 @@ public class Apple2JoystickCalibration implements Apple2MenuView {
mActivity.popApple2View(this);
}
public void dismissAll() {
dismiss();
}
public boolean isShowing() {
return mSettingsView.isShown();
}

View File

@ -210,7 +210,7 @@ public class Apple2JoystickSettingsMenu extends Apple2AbstractMenu {
@Override
public void handleSelection(Apple2Activity activity, Apple2AbstractMenu settingsMenu, boolean isChecked) {
ArrayList<Apple2MenuView> viewStack = new ArrayList<Apple2MenuView>();
ArrayList<Apple2MenuView> viewStack = new ArrayList<>();
{
int idx = 0;
while (true) {

View File

@ -63,7 +63,28 @@ public class Apple2KeypadSettingsMenu extends Apple2AbstractMenu {
@Override
public void handleSelection(final Apple2Activity activity, final Apple2AbstractMenu settingsMenu, boolean isChecked) {
//new Apple2KeypadChooser(activity).show();
ArrayList<Apple2MenuView> viewStack = new ArrayList<>();
{
int idx = 0;
while (true) {
Apple2MenuView apple2MenuView = activity.peekApple2View(idx);
if (apple2MenuView == null) {
break;
}
viewStack.add(apple2MenuView);
++idx;
}
}
Apple2KeypadChooser chooser = new Apple2KeypadChooser(activity, viewStack);
// show this new view...
chooser.show();
// ...with nothing else underneath 'cept the emulator OpenGL layer
for (Apple2MenuView apple2MenuView : viewStack) {
activity.popApple2View(apple2MenuView);
}
}
},
KEYPAD_CALIBRATE {
@ -79,7 +100,7 @@ public class Apple2KeypadSettingsMenu extends Apple2AbstractMenu {
@Override
public void handleSelection(Apple2Activity activity, Apple2AbstractMenu settingsMenu, boolean isChecked) {
ArrayList<Apple2MenuView> viewStack = new ArrayList<Apple2MenuView>();
ArrayList<Apple2MenuView> viewStack = new ArrayList<>();
{
int idx = 0;
while (true) {

View File

@ -21,6 +21,8 @@ public interface Apple2MenuView {
public void dismiss();
public void dismissAll();
public View getView();
public boolean isCalibrating();

View File

@ -14,9 +14,12 @@ package org.deadc0de.apple2ix;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.util.Log;
import java.io.File;
public enum Apple2Preferences {
PREFS_CONFIGURED {
ASSETS_CONFIGURED {
@Override
public void load(Apple2Activity activity) {
// ...
@ -27,6 +30,60 @@ public enum Apple2Preferences {
activity.getPreferences(Context.MODE_PRIVATE).edit().putBoolean(toString(), true).apply();
}
},
CURRENT_DISK_PATH {
@Override
public void load(final Apple2Activity activity) {
Apple2MainMenu mainMenu = activity.getMainMenu();
if (mainMenu != null) {
mainMenu.getDisksMenu().setPathStackJSON(stringValue(activity));
}
}
@Override
public String stringValue(Apple2Activity activity) {
return activity.getPreferences(Context.MODE_PRIVATE).getString(toString(), "[]");
}
@Override
public void saveString(Apple2Activity activity, String value) {
activity.getPreferences(Context.MODE_PRIVATE).edit().putString(toString(), value).apply();
//load(activity);
}
},
CURRENT_DISK_A {
@Override
public void load(final Apple2Activity activity) {
/* ... */
}
@Override
public boolean booleanValue(Apple2Activity activity) {
return activity.getPreferences(Context.MODE_PRIVATE).getBoolean(toString(), true);
}
@Override
public void saveBoolean(Apple2Activity activity, boolean value) {
activity.getPreferences(Context.MODE_PRIVATE).edit().putBoolean(toString(), value).apply();
//load(activity);
}
},
CURRENT_DISK_RO {
@Override
public void load(final Apple2Activity activity) {
/* ... */
}
@Override
public boolean booleanValue(Apple2Activity activity) {
return activity.getPreferences(Context.MODE_PRIVATE).getBoolean(toString(), true);
}
@Override
public void saveBoolean(Apple2Activity activity, boolean value) {
activity.getPreferences(Context.MODE_PRIVATE).edit().putBoolean(toString(), value).apply();
//load(activity);
}
},
CPU_SPEED_PERCENT {
@Override
public void load(Apple2Activity activity) {
@ -368,6 +425,11 @@ public enum Apple2Preferences {
throw new RuntimeException("DENIED! You're doing it wrong! =P");
}
public void saveString(Apple2Activity activity, String value) {
activity.getPreferences(Context.MODE_PRIVATE).edit().putString(toString(), value).apply();
load(activity);
}
public void saveHiresColor(Apple2Activity activity, HiresColor value) {
activity.getPreferences(Context.MODE_PRIVATE).edit().putInt(toString(), value.ordinal()).apply();
load(activity);
@ -402,6 +464,10 @@ public enum Apple2Preferences {
return (float) activity.getPreferences(Context.MODE_PRIVATE).getInt(toString(), 0);
}
public String stringValue(Apple2Activity activity) {
return activity.getPreferences(Context.MODE_PRIVATE).getString(toString(), null);
}
public static void loadPreferences(Apple2Activity activity) {
for (Apple2Preferences pref : Apple2Preferences.values()) {
pref.load(activity);

View File

@ -68,6 +68,10 @@ public class Apple2SplashScreen implements Apple2MenuView {
mActivity.popApple2View(this);
}
public void dismissAll() {
dismiss();
}
public boolean isShowing() {
return mSettingsView.isShown();
}

View File

@ -0,0 +1,51 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="@color/black"
android:baselineAligned="false"
android:orientation="vertical">
<RadioGroup
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<RadioButton
android:id="@+id/radioButton_diskA"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/diskA" />
<RadioButton
android:id="@+id/radioButton_diskB"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/diskB" />
</RadioGroup>
<RadioGroup
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<RadioButton
android:id="@+id/radioButton_readOnly"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/disk_read_only" />
<RadioButton
android:id="@+id/radioButton_readWrite"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/disk_read_write" />
</RadioGroup>
</LinearLayout>

View File

@ -6,39 +6,30 @@
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<TextView
android:id="@+id/header_disks"
style="?android:attr/listSeparatorTextViewStyle"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/header_disks" />
<RadioGroup
android:layout_width="fill_parent"
android:layout_height="wrap_content"
<LinearLayout
android:background="@color/black"
android:orientation="horizontal"
xmlns:android="http://schemas.android.com/apk/res/android">
android:baselineAligned="false"
android:layout_width="fill_parent"
android:layout_height="wrap_content" >
<RadioButton
<TextView
android:id="@+id/header_disks"
style="?android:attr/listSeparatorTextViewStyle"
android:layout_width="0dp"
android:layout_height="fill_parent"
android:layout_weight="1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/diskA"
android:id="@+id/radioButton_diskA" />
android:text="@string/header_disks" />
<RadioButton
android:layout_weight="1"
<Button
style="?android:attr/buttonStyleSmall"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/diskB"
android:id="@+id/radioButton_diskB" />
android:drawableLeft="@android:drawable/ic_menu_close_clear_cancel"
android:drawableStart="@android:drawable/ic_menu_close_clear_cancel"
android:id="@+id/cancelButton" />
<CheckBox
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/disk_read_write"
android:id="@+id/checkBox_readWrite" />
</RadioGroup>
</LinearLayout>
<ListView
android:layout_width="fill_parent"

View File

@ -20,6 +20,7 @@
<string name="color_interpolated">Interpolated color</string>
<string name="diskA">Drive 1</string>
<string name="diskB">Drive 2</string>
<string name="disk_read_only">Read only</string>
<string name="disk_read_write">Read/write</string>
<string name="emulation_continue">Continue…</string>
<string name="emulation_preferences">Preferences…</string>