mirror of
https://github.com/mauiaaron/apple2.git
synced 2024-06-01 13:41:28 +00:00
781 lines
29 KiB
Java
781 lines
29 KiB
Java
/*
|
|
* Apple // emulator for *nix
|
|
*
|
|
* This software package is subject to the GNU General Public License
|
|
* version 3 or later (your choice) as published by the Free Software
|
|
* Foundation.
|
|
*
|
|
* Copyright 2015 Aaron Culliney
|
|
*
|
|
*/
|
|
|
|
package org.deadc0de.apple2ix;
|
|
|
|
import android.content.Context;
|
|
import android.content.DialogInterface;
|
|
import android.content.Intent;
|
|
import android.graphics.drawable.Drawable;
|
|
import android.net.Uri;
|
|
import android.os.Build;
|
|
import androidx.appcompat.app.AlertDialog;
|
|
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.Button;
|
|
import android.widget.CheckBox;
|
|
import android.widget.CompoundButton;
|
|
import android.widget.ImageView;
|
|
import android.widget.LinearLayout;
|
|
import android.widget.ListView;
|
|
import android.widget.RadioButton;
|
|
import android.widget.TextView;
|
|
import android.widget.Toast;
|
|
|
|
import org.deadc0de.apple2ix.basic.R;
|
|
import org.json.JSONArray;
|
|
import org.json.JSONException;
|
|
import org.json.JSONObject;
|
|
|
|
import java.io.File;
|
|
import java.io.FilenameFilter;
|
|
import java.io.IOException;
|
|
import java.util.ArrayList;
|
|
import java.util.Arrays;
|
|
|
|
public class Apple2DisksMenu implements Apple2MenuView {
|
|
|
|
private final static String TAG = "Apple2DisksMenu";
|
|
|
|
public final static String EXTERNAL_CHOOSER_SENTINEL = "apple2ix://";
|
|
|
|
private Apple2Activity mActivity = null;
|
|
private View mDisksView = null;
|
|
|
|
private final ArrayList<String> mPathStack = new ArrayList<String>();
|
|
|
|
private static boolean sInitializedPath = false;
|
|
|
|
private static native String nativeChooseDisk(String jsonData);
|
|
|
|
private static native void nativeEjectDisk(boolean isDriveA);
|
|
|
|
protected enum SETTINGS implements Apple2AbstractMenu.IMenuEnum {
|
|
CURRENT_DISK_SEARCH_PATH {
|
|
@Override
|
|
public String getPrefKey() {
|
|
return "diskPathStack";
|
|
}
|
|
|
|
@Override
|
|
public Object getPrefDefault() {
|
|
return new JSONArray();
|
|
}
|
|
},
|
|
CURRENT_DRIVE_A {
|
|
@Override
|
|
public String getPrefKey() {
|
|
return "driveACurrent";
|
|
}
|
|
|
|
@Override
|
|
public Object getPrefDefault() {
|
|
return true;
|
|
}
|
|
},
|
|
CURRENT_DISK_RO_BUTTON {
|
|
@Override
|
|
public String getPrefKey() {
|
|
return "driveRO";
|
|
}
|
|
|
|
@Override
|
|
public Object getPrefDefault() {
|
|
return false;
|
|
}
|
|
},
|
|
CURRENT_DISK_PATH_A {
|
|
@Override
|
|
public String getPrefKey() {
|
|
return "driveAInsertedDisk";
|
|
}
|
|
|
|
@Override
|
|
public Object getPrefDefault() {
|
|
return "";
|
|
}
|
|
},
|
|
CURRENT_DISK_PATH_A_RO {
|
|
@Override
|
|
public String getPrefKey() {
|
|
return "driveAInsertedDiskRO";
|
|
}
|
|
|
|
@Override
|
|
public Object getPrefDefault() {
|
|
return false;
|
|
}
|
|
},
|
|
CURRENT_DISK_PATH_B {
|
|
@Override
|
|
public String getPrefKey() {
|
|
return "driveBInsertedDisk";
|
|
}
|
|
|
|
@Override
|
|
public Object getPrefDefault() {
|
|
return "";
|
|
}
|
|
},
|
|
CURRENT_DISK_PATH_B_RO {
|
|
@Override
|
|
public String getPrefKey() {
|
|
return "driveBInsertedDiskRO";
|
|
}
|
|
|
|
@Override
|
|
public Object getPrefDefault() {
|
|
return false;
|
|
}
|
|
},
|
|
USE_NEWSCHOOL_DISK_SELECTION {
|
|
@Override
|
|
public String getPrefKey() {
|
|
return "useNewSchoolDiskSelection";
|
|
}
|
|
|
|
@Override
|
|
public Object getPrefDefault() {
|
|
// 2017/06/30 NOTE : keep this default false to accommodate initial installs that only have access to shipped public domain images
|
|
return false;
|
|
}
|
|
};
|
|
|
|
@Override
|
|
public final String getTitle(Apple2Activity activity) {
|
|
throw new RuntimeException();
|
|
}
|
|
|
|
@Override
|
|
public final String getSummary(Apple2Activity activity) {
|
|
throw new RuntimeException();
|
|
}
|
|
|
|
@Override
|
|
public String getPrefDomain() {
|
|
return Apple2Preferences.PREF_DOMAIN_VM;
|
|
}
|
|
|
|
@Override
|
|
public View getView(final Apple2Activity activity, View convertView) {
|
|
throw new RuntimeException();
|
|
}
|
|
|
|
@Override
|
|
public void handleSelection(final Apple2Activity activity, final Apple2AbstractMenu settingsMenu, boolean isChecked) {
|
|
throw new RuntimeException();
|
|
}
|
|
}
|
|
|
|
public Apple2DisksMenu(Apple2Activity activity) {
|
|
mActivity = activity;
|
|
|
|
LayoutInflater inflater = (LayoutInflater) mActivity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
|
mDisksView = inflater.inflate(R.layout.activity_disks, null, false);
|
|
|
|
final Button cancelButton = (Button) mDisksView.findViewById(R.id.cancelButton);
|
|
cancelButton.setOnClickListener(new View.OnClickListener() {
|
|
@Override
|
|
public void onClick(View v) {
|
|
Apple2DisksMenu.this.mActivity.dismissAllMenus();
|
|
}
|
|
});
|
|
|
|
for (int i = 0; i < 2; i++) {
|
|
final Button ejectButton = (Button) mDisksView.findViewById(i == 0 ? R.id.ejectButton1 : R.id.ejectButton2);
|
|
final int idx = i;
|
|
ejectButton.setOnClickListener(new View.OnClickListener() {
|
|
@Override
|
|
public void onClick(View v) {
|
|
ejectDisk(/*isDriveA:*/idx == 0);
|
|
dynamicSetup();
|
|
}
|
|
});
|
|
}
|
|
|
|
final CheckBox newschoolSelection = (CheckBox) mDisksView.findViewById(R.id.newschoolDiskSelectionButton);
|
|
newschoolSelection.setOnClickListener(new View.OnClickListener() {
|
|
@Override
|
|
public void onClick(View v) {
|
|
Apple2Preferences.setJSONPref(SETTINGS.USE_NEWSCHOOL_DISK_SELECTION, newschoolSelection.isChecked());
|
|
dynamicSetup();
|
|
}
|
|
});
|
|
|
|
final View newschoolChooser = mDisksView.findViewById(R.id.disk_selection_newschool_chooser);
|
|
newschoolChooser.setOnClickListener(new View.OnClickListener() {
|
|
@Override
|
|
public void onClick(View v) {
|
|
final boolean alreadyChoosing = Apple2DiskChooserActivity.sDiskChooserIsChoosing.getAndSet(true);
|
|
if (alreadyChoosing) {
|
|
return;
|
|
}
|
|
|
|
Intent chooserIntent = new Intent(mActivity, Apple2DiskChooserActivity.class);
|
|
chooserIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION/* | Intent.FLAG_ACTIVITY_CLEAR_TOP */);
|
|
|
|
Apple2DiskChooserActivity.sDisksCallback = mActivity;
|
|
mActivity.startActivity(chooserIntent);
|
|
}
|
|
});
|
|
|
|
Apple2Utils.getExternalStorageDirectory(activity);
|
|
}
|
|
|
|
// ------------------------------------------------------------------------
|
|
// Apple2MenuView interface methods
|
|
|
|
public final boolean isCalibrating() {
|
|
return false;
|
|
}
|
|
|
|
public void onKeyTapCalibrationEvent(char ascii, int scancode) {
|
|
/* ... */
|
|
}
|
|
|
|
public void show() {
|
|
if (isShowing()) {
|
|
return;
|
|
}
|
|
if (!sInitializedPath) {
|
|
sInitializedPath = true;
|
|
setPathStackJSON((JSONArray) Apple2Preferences.getJSONPref(SETTINGS.CURRENT_DISK_SEARCH_PATH));
|
|
}
|
|
dynamicSetup();
|
|
mActivity.pushApple2View(this);
|
|
}
|
|
|
|
public void dismiss() {
|
|
String path = null;
|
|
if (!(boolean) Apple2Preferences.getJSONPref(SETTINGS.USE_NEWSCHOOL_DISK_SELECTION)) {
|
|
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.getParent() != null;
|
|
}
|
|
|
|
public View getView() {
|
|
return mDisksView;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------
|
|
// path stack methods
|
|
|
|
public JSONArray getPathStackJSON() {
|
|
return new JSONArray(Arrays.asList(mPathStack.toArray()));
|
|
}
|
|
|
|
public void setPathStackJSON(JSONArray jsonArray) {
|
|
mPathStack.clear();
|
|
try {
|
|
for (int i = 0, count = jsonArray.length(); i < count; i++) {
|
|
String pathComponent = jsonArray.getString(i);
|
|
mPathStack.add(pathComponent);
|
|
}
|
|
} catch (JSONException e) {
|
|
e.printStackTrace();
|
|
}
|
|
}
|
|
|
|
public void pushPathStack(String path) {
|
|
mPathStack.add(path);
|
|
Apple2Preferences.setJSONPref(SETTINGS.CURRENT_DISK_SEARCH_PATH, getPathStackJSON());
|
|
}
|
|
|
|
public String popPathStack() {
|
|
if (mPathStack.size() == 0) {
|
|
return null;
|
|
}
|
|
String path = mPathStack.remove(mPathStack.size() - 1);
|
|
Apple2Preferences.setJSONPref(SETTINGS.CURRENT_DISK_SEARCH_PATH, getPathStackJSON());
|
|
return path;
|
|
}
|
|
|
|
public static void insertDisk(Apple2Activity activity, DiskArgs diskArgs, boolean isDriveA, boolean isReadOnly, boolean onLaunch) {
|
|
try {
|
|
JSONObject map = new JSONObject();
|
|
|
|
ejectDisk(isDriveA);
|
|
|
|
String imageName = diskArgs.path;
|
|
|
|
if (imageName == null) {
|
|
imageName = EXTERNAL_CHOOSER_SENTINEL + diskArgs.uri.toString();
|
|
}
|
|
|
|
if (imageName.startsWith(EXTERNAL_CHOOSER_SENTINEL)) {
|
|
if (!Apple2Utils.isExternalStorageAccessible(activity)) {
|
|
// disallow access if we cannot access external storage
|
|
throw new Exception("External storage not accessible");
|
|
}
|
|
if (diskArgs.pfd == null) {
|
|
if (diskArgs.uri == null) {
|
|
String uriString = imageName.substring(EXTERNAL_CHOOSER_SENTINEL.length());
|
|
diskArgs.uri = Uri.parse(uriString);
|
|
}
|
|
diskArgs.pfd = Apple2DiskChooserActivity.openFileDescriptorFromUri(activity, diskArgs.uri);
|
|
}
|
|
|
|
int fd = diskArgs.pfd.getFd(); // NPE thrown if diskArgs.pfd is null
|
|
map.put("fd", fd);
|
|
} else {
|
|
File file = new File(imageName);
|
|
if (!file.exists()) {
|
|
throw new RuntimeException("cannot insert : " + imageName);
|
|
}
|
|
}
|
|
|
|
if (isDriveA) {
|
|
Apple2Preferences.setJSONPref(SETTINGS.CURRENT_DISK_PATH_A_RO, isReadOnly);
|
|
Apple2Preferences.setJSONPref(SETTINGS.CURRENT_DISK_PATH_A, imageName);
|
|
} else {
|
|
Apple2Preferences.setJSONPref(SETTINGS.CURRENT_DISK_PATH_B_RO, isReadOnly);
|
|
Apple2Preferences.setJSONPref(SETTINGS.CURRENT_DISK_PATH_B, imageName);
|
|
}
|
|
|
|
map.put("disk", imageName);
|
|
map.put("drive", isDriveA ? "0" : "1");
|
|
map.put("readOnly", isReadOnly ? "true" : "false");
|
|
|
|
String jsonString = nativeChooseDisk(map.toString());
|
|
|
|
if (diskArgs.pfd != null) {
|
|
try {
|
|
diskArgs.pfd.close();
|
|
} catch (IOException ioe) {
|
|
Log.e(TAG, "Error attempting to close PFD : " + ioe);
|
|
}
|
|
}
|
|
diskArgs.pfd = null;
|
|
|
|
map = new JSONObject(jsonString);
|
|
boolean inserted = map.getBoolean("inserted");
|
|
if (!inserted) {
|
|
ejectDisk(isDriveA);
|
|
}
|
|
|
|
} catch (Throwable t) {
|
|
Log.d(TAG, "OOPS: " + t);
|
|
}
|
|
}
|
|
|
|
public static void ejectDisk(boolean isDriveA) {
|
|
if (isDriveA) {
|
|
Apple2Preferences.setJSONPref(SETTINGS.CURRENT_DISK_PATH_A, "");
|
|
} else {
|
|
Apple2Preferences.setJSONPref(SETTINGS.CURRENT_DISK_PATH_B, "");
|
|
}
|
|
nativeEjectDisk(isDriveA);
|
|
}
|
|
|
|
public void showDiskInsertionAlertDialog(String title, final DiskArgs diskArgs) {
|
|
|
|
title = mActivity.getResources().getString(R.string.header_disks) + " " + title;
|
|
|
|
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 driveA = (RadioButton) diskConfirmationView.findViewById(R.id.radioButton_diskA);
|
|
boolean driveAChecked = (boolean) Apple2Preferences.getJSONPref(SETTINGS.CURRENT_DRIVE_A);
|
|
driveA.setChecked(driveAChecked);
|
|
driveA.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
|
|
@Override
|
|
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
|
|
Apple2Preferences.setJSONPref(SETTINGS.CURRENT_DRIVE_A, isChecked);
|
|
}
|
|
});
|
|
final RadioButton driveB = (RadioButton) diskConfirmationView.findViewById(R.id.radioButton_diskB);
|
|
driveB.setChecked(!driveAChecked);
|
|
|
|
final RadioButton readOnly = (RadioButton) diskConfirmationView.findViewById(R.id.radioButton_readOnly);
|
|
boolean roChecked = (boolean) Apple2Preferences.getJSONPref(SETTINGS.CURRENT_DISK_RO_BUTTON);
|
|
readOnly.setChecked(roChecked);
|
|
readOnly.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
|
|
@Override
|
|
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
|
|
Apple2Preferences.setJSONPref(SETTINGS.CURRENT_DISK_RO_BUTTON, isChecked);
|
|
}
|
|
});
|
|
|
|
final RadioButton readWrite = (RadioButton) diskConfirmationView.findViewById(R.id.radioButton_readWrite);
|
|
readWrite.setChecked(!roChecked);
|
|
|
|
builder.setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
|
|
@Override
|
|
public void onClick(DialogInterface dialog, int which) {
|
|
boolean isDriveA = driveA.isChecked();
|
|
boolean diskReadOnly = readOnly.isChecked();
|
|
|
|
insertDisk(mActivity, diskArgs, isDriveA, diskReadOnly, /*onLaunch:*/false);
|
|
|
|
dialog.dismiss();
|
|
mActivity.dismissAllMenus();
|
|
}
|
|
});
|
|
|
|
AlertDialog dialog = builder.create();
|
|
mActivity.registerAndShowDialog(dialog);
|
|
}
|
|
|
|
public static boolean hasDiskExtension(String name) {
|
|
|
|
// check file extensions ... sigh ... no String.endsWithIgnoreCase() ?
|
|
|
|
final int len = name.length();
|
|
if (len <= 3) {
|
|
return false;
|
|
}
|
|
|
|
String suffix;
|
|
suffix = name.substring(len - 3, len);
|
|
if (suffix.equalsIgnoreCase(".do") || suffix.equalsIgnoreCase(".po")) {
|
|
return true;
|
|
}
|
|
|
|
if (len <= 4) {
|
|
return false;
|
|
}
|
|
|
|
suffix = name.substring(len - 4, len);
|
|
if (suffix.equalsIgnoreCase(".dsk") || suffix.equalsIgnoreCase(".nib")) {
|
|
return true;
|
|
}
|
|
|
|
if (len <= 6) {
|
|
return false;
|
|
}
|
|
|
|
suffix = name.substring(len - 6, len);
|
|
if (suffix.equalsIgnoreCase(".do.gz") || suffix.equalsIgnoreCase(".po.gz")) {
|
|
return true;
|
|
}
|
|
|
|
if (len <= 7) {
|
|
return false;
|
|
}
|
|
|
|
suffix = name.substring(len - 7, len);
|
|
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 ...
|
|
|
|
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 void dynamicSetup() {
|
|
|
|
final ListView disksList = (ListView) mDisksView.findViewById(R.id.listView_settings);
|
|
|
|
final boolean useNewschoolSelection = (boolean) Apple2Preferences.getJSONPref(SETTINGS.USE_NEWSCHOOL_DISK_SELECTION);
|
|
|
|
final CheckBox newschoolSelection = (CheckBox) mDisksView.findViewById(R.id.newschoolDiskSelectionButton);
|
|
newschoolSelection.setChecked(useNewschoolSelection);
|
|
|
|
final boolean isKitKatOrBetter = (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT);
|
|
|
|
final boolean includeExternalFileChooser = Apple2Utils.isExternalStorageAccessible(mActivity) && isKitKatOrBetter;
|
|
|
|
final View newschoolChooser = mDisksView.findViewById(R.id.disk_selection_newschool_chooser);
|
|
|
|
if (!includeExternalFileChooser || !useNewschoolSelection) {
|
|
disksList.setEnabled(true);
|
|
disksList.setVisibility(View.VISIBLE);
|
|
newschoolChooser.setVisibility(View.INVISIBLE);
|
|
|
|
for (int i = 0; i < 2; i++) {
|
|
LinearLayout layout = (LinearLayout) mDisksView.findViewById((i == 0) ? R.id.a2_newschool_driveA_layout : R.id.a2_newschool_driveB_layout);
|
|
layout.setVisibility(View.INVISIBLE);
|
|
}
|
|
|
|
if (!includeExternalFileChooser) {
|
|
newschoolSelection.setVisibility(View.INVISIBLE);
|
|
}
|
|
Apple2Preferences.setJSONPref(SETTINGS.USE_NEWSCHOOL_DISK_SELECTION, false);
|
|
oldschoolDynamicSetup();
|
|
return;
|
|
}
|
|
|
|
disksList.setEnabled(false);
|
|
disksList.setVisibility(View.INVISIBLE);
|
|
newschoolChooser.setVisibility(View.VISIBLE);
|
|
|
|
// new external file chooser activity can allow navigation to restricted external SD Card(s) ...
|
|
newschoolSelection.setVisibility(View.VISIBLE);
|
|
|
|
for (int i = 0; i < 2; i++) {
|
|
String imageName = null;
|
|
do {
|
|
String diskPath = (String) Apple2Preferences.getJSONPref((i == 0) ? SETTINGS.CURRENT_DISK_PATH_A : SETTINGS.CURRENT_DISK_PATH_B);
|
|
|
|
if (diskPath == null || diskPath.equals("")) {
|
|
break;
|
|
}
|
|
|
|
if (diskPath.startsWith(Apple2DisksMenu.EXTERNAL_CHOOSER_SENTINEL)) {
|
|
diskPath = diskPath.substring(Apple2DisksMenu.EXTERNAL_CHOOSER_SENTINEL.length());
|
|
}
|
|
|
|
Uri uri = Uri.parse(diskPath);
|
|
if (uri == null) {
|
|
break;
|
|
}
|
|
|
|
diskPath = uri.getPath();
|
|
int idx = diskPath.lastIndexOf("/");
|
|
if (idx < 0) {
|
|
break;
|
|
}
|
|
|
|
imageName = Apple2DiskChooserActivity.getFileNameFromUri(mActivity, uri);
|
|
} while (false);
|
|
|
|
LinearLayout layout = (LinearLayout) mDisksView.findViewById((i == 0) ? R.id.a2_newschool_driveA_layout : R.id.a2_newschool_driveB_layout);
|
|
|
|
if (imageName == null || imageName.equals("")) {
|
|
layout.setVisibility(View.INVISIBLE);
|
|
} else {
|
|
layout.setVisibility(View.VISIBLE);
|
|
|
|
boolean readOnly = (boolean) Apple2Preferences.getJSONPref((i == 0) ? SETTINGS.CURRENT_DISK_PATH_A_RO : SETTINGS.CURRENT_DISK_PATH_B_RO);
|
|
imageName = "(" + mActivity.getResources().getString((readOnly ? R.string.disk_read_only : R.string.disk_read_write)) + "): " + imageName;
|
|
TextView textView = (TextView) mDisksView.findViewById((i == 0) ? R.id.a2_newschool_diskA : R.id.a2_newschool_diskB);
|
|
textView.setText(imageName);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void oldschoolDynamicSetup() {
|
|
|
|
final ListView disksList = (ListView) mDisksView.findViewById(R.id.listView_settings);
|
|
|
|
String disksDir = pathStackAsDirectory();
|
|
final boolean isRootPath = (disksDir == null);
|
|
if (isRootPath) {
|
|
disksDir = Apple2Utils.getDataDir(mActivity) + File.separator + "disks"; // default path
|
|
}
|
|
|
|
while (disksDir.charAt(disksDir.length() - 1) == File.separatorChar) {
|
|
disksDir = disksDir.substring(0, disksDir.length() - 1);
|
|
}
|
|
|
|
File dir = new File(disksDir);
|
|
final File[] files = dir.listFiles(new FilenameFilter() {
|
|
public boolean accept(File dir, String name) {
|
|
name = name.toLowerCase();
|
|
if (name.equals(".")) {
|
|
return false;
|
|
}
|
|
if (name.equals("..")) {
|
|
return false;
|
|
}
|
|
File file = new File(dir, name);
|
|
return file.isDirectory() || hasDiskExtension(name) || hasStateExtension(name);
|
|
}
|
|
});
|
|
|
|
// This appears to happen in cases where the external files directory String is valid, but is not actually mounted
|
|
// We could probably check for more media "states" in the setup above ... but this defensive coding probably should
|
|
// remain here after any refactoring =)
|
|
if (files == null) {
|
|
dismiss();
|
|
return;
|
|
}
|
|
|
|
Arrays.sort(files);
|
|
|
|
final File realExtStorageDir = Apple2Utils.getRealExternalStorageDirectory(mActivity);
|
|
final boolean isStoragePath = !isRootPath && (realExtStorageDir != null) && disksDir.equalsIgnoreCase(realExtStorageDir.getAbsolutePath());
|
|
if (isStoragePath) {
|
|
// promote apple2ix directory to top of list
|
|
for (int i = 0; i < files.length; i++) {
|
|
if (files[i].getName().equals("apple2ix")) {
|
|
if (i > 0) {
|
|
System.arraycopy(/*src:*/files, /*srcPos:*/0, /*dst:*/files, /*dstPos:*/1, /*length:*/i);
|
|
files[0] = new File(realExtStorageDir, "apple2ix");
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
final boolean includeExternalStoragePath = (Apple2Utils.isExternalStorageAccessible(mActivity) && isRootPath);
|
|
|
|
final int offset = includeExternalStoragePath ? 1 : 0;
|
|
final String[] fileNames = new String[files.length + offset];
|
|
final String[] filePaths = new String[files.length + offset];
|
|
final boolean[] isDirectory = new boolean[files.length + offset];
|
|
|
|
int idx = 0;
|
|
|
|
if (includeExternalStoragePath) {
|
|
filePaths[idx] = Apple2Utils.getRealExternalStorageDirectory(mActivity).getAbsolutePath();
|
|
fileNames[idx] = mActivity.getResources().getString(R.string.storage);
|
|
isDirectory[idx] = true;
|
|
++idx;
|
|
}
|
|
|
|
for (File file : files) {
|
|
isDirectory[idx] = file.isDirectory();
|
|
filePaths[idx] = file.getName();
|
|
fileNames[idx] = filePaths[idx];
|
|
if (isDirectory[idx]) {
|
|
fileNames[idx] += File.separator;
|
|
}
|
|
++idx;
|
|
}
|
|
|
|
ArrayAdapter<?> adapter = new ArrayAdapter<String>(mActivity, R.layout.a2disk, R.id.a2disk_title, fileNames) {
|
|
@Override
|
|
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);
|
|
if (layout.getChildCount() > 0) {
|
|
// layout cells appear to be reused when scrolling into view ... make sure we start with clear hierarchy
|
|
layout.removeAllViews();
|
|
}
|
|
|
|
if (isDirectory[position]) {
|
|
ImageView imageView = new ImageView(mActivity);
|
|
Drawable drawable = mActivity.getResources().getDrawable(android.R.drawable.ic_menu_more);
|
|
imageView.setImageDrawable(drawable);
|
|
layout.addView(imageView);
|
|
} else {
|
|
|
|
String imageName = files[position - offset].getAbsolutePath();
|
|
String eject = mActivity.getResources().getString(R.string.disk_eject);
|
|
if (imageName.equals((String) Apple2Preferences.getJSONPref(SETTINGS.CURRENT_DISK_PATH_A))) {
|
|
Button ejectButton = new Button(mActivity);
|
|
ejectButton.setText(eject + " 1");
|
|
ejectButton.setOnClickListener(new View.OnClickListener() {
|
|
@Override
|
|
public void onClick(View v) {
|
|
ejectDisk(/*driveA:*/true);
|
|
dynamicSetup();
|
|
}
|
|
});
|
|
layout.addView(ejectButton);
|
|
} else if (imageName.equals((String) Apple2Preferences.getJSONPref(SETTINGS.CURRENT_DISK_PATH_B))) {
|
|
Button ejectButton = new Button(mActivity);
|
|
ejectButton.setText(eject + " 2");
|
|
ejectButton.setOnClickListener(new View.OnClickListener() {
|
|
@Override
|
|
public void onClick(View v) {
|
|
ejectDisk(/*driveA:*/false);
|
|
dynamicSetup();
|
|
}
|
|
});
|
|
layout.addView(ejectButton);
|
|
}
|
|
|
|
}
|
|
return view;
|
|
}
|
|
};
|
|
|
|
final String parentDisksDir = disksDir;
|
|
final boolean parentIsRootPath = isRootPath;
|
|
|
|
disksList.setAdapter(adapter);
|
|
disksList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
|
|
@Override
|
|
public void onItemClick(AdapterView<?> parent, View view, final int position, long id) {
|
|
if (isDirectory[position]) {
|
|
Log.d(TAG, "Descending to path : " + filePaths[position]);
|
|
if (parentIsRootPath && !new File(filePaths[position]).isAbsolute()) {
|
|
pushPathStack(parentDisksDir + File.separator + filePaths[position]);
|
|
} else {
|
|
pushPathStack(filePaths[position]);
|
|
}
|
|
dynamicSetup();
|
|
ListView disksList = (ListView) mDisksView.findViewById(R.id.listView_settings);
|
|
disksList.postInvalidate();
|
|
return;
|
|
}
|
|
|
|
final String imageName = files[position - offset].getAbsolutePath();
|
|
if (imageName.equals((String) Apple2Preferences.getJSONPref(SETTINGS.CURRENT_DISK_PATH_A))) {
|
|
ejectDisk(/*isDriveA:*/true);
|
|
dynamicSetup();
|
|
return;
|
|
}
|
|
if (imageName.equals((String) Apple2Preferences.getJSONPref(SETTINGS.CURRENT_DISK_PATH_B))) {
|
|
ejectDisk(/*isDriveA:*/false);
|
|
dynamicSetup();
|
|
return;
|
|
}
|
|
|
|
if (hasStateExtension(imageName)) {
|
|
final String jsonString = "{ \"stateFile\" : \"" + imageName + "\" }";
|
|
final boolean restored = Apple2MainMenu.restoreEmulatorState(mActivity, jsonString);
|
|
mActivity.dismissAllMenus();
|
|
if (!restored) {
|
|
Toast.makeText(mActivity, R.string.state_not_restored, Toast.LENGTH_SHORT).show();
|
|
}
|
|
return;
|
|
}
|
|
|
|
showDiskInsertionAlertDialog(/*title:*/fileNames[position], /*diskPath:*/new DiskArgs(imageName));
|
|
}
|
|
});
|
|
}
|
|
}
|