Improved Android main menu and begin to implement the settings page

This commit is contained in:
Aaron Culliney 2015-03-12 15:12:18 -07:00
parent 99d9c3510e
commit 45c59fcb56
8 changed files with 519 additions and 45 deletions

View File

@ -35,9 +35,10 @@ public class Apple2Activity extends Activity {
private final static String TAG = "Apple2Activity";
private final static int BUF_SZ = 4096;
private final static String PREFS_CONFIGURED = "prefs_configured";
private final static int SOFTKEYBOARD_THRESHOLD = 10;
private final static int SOFTKEYBOARD_THRESHOLD = 50;
private Apple2View mView = null;
private AlertDialog mQuitDialog = null;
private int mWidth = 0;
private int mHeight = 0;
private boolean mSoftKeyboardShowing = false;
@ -59,7 +60,7 @@ public class Apple2Activity extends Activity {
// 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
// these assets
// security or DRM for these assets =)
private String firstTimeInitialization() {
String dataDir = null;
@ -156,14 +157,46 @@ public class Apple2Activity extends Activity {
protected void onResume() {
super.onResume();
mView.onResume();
nativeOnResume();
Apple2MainMenu mainMenu = mView.getMainMenu();
boolean noMenusShowing = !(
(mainMenu != null && mainMenu.isShowing()) ||
(mQuitDialog != null && mQuitDialog.isShowing()) );
if (noMenusShowing) {
nativeOnResume();
}
}
@Override
protected void onPause() {
super.onPause();
mView.onPause();
Apple2MainMenu mainMenu = mView.getMainMenu();
if (mainMenu == null) {
// wow, early onPause, just quit and restart later
nativeOnQuit();
return;
}
nativeOnPause();
if (isSoftKeyboardShowing()) {
mView.toggleKeyboard();
}
Apple2SettingsMenu settingsMenu = mView.getSettingsMenu();
if (settingsMenu != null) {
settingsMenu.dismissWithoutResume();
}
if (mainMenu.isShowing() || (mQuitDialog != null && mQuitDialog.isShowing())) {
// this is a good paused state
} else {
mView.showMainMenu();
}
}
@Override
@ -175,14 +208,22 @@ public class Apple2Activity extends Activity {
@Override
public boolean onKeyUp(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
maybeQuitApp();
Apple2SettingsMenu settingsMenu = mView.getSettingsMenu();
if (settingsMenu != null && settingsMenu.isShowing()) {
settingsMenu.dismiss();
} else {
maybeQuitApp();
}
return true;
} else if (keyCode == KeyEvent.KEYCODE_MENU) {
mView.showMainMenu();
return true;
} else if ((keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) || (keyCode == KeyEvent.KEYCODE_VOLUME_MUTE) || (keyCode == KeyEvent.KEYCODE_VOLUME_UP)) {
return false;
} else {
nativeOnKeyUp(keyCode, event.getMetaState());
return true;
}
nativeOnKeyUp(keyCode, event.getMetaState());
return true;
}
@Override
@ -211,27 +252,26 @@ public class Apple2Activity extends Activity {
public void maybeQuitApp() {
nativeOnPause();
AlertDialog dialog = new AlertDialog.Builder(this).setCancelable(true).setMessage("Quit Apple2ix?").setPositiveButton("OK", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
nativeOnQuit();
}
}).setNegativeButton("No", null).create();
dialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
@Override
public void onCancel(DialogInterface dialog) {
nativeOnResume();
}
});
dialog.setOnDismissListener(new DialogInterface.OnDismissListener() {
@Override
public void onDismiss(DialogInterface dialog) {
nativeOnResume();
}
});
dialog.show();
if (mQuitDialog == null) {
mQuitDialog = new AlertDialog.Builder(this).setCancelable(true).setMessage(R.string.quit).setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
nativeOnQuit();
}
}).setNegativeButton(R.string.no, null).create();
mQuitDialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
@Override
public void onCancel(DialogInterface dialog) {
nativeOnResume();
}
});
mQuitDialog.setOnDismissListener(new DialogInterface.OnDismissListener() {
@Override
public void onDismiss(DialogInterface dialog) {
nativeOnResume();
}
});
}
mQuitDialog.show();
}
}

View File

@ -26,34 +26,48 @@ import android.widget.PopupWindow;
public class Apple2MainMenu {
public final static int MENU_INSET = 20;
private final static int MENU_INSET = 20;
private final static String TAG = "Apple2MainMenu";
private Apple2Activity mActivity = null;
private Apple2View mParentView = null;
private PopupWindow mMainMenuPopup = null;
private Apple2SettingsMenu mSettingsMenu = null;
public Apple2MainMenu(Apple2Activity activity, Apple2View parent) {
mActivity = activity;
mParentView = parent;
init();
setup();
}
private void init() {
private void setup() {
LayoutInflater inflater = (LayoutInflater)mActivity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View listLayout=inflater.inflate(R.layout.activity_main_menu, null, false);
ListView mainMenuView = (ListView)listLayout.findViewById(R.id.main_popup_menu);
mainMenuView.setEnabled(true);
LinearLayout mainPopupContainer = (LinearLayout)listLayout.findViewById(R.id.main_popup_container);
String[] values = new String[] {
"Emulation Settings...",
"Load Disk Image...",
"Resume...",
mActivity.getResources().getString(R.string.menu_settings),
mActivity.getResources().getString(R.string.menu_disks),
mActivity.getResources().getString(R.string.spacer),
mActivity.getResources().getString(R.string.reboot),
};
ArrayAdapter<?> adapter = new ArrayAdapter<String>(mActivity, android.R.layout.simple_list_item_1, android.R.id.text1, values);
ArrayAdapter<?> adapter = new ArrayAdapter<String>(mActivity, android.R.layout.simple_list_item_1, android.R.id.text1, values) {
@Override
public boolean areAllItemsEnabled() {
return false;
}
@Override
public boolean isEnabled(int position) {
if (position < 0 || position > 3) {
throw new ArrayIndexOutOfBoundsException();
}
return position != 2;
}
};
mainMenuView.setAdapter(adapter);
mainMenuView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
@ -65,6 +79,9 @@ public class Apple2MainMenu {
case 1:
Apple2MainMenu.this.showDisksMenu();
break;
case 3:
Apple2MainMenu.this.reboot();
break;
default:
Apple2MainMenu.this.dismiss();
break;
@ -97,7 +114,9 @@ public class Apple2MainMenu {
mMainMenuPopup.setOnDismissListener(new PopupWindow.OnDismissListener() {
@Override
public void onDismiss() {
Apple2MainMenu.this.mActivity.nativeOnResume();
if ( !(getSettingsMenu().isShowing() /*|| getDisksMenu().isShowing()*/) ) {
Apple2MainMenu.this.mActivity.nativeOnResume();
}
}
});
}
@ -107,7 +126,21 @@ public class Apple2MainMenu {
}
public void showSettings() {
Log.d(TAG, "showSettings...");
Apple2SettingsMenu settings = getSettingsMenu();
settings.show();
mMainMenuPopup.dismiss();
}
public void reboot() {
mActivity.nativeReboot();
mMainMenuPopup.dismiss();
}
public synchronized Apple2SettingsMenu getSettingsMenu() {
if (mSettingsMenu == null) {
mSettingsMenu = new Apple2SettingsMenu(mActivity, mParentView);
}
return mSettingsMenu;
}
public void show() {
@ -123,6 +156,7 @@ public class Apple2MainMenu {
public void dismiss() {
if (mMainMenuPopup.isShowing()) {
mMainMenuPopup.dismiss();
// listener will resume ...
}
}

View File

@ -0,0 +1,120 @@
/*
* 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.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.FrameLayout;
import android.widget.ListView;
import android.widget.TabHost;
public class Apple2SettingsMenu {
private final static String TAG = "Apple2SettingsMenu";
private Apple2Activity mActivity = null;
private Apple2View mParentView = null;
private View mSettingsView = null;
public Apple2SettingsMenu(Apple2Activity activity, Apple2View parent) {
mActivity = activity;
mParentView = parent;
setup();
}
private void setup() {
LayoutInflater inflater = (LayoutInflater)mActivity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
mSettingsView = inflater.inflate(R.layout.activity_settings, null, false);
ListView settingsMenuView = (ListView)mSettingsView.findViewById(R.id.joystick_settings_listview);
String[] values = new String[] {
mActivity.getResources().getString(R.string.joystick_configure),
};
ArrayAdapter<?> adapter = new ArrayAdapter<String>(mActivity, android.R.layout.simple_list_item_1, android.R.id.text1, values);
settingsMenuView.setAdapter(adapter);
settingsMenuView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
switch (position) {
case 0:
Apple2SettingsMenu.this.showJoystickConfiguration();
break;
default:
break;
}
}
});
TabHost tabHost = (TabHost)mSettingsView.findViewById(R.id.tabHost_settings);
tabHost.setup();
TabHost.TabSpec spec = tabHost.newTabSpec("tab_general");
spec.setIndicator(mActivity.getResources().getString(R.string.tab_general), mActivity.getResources().getDrawable(android.R.drawable.ic_menu_edit));
spec.setContent(R.id.tab_general);
tabHost.addTab(spec);
spec = tabHost.newTabSpec("tab_joystick");
spec.setIndicator(mActivity.getResources().getString(R.string.tab_joystick), mActivity.getResources().getDrawable(android.R.drawable.ic_menu_compass));
spec.setContent(R.id.tab_joystick);
tabHost.addTab(spec);
Button rebootButton = (Button)mSettingsView.findViewById(R.id.reboot_button);
rebootButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Apple2SettingsMenu.this.mActivity.nativeReboot();
Apple2SettingsMenu.this.dismiss();
}
});
}
public void showJoystickConfiguration() {
Log.d(TAG, "showJoystickConfiguration...");
}
public void show() {
if (isShowing()) {
return;
}
mActivity.nativeOnPause();
mActivity.addContentView(mSettingsView, new FrameLayout.LayoutParams(mActivity.getWidth(), mActivity.getHeight()));
}
public void dismiss() {
if (isShowing()) {
dismissWithoutResume();
mActivity.nativeOnResume();
}
}
public void dismissWithoutResume() {
if (isShowing()) {
((ViewGroup)mSettingsView.getParent()).removeView(mSettingsView);
// HACK FIXME TODO ... we seem to lose ability to toggle/show soft keyboard upon dismissal of mSettingsView after use.
// This hack appears to get the Android UI unwedged ... =P
Apple2MainMenu androidUIFTW = mParentView.getMainMenu();
androidUIFTW.show();
androidUIFTW.dismiss();
}
}
public boolean isShowing() {
return mSettingsView.isShown();
}
}

View File

@ -154,7 +154,8 @@ class Apple2View extends GLSurfaceView {
case (MotionEvent.ACTION_POINTER_UP):
if (mUltiTapEventBegin) {
toggleMultiTapMenu();
Log.d(TAG, "Toggling keyboard...");
toggleKeyboard();
}
mTapEventBegin = false;
mUltiTapEventBegin = false;
@ -174,10 +175,13 @@ class Apple2View extends GLSurfaceView {
public void showMainMenu() {
if (mMainMenu != null) {
if (mActivity.isSoftKeyboardShowing()) {
toggleMultiTapMenu();
Apple2SettingsMenu settingsMenu = mMainMenu.getSettingsMenu();
if (!settingsMenu.isShowing()) {
if (mActivity.isSoftKeyboardShowing()) {
toggleKeyboard();
}
mMainMenu.show();
}
mMainMenu.show();
}
}
@ -185,7 +189,11 @@ class Apple2View extends GLSurfaceView {
return mMainMenu;
}
public void toggleMultiTapMenu() {
public Apple2SettingsMenu getSettingsMenu() {
return (mMainMenu == null) ? null : mMainMenu.getSettingsMenu();
}
public void toggleKeyboard() {
InputMethodManager inputMethodManager=(InputMethodManager)mActivity.getSystemService(Context.INPUT_METHOD_SERVICE);
inputMethodManager.toggleSoftInputFromWindow(getApplicationWindowToken(), InputMethodManager.SHOW_FORCED, 0);
}
@ -405,7 +413,9 @@ class Apple2View extends GLSurfaceView {
public void onSurfaceChanged(GL10 gl, int width, int height) {
Apple2View.this.mActivity.graphicsInitialized(width, height);
Apple2View.this.mMainMenu = new Apple2MainMenu(Apple2View.this.mActivity, Apple2View.this);
if (Apple2View.this.mMainMenu == null) {
Apple2View.this.mMainMenu = new Apple2MainMenu(Apple2View.this.mActivity, Apple2View.this);
}
}
public void onSurfaceCreated(GL10 gl, EGLConfig config) {

View File

@ -0,0 +1,43 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:background="@color/black"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<TabHost
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:id="@+id/tabHost_settings">
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical">
<TabWidget
android:id="@android:id/tabs"
android:layout_width="fill_parent"
android:layout_height="wrap_content"></TabWidget>
<FrameLayout
android:id="@android:id/tabcontent"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<include
android:id="@+id/tab_general"
android:layout_width="fill_parent"
android:layout_height="match_parent"
layout="@layout/general_settings" >
</include>
<include
android:id="@+id/tab_joystick"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
layout="@layout/joystick_settings" >
</include>
</FrameLayout>
</LinearLayout>
</TabHost>
</LinearLayout>

View File

@ -0,0 +1,134 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/tab_settings1"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical|center_horizontal"
android:orientation="horizontal">
<TextView
android:id="@+id/cpuspeed_section_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/speed_cpu"
android:textAppearance="?android:attr/textAppearanceSmall"
android:layout_marginTop="4dp"
android:textSize="14sp" />
</LinearLayout>
<LinearLayout
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical">
<SeekBar
android:layout_width="0dp"
android:layout_height="wrap_content"
android:id="@+id/cpuspeed_scale"
android:max="375"
android:progress="75"
android:layout_margin="4dp"
android:layout_weight=".75" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceSmall"
android:text="100%"
android:id="@+id/cpuspeed_label"
android:layout_marginRight="4dp"
android:textSize="14sp" />
<CheckBox
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/max"
android:id="@+id/cpuspeed_max"
android:layout_marginRight="4dp"
android:textSize="14sp" />
</LinearLayout>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical|center_horizontal"
android:orientation="horizontal">
<TextView
android:id="@+id/altspeed_section_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/speed_alt"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textSize="14sp" />
</LinearLayout>
<LinearLayout
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical">
<SeekBar
android:layout_width="0dp"
android:layout_height="wrap_content"
android:id="@+id/altspeed_scale"
android:max="375"
android:progress="375"
android:layout_margin="4dp"
android:layout_weight=".75" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceSmall"
android:text="400%"
android:id="@+id/altspeed_label"
android:layout_marginRight="4dp"
android:textSize="14sp" />
<CheckBox
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/max"
android:id="@+id/altspeed_max"
android:layout_marginRight="4dp"
android:textSize="14sp"
android:checked="true" />
</LinearLayout>
<LinearLayout
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical">
<CheckBox
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/speed_swipe"
android:id="@+id/checkBox_speedswipe"
android:checked="true"
android:textSize="14sp" />
</LinearLayout>
<LinearLayout
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:gravity="bottom|right"
android:layout_margin="4dp">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/reboot"
android:id="@+id/reboot_button" />
</LinearLayout>
</LinearLayout>

View File

@ -0,0 +1,72 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/tab_settings2"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical">
<LinearLayout
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_margin="4dp"
android:gravity="center_vertical">
<CheckBox
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/joystick_show"
android:id="@+id/checkBox_joystick"
android:textSize="14sp"
android:checked="true" />
</LinearLayout>
<LinearLayout
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_margin="4dp"
android:gravity="fill_horizontal">
<RadioButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/joystick"
android:id="@+id/radioButton_joystick0"
android:textSize="14sp"
android:layout_marginRight="4dp"
android:checked="true"
android:layout_weight=".33" />
<RadioButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/joystick_keyA"
android:id="@+id/radioButton_joystickA"
android:textSize="14sp"
android:layout_marginRight="4dp"
android:layout_weight=".33" />
<RadioButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/joystick_keyB"
android:id="@+id/radioButton_joystickB"
android:textSize="14sp"
android:layout_marginRight="4dp" />
</LinearLayout>
<LinearLayout
android:orientation="horizontal"
android:baselineAligned="false"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<ListView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:id="@+id/joystick_settings_listview"
android:layout_weight="1" />
</LinearLayout>
</LinearLayout>

View File

@ -1,4 +1,25 @@
<resources>
<string name="app_name">Apple2ix</string>
<color name="black">#000000</color>
<color name="white">#ffffff</color>
<string name="app_name">Apple2ix</string>
<string name="joystick">Joystick</string>
<string name="joystick_configure">Configure emulated joysticks…</string>
<string name="joystick_keyA">Key Joystick 1</string>
<string name="joystick_keyB">Key Joystick 2</string>
<string name="joystick_show">Show emulated joystick</string>
<string name="keyboard">Keyboard</string>
<string name="keyboard_two_finger">2-finger-tap shows keyboard</string>
<string name="max">Max</string>
<string name="menu_disks">Load disk image…</string>
<string name="menu_settings">Emulator settings…</string>
<string name="no">No</string>
<string name="ok">OK</string>
<string name="quit">Quit Apple2ix?</string>
<string name="reboot">Reboot Apple //e…</string>
<string name="spacer"> </string>
<string name="speed_alt">Alternate CPU Speed</string>
<string name="speed_cpu">CPU Speed</string>
<string name="speed_swipe">Swipe toggles between configured speeds</string>
<string name="tab_general">General</string>
<string name="tab_joystick">Joystick</string>
</resources>