609 lines
22 KiB
Java
609 lines
22 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.app.Activity;
|
|
import android.app.AlertDialog;
|
|
import android.content.DialogInterface;
|
|
import android.content.Intent;
|
|
import android.media.AudioManager;
|
|
import android.net.Uri;
|
|
import android.os.Bundle;
|
|
import android.os.StrictMode;
|
|
import android.util.Log;
|
|
import android.view.KeyEvent;
|
|
import android.view.MotionEvent;
|
|
import android.view.View;
|
|
import android.view.ViewGroup;
|
|
import android.widget.FrameLayout;
|
|
import android.widget.Toast;
|
|
|
|
import java.io.File;
|
|
import java.util.ArrayList;
|
|
import java.util.Collections;
|
|
import java.util.StringTokenizer;
|
|
import java.util.concurrent.atomic.AtomicBoolean;
|
|
|
|
import org.deadc0de.apple2ix.basic.BuildConfig;
|
|
import org.deadc0de.apple2ix.basic.R;
|
|
|
|
public class Apple2Activity extends Activity {
|
|
|
|
private final static String TAG = "Apple2Activity";
|
|
private final static int MAX_FINGERS = 32;// HACK ...
|
|
private static volatile boolean DEBUG_STRICT = false;
|
|
|
|
private Apple2View mView = null;
|
|
private Runnable mGraphicsInitializedRunnable = null;
|
|
private Apple2SplashScreen mSplashScreen = null;
|
|
private Apple2MainMenu mMainMenu = null;
|
|
private Apple2SettingsMenu mSettingsMenu = null;
|
|
private Apple2DisksMenu mDisksMenu = null;
|
|
|
|
private ArrayList<Apple2MenuView> mMenuStack = new ArrayList<Apple2MenuView>();
|
|
private ArrayList<AlertDialog> mAlertDialogs = new ArrayList<AlertDialog>();
|
|
|
|
private AtomicBoolean mPausing = new AtomicBoolean(false);
|
|
|
|
private float[] mXCoords = new float[MAX_FINGERS];
|
|
private float[] mYCoords = new float[MAX_FINGERS];
|
|
|
|
// non-null if we failed to load/link the native code ... likely we are running on some bizarre 'droid variant
|
|
private static Throwable sNativeBarfedThrowable = null;
|
|
private static boolean sNativeBarfed = false;
|
|
|
|
static {
|
|
try {
|
|
System.loadLibrary("apple2ix");
|
|
} catch (Throwable barf) {
|
|
sNativeBarfed = true;
|
|
sNativeBarfedThrowable = barf;
|
|
}
|
|
}
|
|
|
|
public final static long NATIVE_TOUCH_HANDLED = (1 << 0);
|
|
public final static long NATIVE_TOUCH_REQUEST_SHOW_MENU = (1 << 1);
|
|
|
|
public final static long NATIVE_TOUCH_KEY_TAP = (1 << 4);
|
|
public final static long NATIVE_TOUCH_KBD = (1 << 5);
|
|
public final static long NATIVE_TOUCH_JOY = (1 << 6);
|
|
public final static long NATIVE_TOUCH_MENU = (1 << 7);
|
|
public final static long NATIVE_TOUCH_JOY_KPAD = (1 << 8);
|
|
|
|
public final static long NATIVE_TOUCH_INPUT_DEVICE_CHANGED = (1 << 16);
|
|
public final static long NATIVE_TOUCH_CPU_SPEED_DEC = (1 << 17);
|
|
public final static long NATIVE_TOUCH_CPU_SPEED_INC = (1 << 18);
|
|
|
|
public final static long NATIVE_TOUCH_ASCII_SCANCODE_SHIFT = 32;
|
|
public final static long NATIVE_TOUCH_ASCII_SCANCODE_MASK = 0xFFFFL;
|
|
public final static long NATIVE_TOUCH_ASCII_MASK = 0xFF00L;
|
|
public final static long NATIVE_TOUCH_SCANCODE_MASK = 0x00FFL;
|
|
|
|
private native void nativeOnCreate(String dataDir, int sampleRate, int monoBufferSize, int stereoBufferSize);
|
|
|
|
private native void nativeOnKeyDown(int keyCode, int metaState);
|
|
|
|
private native void nativeOnKeyUp(int keyCode, int metaState);
|
|
|
|
public native void nativeEmulationResume();
|
|
|
|
public native void nativeEmulationPause();
|
|
|
|
public native void nativeOnQuit();
|
|
|
|
public native long nativeOnTouch(int action, int pointerCount, int pointerIndex, float[] xCoords, float[] yCoords);
|
|
|
|
public native void nativeReboot();
|
|
|
|
public native void nativeChooseDisk(String path, boolean driveA, boolean readOnly);
|
|
|
|
public native void nativeEjectDisk(boolean driveA);
|
|
|
|
|
|
@Override
|
|
public void onCreate(Bundle savedInstanceState) {
|
|
if (Apple2Activity.DEBUG_STRICT && BuildConfig.DEBUG) {
|
|
StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
|
|
.detectDiskReads()
|
|
.detectDiskWrites()
|
|
.detectAll()
|
|
.penaltyLog()
|
|
.build());
|
|
StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()
|
|
.detectLeakedSqlLiteObjects()
|
|
/*.detectLeakedClosableObjects()*/
|
|
.penaltyLog()
|
|
.penaltyDeath()
|
|
.build());
|
|
}
|
|
super.onCreate(savedInstanceState);
|
|
|
|
Log.e(TAG, "onCreate()");
|
|
|
|
// placeholder view on initial launch
|
|
if (mView == null) {
|
|
setContentView(new View(this));
|
|
}
|
|
|
|
Apple2CrashHandler.getInstance().initializeAndSetCustomExceptionHandler(this);
|
|
if (sNativeBarfed) {
|
|
Log.e(TAG, "NATIVE BARFED...", sNativeBarfedThrowable);
|
|
return;
|
|
}
|
|
|
|
int sampleRate = DevicePropertyCalculator.getRecommendedSampleRate(this);
|
|
int monoBufferSize = DevicePropertyCalculator.getRecommendedBufferSize(this, /*isStereo:*/false);
|
|
int stereoBufferSize = DevicePropertyCalculator.getRecommendedBufferSize(this, /*isStereo:*/true);
|
|
Log.d(TAG, "Device sampleRate:" + sampleRate + " mono bufferSize:" + monoBufferSize + " stereo bufferSize:" + stereoBufferSize);
|
|
|
|
String dataDir = Apple2DisksMenu.getDataDir(this);
|
|
nativeOnCreate(dataDir, sampleRate, monoBufferSize, stereoBufferSize);
|
|
|
|
final boolean firstTime = !Apple2Preferences.FIRST_TIME_CONFIGURED.booleanValue(this);
|
|
Apple2Preferences.FIRST_TIME_CONFIGURED.saveBoolean(this, true);
|
|
|
|
showSplashScreen(!firstTime);
|
|
Apple2CrashHandler.getInstance().checkForCrashes(this);
|
|
|
|
mGraphicsInitializedRunnable = new Runnable() {
|
|
@Override
|
|
public void run() {
|
|
if (firstTime) {
|
|
Apple2Preferences.KeypadPreset.IJKM_SPACE.apply(Apple2Activity.this);
|
|
}
|
|
Apple2Preferences.loadPreferences(Apple2Activity.this);
|
|
}
|
|
};
|
|
|
|
// first-time initializations
|
|
if (firstTime) {
|
|
new Thread(new Runnable() {
|
|
@Override
|
|
public void run() {
|
|
Apple2DisksMenu.firstTime(Apple2Activity.this);
|
|
mSplashScreen.setDismissable(true);
|
|
Log.d(TAG, "Finished first time copying...");
|
|
}
|
|
}).start();
|
|
}
|
|
|
|
mSettingsMenu = new Apple2SettingsMenu(this);
|
|
mDisksMenu = new Apple2DisksMenu(this);
|
|
|
|
Intent intent = getIntent();
|
|
String path = null;
|
|
if (intent != null) {
|
|
Uri data = intent.getData();
|
|
if (data != null) {
|
|
path = data.getPath();
|
|
}
|
|
}
|
|
if (path != null && Apple2DisksMenu.hasDiskExtension(path)) {
|
|
handleInsertDiskIntent(path);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
protected void onResume() {
|
|
super.onResume();
|
|
if (sNativeBarfed) {
|
|
Apple2CrashHandler.getInstance().abandonAllHope(this, sNativeBarfedThrowable);
|
|
return;
|
|
}
|
|
|
|
Log.d(TAG, "onResume()");
|
|
showSplashScreen(/*dismissable:*/true);
|
|
Apple2CrashHandler.getInstance().checkForCrashes(this); // NOTE : needs to be called again to clean-up
|
|
}
|
|
|
|
@Override
|
|
protected void onPause() {
|
|
super.onPause();
|
|
if (sNativeBarfed) {
|
|
return;
|
|
}
|
|
|
|
boolean wasPausing = mPausing.getAndSet(true);
|
|
if (wasPausing) {
|
|
return;
|
|
}
|
|
|
|
Log.d(TAG, "onPause()");
|
|
if (mView != null) {
|
|
mView.onPause();
|
|
}
|
|
|
|
// Apparently not good to leave popup/dialog windows showing when backgrounding.
|
|
// Dismiss these popups to avoid android.view.WindowLeaked issues
|
|
synchronized (this) {
|
|
dismissAllMenus();
|
|
nativeEmulationPause();
|
|
}
|
|
|
|
mPausing.set(false);
|
|
}
|
|
|
|
@Override
|
|
public boolean onKeyDown(int keyCode, KeyEvent event) {
|
|
if (sNativeBarfed) {
|
|
return true;
|
|
}
|
|
if ((keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) || (keyCode == KeyEvent.KEYCODE_VOLUME_MUTE) || (keyCode == KeyEvent.KEYCODE_VOLUME_UP)) {
|
|
return false;
|
|
}
|
|
nativeOnKeyDown(keyCode, event.getMetaState());
|
|
return true;
|
|
}
|
|
|
|
@Override
|
|
public boolean onKeyUp(int keyCode, KeyEvent event) {
|
|
if (sNativeBarfed) {
|
|
return true;
|
|
}
|
|
if (keyCode == KeyEvent.KEYCODE_BACK) {
|
|
Apple2MenuView apple2MenuView = peekApple2View();
|
|
if (apple2MenuView == null) {
|
|
showMainMenu();
|
|
} else {
|
|
apple2MenuView.dismiss();
|
|
}
|
|
return true;
|
|
} else if (keyCode == KeyEvent.KEYCODE_MENU) {
|
|
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;
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public boolean onTouchEvent(MotionEvent event) {
|
|
do {
|
|
|
|
if (sNativeBarfed) {
|
|
break;
|
|
}
|
|
if (mMainMenu == null) {
|
|
break;
|
|
}
|
|
|
|
Apple2MenuView apple2MenuView = peekApple2View();
|
|
if ((apple2MenuView != null) && (!apple2MenuView.isCalibrating())) {
|
|
break;
|
|
}
|
|
|
|
//printSamples(event);
|
|
int action = event.getActionMasked();
|
|
int pointerIndex = event.getActionIndex();
|
|
int pointerCount = event.getPointerCount();
|
|
for (int i = 0; i < pointerCount/* && i < MAX_FINGERS */; i++) {
|
|
mXCoords[i] = event.getX(i);
|
|
mYCoords[i] = event.getY(i);
|
|
}
|
|
|
|
long nativeFlags = nativeOnTouch(action, pointerCount, pointerIndex, mXCoords, mYCoords);
|
|
|
|
if ((nativeFlags & NATIVE_TOUCH_HANDLED) == 0) {
|
|
break;
|
|
}
|
|
|
|
if ((nativeFlags & NATIVE_TOUCH_REQUEST_SHOW_MENU) != 0) {
|
|
mMainMenu.show();
|
|
}
|
|
|
|
if ((nativeFlags & NATIVE_TOUCH_KEY_TAP) != 0) {
|
|
if (Apple2Preferences.KEYBOARD_CLICK_ENABLED.booleanValue(this)) {
|
|
AudioManager am = (AudioManager) getSystemService(AUDIO_SERVICE);
|
|
if (am != null) {
|
|
am.playSoundEffect(AudioManager.FX_KEY_CLICK);
|
|
}
|
|
}
|
|
|
|
if ((apple2MenuView != null) && apple2MenuView.isCalibrating()) {
|
|
long asciiScancodeLong = nativeFlags & (NATIVE_TOUCH_ASCII_SCANCODE_MASK << NATIVE_TOUCH_ASCII_SCANCODE_SHIFT);
|
|
int asciiInt = (int) (asciiScancodeLong >> (NATIVE_TOUCH_ASCII_SCANCODE_SHIFT + 8));
|
|
int scancode = (int) ((asciiScancodeLong >> NATIVE_TOUCH_ASCII_SCANCODE_SHIFT) & 0xFFL);
|
|
char ascii = (char) asciiInt;
|
|
apple2MenuView.onKeyTapCalibrationEvent(ascii, scancode);
|
|
}
|
|
}
|
|
|
|
if ((nativeFlags & NATIVE_TOUCH_MENU) == 0) {
|
|
break;
|
|
}
|
|
|
|
// handle menu-specific actions
|
|
|
|
if ((nativeFlags & NATIVE_TOUCH_INPUT_DEVICE_CHANGED) != 0) {
|
|
Apple2Preferences.TouchDeviceVariant nextVariant;
|
|
if ((nativeFlags & NATIVE_TOUCH_KBD) != 0) {
|
|
nextVariant = Apple2Preferences.TouchDeviceVariant.KEYBOARD;
|
|
} else if ((nativeFlags & NATIVE_TOUCH_JOY) != 0) {
|
|
nextVariant = Apple2Preferences.TouchDeviceVariant.JOYSTICK;
|
|
} else if ((nativeFlags & NATIVE_TOUCH_JOY_KPAD) != 0) {
|
|
nextVariant = Apple2Preferences.TouchDeviceVariant.JOYSTICK_KEYPAD;
|
|
} else {
|
|
int touchDevice = Apple2Preferences.nativeGetCurrentTouchDevice();
|
|
nextVariant = Apple2Preferences.TouchDeviceVariant.next(touchDevice);
|
|
}
|
|
Apple2Preferences.CURRENT_TOUCH_DEVICE.saveTouchDevice(this, nextVariant);
|
|
} else if ((nativeFlags & NATIVE_TOUCH_CPU_SPEED_DEC) != 0) {
|
|
int percentSpeed = Apple2Preferences.nativeGetCPUSpeed();
|
|
if (percentSpeed > 400) { // HACK: max value from native side
|
|
percentSpeed = 375;
|
|
} else if (percentSpeed > 100) {
|
|
percentSpeed -= 25;
|
|
} else {
|
|
percentSpeed -= 5;
|
|
}
|
|
Apple2Preferences.CPU_SPEED_PERCENT.saveInt(this, percentSpeed);
|
|
} else if ((nativeFlags & NATIVE_TOUCH_CPU_SPEED_INC) != 0) {
|
|
int percentSpeed = Apple2Preferences.nativeGetCPUSpeed();
|
|
if (percentSpeed >= 100) {
|
|
percentSpeed += 25;
|
|
} else {
|
|
percentSpeed += 5;
|
|
}
|
|
Apple2Preferences.CPU_SPEED_PERCENT.saveInt(this, percentSpeed);
|
|
}
|
|
} while (false);
|
|
|
|
return super.onTouchEvent(event);
|
|
}
|
|
|
|
public void showMainMenu() {
|
|
if (mMainMenu != null) {
|
|
if (!(mSettingsMenu.isShowing() || mDisksMenu.isShowing())) {
|
|
mMainMenu.show();
|
|
}
|
|
}
|
|
}
|
|
|
|
public Apple2MainMenu getMainMenu() {
|
|
return mMainMenu;
|
|
}
|
|
|
|
public synchronized Apple2DisksMenu getDisksMenu() {
|
|
return mDisksMenu;
|
|
}
|
|
|
|
public synchronized Apple2SettingsMenu getSettingsMenu() {
|
|
return mSettingsMenu;
|
|
}
|
|
|
|
private void handleInsertDiskIntent(final String path) {
|
|
runOnUiThread(new Runnable() {
|
|
@Override
|
|
public void run() {
|
|
synchronized (Apple2Activity.this) {
|
|
if (mMainMenu == null) {
|
|
return;
|
|
}
|
|
String diskPath = path;
|
|
File diskFile = new File(diskPath);
|
|
if (!diskFile.canRead()) {
|
|
Toast.makeText(Apple2Activity.this, Apple2Activity.this.getString(R.string.disk_insert_could_not_read), Toast.LENGTH_SHORT).show();
|
|
return;
|
|
}
|
|
|
|
Apple2Preferences.CURRENT_DISK_A_RO.saveBoolean(Apple2Activity.this, true);
|
|
final int len = diskPath.length();
|
|
final String suffix = diskPath.substring(len - 3, len);
|
|
if (suffix.equalsIgnoreCase(".gz")) { // HACK FIXME TODO : small amount of code duplication of Apple2DisksMenu
|
|
diskPath = diskPath.substring(0, len - 3);
|
|
}
|
|
Apple2Preferences.CURRENT_DISK_A.saveString(Apple2Activity.this, diskPath);
|
|
|
|
while (mDisksMenu.popPathStack() != null) {
|
|
/* ... */
|
|
}
|
|
|
|
File storageDir = Apple2DisksMenu.getExternalStorageDirectory();
|
|
if (storageDir != null) {
|
|
String storagePath = storageDir.getAbsolutePath();
|
|
if (diskPath.contains(storagePath)) {
|
|
diskPath = diskPath.replace(storagePath + File.separator, "");
|
|
mDisksMenu.pushPathStack(storagePath);
|
|
}
|
|
}
|
|
StringTokenizer tokenizer = new StringTokenizer(diskPath, File.separator);
|
|
while (tokenizer.hasMoreTokens()) {
|
|
String token = tokenizer.nextToken();
|
|
if (token.equals("")) {
|
|
continue;
|
|
}
|
|
if (Apple2DisksMenu.hasDiskExtension(token)) {
|
|
continue;
|
|
}
|
|
mDisksMenu.pushPathStack(token);
|
|
}
|
|
|
|
Toast.makeText(Apple2Activity.this, Apple2Activity.this.getString(R.string.disk_insert_toast), Toast.LENGTH_SHORT).show();
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
public Apple2SplashScreen getSplashScreen() {
|
|
return mSplashScreen;
|
|
}
|
|
|
|
private void showSplashScreen(boolean dismissable) {
|
|
if (mSplashScreen != null) {
|
|
return;
|
|
}
|
|
mSplashScreen = new Apple2SplashScreen(this, dismissable);
|
|
mSplashScreen.show();
|
|
}
|
|
|
|
private void setupGLView() {
|
|
|
|
boolean glViewFirstTime = false;
|
|
if (mView == null) {
|
|
glViewFirstTime = true;
|
|
mView = new Apple2View(this, mGraphicsInitializedRunnable);
|
|
mGraphicsInitializedRunnable = null;
|
|
mMainMenu = new Apple2MainMenu(this, mView);
|
|
}
|
|
|
|
if (glViewFirstTime) {
|
|
// HACK NOTE : do not blanket setContentView() ... it appears to wedge Gingerbread
|
|
setContentView(mView);
|
|
} else {
|
|
mView.onResume();
|
|
}
|
|
}
|
|
|
|
public void registerAndShowDialog(AlertDialog dialog) {
|
|
dialog.show();
|
|
mAlertDialogs.add(dialog);
|
|
}
|
|
|
|
public synchronized void pushApple2View(Apple2MenuView apple2MenuView) {
|
|
mMenuStack.add(apple2MenuView);
|
|
View menuView = apple2MenuView.getView();
|
|
nativeEmulationPause();
|
|
addContentView(menuView, new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT));
|
|
}
|
|
|
|
public synchronized Apple2MenuView popApple2View() {
|
|
int lastIndex = mMenuStack.size() - 1;
|
|
if (lastIndex < 0) {
|
|
return null;
|
|
}
|
|
|
|
Apple2MenuView apple2MenuView = mMenuStack.remove(lastIndex);
|
|
_disposeApple2View(apple2MenuView);
|
|
return apple2MenuView;
|
|
}
|
|
|
|
public synchronized Apple2MenuView peekApple2View() {
|
|
int lastIndex = mMenuStack.size() - 1;
|
|
if (lastIndex < 0) {
|
|
return null;
|
|
}
|
|
|
|
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();
|
|
}
|
|
|
|
for (AlertDialog dialog : mAlertDialogs) {
|
|
dialog.dismiss();
|
|
}
|
|
mAlertDialogs.clear();
|
|
|
|
// Get rid of the menu hierarchy
|
|
ArrayList<Apple2MenuView> menuHierarchy = new ArrayList<Apple2MenuView>(mMenuStack);
|
|
Collections.reverse(menuHierarchy);
|
|
for (Apple2MenuView view : menuHierarchy) {
|
|
view.dismissAll();
|
|
}
|
|
}
|
|
|
|
public synchronized Apple2MenuView popApple2View(Apple2MenuView apple2MenuView) {
|
|
boolean wasRemoved = mMenuStack.remove(apple2MenuView);
|
|
_disposeApple2View(apple2MenuView);
|
|
return wasRemoved ? apple2MenuView : null;
|
|
}
|
|
|
|
private void _disposeApple2View(Apple2MenuView apple2MenuView) {
|
|
|
|
boolean dismissedSplashScreen = false;
|
|
|
|
// Actually remove View from view hierarchy
|
|
{
|
|
View menuView = apple2MenuView.getView();
|
|
ViewGroup viewGroup = (ViewGroup) menuView.getParent();
|
|
if (viewGroup != null) {
|
|
viewGroup.removeView(menuView);
|
|
}
|
|
if (apple2MenuView instanceof Apple2SplashScreen) { // 20151101 HACK NOTE : use instanceof to avoid edge case where joystick calibration occurred (and thus the splash was already dismissed without proper mView initialization)
|
|
mSplashScreen = null;
|
|
dismissedSplashScreen = true;
|
|
}
|
|
}
|
|
|
|
// if no more views on menu stack, resume emulation
|
|
if (mMenuStack.size() == 0) {
|
|
dismissAllMenus(); // NOTE : at this point, this should not be re-entrant into mMenuStack, it should just dismiss lingering popups
|
|
if (!mPausing.get()) {
|
|
if (dismissedSplashScreen) {
|
|
setupGLView();
|
|
} else {
|
|
nativeEmulationResume();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public void maybeResumeCPU() {
|
|
if (mMenuStack.size() == 0 && !mPausing.get()) {
|
|
nativeEmulationResume();
|
|
}
|
|
}
|
|
|
|
public void maybeQuitApp() {
|
|
nativeEmulationPause();
|
|
AlertDialog quitDialog = new AlertDialog.Builder(this).setIcon(R.drawable.ic_launcher).setCancelable(true).setTitle(R.string.quit_really).setMessage(R.string.quit_warning).setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
|
|
@Override
|
|
public void onClick(DialogInterface dialog, int which) {
|
|
nativeOnQuit();
|
|
Apple2Activity.this.finish();
|
|
new Runnable() {
|
|
@Override
|
|
public void run() {
|
|
try {
|
|
Thread.sleep(2000);
|
|
} catch (InterruptedException ex) {
|
|
// ...
|
|
}
|
|
System.exit(0);
|
|
}
|
|
}.run();
|
|
}
|
|
}).setNegativeButton(R.string.no, null).create();
|
|
registerAndShowDialog(quitDialog);
|
|
}
|
|
|
|
public void maybeReboot() {
|
|
nativeEmulationPause();
|
|
AlertDialog rebootDialog = new AlertDialog.Builder(this).setIcon(R.drawable.ic_launcher).setCancelable(true).setTitle(R.string.reboot_really).setMessage(R.string.reboot_warning).setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
|
|
@Override
|
|
public void onClick(DialogInterface dialog, int which) {
|
|
nativeReboot();
|
|
Apple2Activity.this.mMainMenu.dismiss();
|
|
}
|
|
}).setNegativeButton(R.string.no, null).create();
|
|
registerAndShowDialog(rebootDialog);
|
|
}
|
|
}
|