First cut at Android disk selection interface

This commit is contained in:
Aaron Culliney 2015-04-07 22:40:22 -07:00
parent ae27a891dd
commit e808dd9861
8 changed files with 335 additions and 5 deletions

View File

@ -39,6 +39,8 @@ public class Apple2Activity extends Activity {
private final static int SOFTKEYBOARD_THRESHOLD = 50;
private final static int MAX_FINGERS = 32;// HACK ...
private String mDataDir = null;
private Apple2View mView = null;
private AlertDialog mQuitDialog = null;
private AlertDialog mRebootDialog = null;
@ -77,6 +79,7 @@ public class Apple2Activity extends Activity {
public native void nativeEnableTouchJoystick(boolean visibility);
public native void nativeSetColor(int color);
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
@ -152,8 +155,8 @@ public class Apple2Activity extends Activity {
super.onCreate(savedInstanceState);
Log.e(TAG, "onCreate()");
String dataDir = firstTimeInitialization();
nativeOnCreate(dataDir);
mDataDir = firstTimeInitialization();
nativeOnCreate(mDataDir);
mView = new Apple2View(this);
setContentView(mView);
@ -214,9 +217,13 @@ public class Apple2Activity extends Activity {
}
Apple2SettingsMenu settingsMenu = mView.getSettingsMenu();
Apple2DisksMenu disksMenu = mView.getDisksMenu();
if (settingsMenu != null) {
settingsMenu.dismissWithoutResume();
}
if (disksMenu != null) {
disksMenu.dismissWithoutResume();
}
boolean someMenuShowing = mainMenu.isShowing() ||
(mQuitDialog != null && mQuitDialog.isShowing()) ||
@ -237,9 +244,12 @@ public class Apple2Activity extends Activity {
public boolean onKeyUp(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
Apple2SettingsMenu settingsMenu = mView.getSettingsMenu();
Apple2DisksMenu disksMenu = mView.getDisksMenu();
if (settingsMenu != null) {
if (settingsMenu.isShowing()) {
settingsMenu.dismiss();
} else if (disksMenu.isShowing()) {
disksMenu.dismiss();
} else {
mView.showMainMenu();
}
@ -304,9 +314,13 @@ public class Apple2Activity extends Activity {
}
Apple2SettingsMenu settingsMenu = mainMenu.getSettingsMenu();
Apple2DisksMenu disksMenu = mView.getDisksMenu();
if (settingsMenu != null && settingsMenu.isShowing()) {
break;
}
if (disksMenu != null && disksMenu.isShowing()) {
break;
}
//printSamples(event);
int action = event.getActionMasked();
@ -396,6 +410,14 @@ public class Apple2Activity extends Activity {
nativeGraphicsInitialized(width, height);
}
public Apple2View getView() {
return mView;
}
public String getDataDir() {
return mDataDir;
}
public int getWidth() {
return mWidth;
}

View File

@ -0,0 +1,159 @@
/*
* Apple // emulator for *nix
*
* This software package is subject to the GNU General Public License
* version 2 or later (your choice) as published by the Free Software
* Foundation.
*
* THERE ARE NO WARRANTIES WHATSOEVER.
*
*/
package org.deadc0de.apple2ix;
import android.content.Context;
import android.graphics.drawable.Drawable;
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.FrameLayout;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.RadioButton;
import java.io.File;
import java.io.FilenameFilter;
import java.util.Arrays;
public class Apple2DisksMenu {
private final static String TAG = "Apple2DisksMenu";
private Apple2Activity mActivity = null;
private Apple2View mParentView = null;
private View mDisksView = null;
public Apple2DisksMenu(Apple2Activity activity, Apple2View parent) {
mActivity = activity;
mParentView = parent;
setup();
}
private void setup() {
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);
CheckBox readWrite = (CheckBox) mDisksView.findViewById(R.id.checkBox_readWrite);
readWrite.setChecked(false);
}
private void dynamicSetup() {
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);
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;
}
});
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();
}
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);
}
return view;
}
};
disksList.setAdapter(adapter);
disksList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
if (isDirectory[position]) {
// TODO FIXME ...
} else {
RadioButton diskA = (RadioButton)mDisksView.findViewById(R.id.radioButton_diskA);
CheckBox readWrite = (CheckBox)mDisksView.findViewById(R.id.checkBox_readWrite);
mActivity.nativeChooseDisk(files[position].getAbsolutePath(), diskA.isChecked(), !readWrite.isChecked());
Apple2DisksMenu.this.dismissWithoutResume();
Apple2DisksMenu.this.mActivity.getView().showMainMenu();
}
}
});
}
public void show() {
if (isShowing()) {
return;
}
dynamicSetup();
mActivity.nativeOnPause();
mActivity.addContentView(mDisksView, new FrameLayout.LayoutParams(mActivity.getWidth(), mActivity.getHeight()));
}
public void dismiss() {
if (isShowing()) {
dismissWithoutResume();
mActivity.nativeOnResume();
}
}
public void dismissWithoutResume() {
if (isShowing()) {
((ViewGroup)mDisksView.getParent()).removeView(mDisksView);
// HACK FIXME TODO ... we seem to lose ability to toggle/show soft keyboard upon dismissal of mDisksView after use.
// This hack appears to get the Android UI unwedged ... =P
Apple2MainMenu androidUIFTW = mParentView.getMainMenu();
androidUIFTW.show();
androidUIFTW.dismiss();
}
}
public boolean isShowing() {
return mDisksView.isShown();
}
}

View File

@ -35,6 +35,7 @@ public class Apple2MainMenu {
private Apple2View mParentView = null;
private PopupWindow mMainMenuPopup = null;
private Apple2SettingsMenu mSettingsMenu = null;
private Apple2DisksMenu mDisksMenu = null;
public Apple2MainMenu(Apple2Activity activity, Apple2View parent) {
mActivity = activity;
@ -161,7 +162,8 @@ public class Apple2MainMenu {
mMainMenuPopup.setOnDismissListener(new PopupWindow.OnDismissListener() {
@Override
public void onDismiss() {
if ( !(getSettingsMenu().isShowing() /*|| getDisksMenu().isShowing()*/) ) {
boolean otherMenusShowing = (getSettingsMenu().isShowing() || getDisksMenu().isShowing());
if (!otherMenusShowing) {
Apple2MainMenu.this.mActivity.nativeOnResume();
}
}
@ -169,7 +171,9 @@ public class Apple2MainMenu {
}
public void showDisksMenu() {
Log.d(TAG, "showDisksMenu...");
Apple2DisksMenu disksMenu = getDisksMenu();
disksMenu.show();
mMainMenuPopup.dismiss();
}
public void showSettings() {
@ -178,6 +182,13 @@ public class Apple2MainMenu {
mMainMenuPopup.dismiss();
}
public synchronized Apple2DisksMenu getDisksMenu() {
if (mDisksMenu == null) {
mDisksMenu = new Apple2DisksMenu(mActivity, mParentView);
}
return mDisksMenu;
}
public synchronized Apple2SettingsMenu getSettingsMenu() {
if (mSettingsMenu == null) {
mSettingsMenu = new Apple2SettingsMenu(mActivity, mParentView);

View File

@ -93,7 +93,8 @@ class Apple2View extends GLSurfaceView {
public void showMainMenu() {
if (mMainMenu != null) {
Apple2SettingsMenu settingsMenu = mMainMenu.getSettingsMenu();
if (!settingsMenu.isShowing()) {
Apple2DisksMenu disksMenu = mMainMenu.getDisksMenu();
if (! (settingsMenu.isShowing() || disksMenu.isShowing()) ) {
mMainMenu.show();
}
}
@ -107,6 +108,10 @@ class Apple2View extends GLSurfaceView {
return (mMainMenu == null) ? null : mMainMenu.getSettingsMenu();
}
public Apple2DisksMenu getDisksMenu() {
return (mMainMenu == null) ? null : mMainMenu.getDisksMenu();
}
public void toggleKeyboard() {
InputMethodManager inputMethodManager=(InputMethodManager)mActivity.getSystemService(Context.INPUT_METHOD_SERVICE);
inputMethodManager.toggleSoftInputFromWindow(getApplicationWindowToken(), InputMethodManager.SHOW_FORCED, 0);

View File

@ -0,0 +1,61 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2006 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<!-- Modified from Gingerbread android.R.layout.preference -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="?android:attr/listPreferredItemHeight"
android:gravity="center_vertical"
android:paddingRight="?android:attr/scrollbarSize">
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="15dip"
android:layout_marginRight="6dip"
android:layout_marginTop="6dip"
android:layout_marginBottom="6dip"
android:layout_weight="1">
<TextView android:id="@+id/a2disk_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:singleLine="true"
android:textAppearance="?android:attr/textAppearanceLarge"
android:ellipsize="marquee"
android:fadingEdge="horizontal" />
<!--
<TextView android:id="@+id/a2disk_summary"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/a2preference_title"
android:layout_alignLeft="@id/a2preference_title"
android:textAppearance="?android:attr/textAppearanceSmall"
android:maxLines="4" />
-->
</RelativeLayout>
<!-- Custom preference should place its actual preference widget here. -->
<LinearLayout android:id="@+id/a2disk_widget_frame"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="center_vertical"
android:orientation="vertical"
android:descendantFocusability="blocksDescendants" />
</LinearLayout>

View File

@ -0,0 +1,48 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:background="@color/black"
android:orientation="vertical"
android:baselineAligned="false"
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"
android:orientation="horizontal"
xmlns:android="http://schemas.android.com/apk/res/android">
<RadioButton
android:layout_weight="1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/diskA"
android:id="@+id/radioButton_diskA" />
<RadioButton
android:layout_weight="1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/diskB"
android:id="@+id/radioButton_diskB" />
<CheckBox
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/disk_read_write"
android:id="@+id/checkBox_readWrite" />
</RadioGroup>
<ListView
android:layout_width="fill_parent"
android:layout_height="0dp"
android:id="@+id/listView_settings"
android:layout_weight="1" />
</LinearLayout>

View File

@ -15,6 +15,10 @@
<string name="configure_joystick_summary">TouchJoy axis and buttons, hitboxes, etc</string>
<string name="configure_video">Configure video…</string>
<string name="configure_video_summary">Color settings</string>
<string name="diskA">Drive 1</string>
<string name="diskB">Drive 2</string>
<string name="disk_read_write">Read/write</string>
<string name="header_disks">Insert disk:</string>
<string name="joystick">Joystick</string>
<string name="joystick_keyA">Key Joystick 1</string>
<string name="joystick_keyB">Key Joystick 2</string>

View File

@ -276,3 +276,23 @@ void Java_org_deadc0de_apple2ix_Apple2Activity_nativeSetColor(JNIEnv *env, jobje
video_redraw();
}
void Java_org_deadc0de_apple2ix_Apple2Activity_nativeChooseDisk(JNIEnv *env, jobject obj, jstring jPath, jboolean driveA, jboolean readOnly) {
const char *path = (*env)->GetStringUTFChars(env, jPath, 0);
int drive = driveA ? 0 : 1;
int ro = readOnly ? 1 : 0;
LOG("nativeChooseDisk(%s, %s, %s)", path, driveA ? "drive A" : "drive B", readOnly ? "read only" : "read/write");
if (c_new_diskette_6(drive, path, ro)) {
char *gzPath = NULL;
asprintf(&gzPath, "%s.gz", path);
if (c_new_diskette_6(drive, gzPath, ro)) {
// TODO FIXME : show error message disk was unreadable ...
} else {
// TODO FIXME : show an OpenGL message that the disk was chosen ...
}
FREE(gzPath);
} else {
// TODO FIXME : show an OpenGL message that the disk was chosen ...
}
(*env)->ReleaseStringUTFChars(env, jPath, path);
}