mirror of
https://github.com/mauiaaron/apple2.git
synced 2024-12-26 15:29:19 +00:00
Refactor app startup
- Make sure crash checking is performed as early as possible - Minimize calling complex native functions until after splash screen is dimissed - Do not attempt to setup/resume OpenGL until after splash screen is dimissed
This commit is contained in:
parent
cbe8a734d0
commit
521d1daccf
@ -15,7 +15,6 @@ import android.app.Activity;
|
||||
import android.app.AlertDialog;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.graphics.Rect;
|
||||
import android.media.AudioManager;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
@ -25,7 +24,6 @@ import android.view.KeyEvent;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.ViewTreeObserver;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.Toast;
|
||||
|
||||
@ -51,9 +49,6 @@ public class Apple2Activity extends Activity {
|
||||
|
||||
private AtomicBoolean mPausing = new AtomicBoolean(false);
|
||||
|
||||
private int mWidth = 0;
|
||||
private int mHeight = 0;
|
||||
|
||||
private float[] mXCoords = new float[MAX_FINGERS];
|
||||
private float[] mYCoords = new float[MAX_FINGERS];
|
||||
|
||||
@ -88,17 +83,11 @@ public class Apple2Activity extends Activity {
|
||||
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 nativeGraphicsInitialized(int width, int height);
|
||||
|
||||
private native void nativeGraphicsChanged(int width, int height);
|
||||
|
||||
private native void nativeOnKeyDown(int keyCode, int metaState);
|
||||
|
||||
private native void nativeOnKeyUp(int keyCode, int metaState);
|
||||
|
||||
private native void nativeEmulationResume();
|
||||
public native void nativeEmulationResume();
|
||||
|
||||
public native void nativeEmulationPause();
|
||||
|
||||
@ -108,8 +97,6 @@ public class Apple2Activity extends Activity {
|
||||
|
||||
public native void nativeReboot();
|
||||
|
||||
public native void nativeRender();
|
||||
|
||||
public native void nativeChooseDisk(String path, boolean driveA, boolean readOnly);
|
||||
|
||||
public native void nativeEjectDisk(boolean driveA);
|
||||
@ -135,55 +122,36 @@ public class Apple2Activity extends Activity {
|
||||
|
||||
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);
|
||||
View view = new View(this);
|
||||
setContentView(view);
|
||||
return;
|
||||
}
|
||||
|
||||
// run first-time initializations
|
||||
showSplashScreen();
|
||||
Apple2CrashHandler.getInstance().checkForCrashes(Apple2Activity.this);
|
||||
|
||||
// first-time initializations #1
|
||||
if (!Apple2Preferences.FIRST_TIME_CONFIGURED.booleanValue(this)) {
|
||||
Apple2DisksMenu.firstTime(this);
|
||||
Apple2Preferences.KeypadPreset.IJKM_SPACE.apply(this);
|
||||
}
|
||||
Apple2Preferences.FIRST_TIME_CONFIGURED.saveBoolean(this, true);
|
||||
|
||||
// get device audio parameters for native OpenSLES
|
||||
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);
|
||||
|
||||
// NOTE: load preferences after nativeOnCreate ... native CPU thread should still be paused
|
||||
Apple2Preferences.loadPreferences(this);
|
||||
|
||||
mView = new Apple2View(this);
|
||||
setContentView(mView);
|
||||
|
||||
// Another Android Annoyance ...
|
||||
// Even though we no longer use the system soft keyboard (which would definitely trigger width/height changes to our OpenGL canvas),
|
||||
// we still need to listen to dimension changes, because it seems on some janky devices you have an incorrect width/height set when
|
||||
// the initial OpenGL onSurfaceChanged() callback occurs. For now, include this defensive coding...
|
||||
mView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
|
||||
public void onGlobalLayout() {
|
||||
Rect rect = new Rect();
|
||||
mView.getWindowVisibleDisplayFrame(rect);
|
||||
int h = rect.height();
|
||||
int w = rect.width();
|
||||
if (w < h) {
|
||||
// assure landscape dimensions
|
||||
final int w_ = w;
|
||||
w = h;
|
||||
h = w_;
|
||||
}
|
||||
nativeGraphicsChanged(w, h);
|
||||
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
|
||||
@ -195,7 +163,7 @@ public class Apple2Activity extends Activity {
|
||||
}
|
||||
|
||||
Log.d(TAG, "onResume()");
|
||||
mView.onResume();
|
||||
showSplashScreen();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -211,7 +179,9 @@ public class Apple2Activity extends Activity {
|
||||
}
|
||||
|
||||
Log.d(TAG, "onPause()");
|
||||
mView.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
|
||||
@ -354,40 +324,6 @@ public class Apple2Activity extends Activity {
|
||||
return super.onTouchEvent(event);
|
||||
}
|
||||
|
||||
void graphicsInitialized(int w, int h) {
|
||||
Log.v(TAG, "graphicsInitialized(" + w + ", " + h + ")");
|
||||
|
||||
if (mMainMenu == null) {
|
||||
mMainMenu = new Apple2MainMenu(this, mView);
|
||||
}
|
||||
|
||||
if (w < h) {
|
||||
// assure landscape dimensions
|
||||
final int w_ = w;
|
||||
w = h;
|
||||
h = w_;
|
||||
}
|
||||
|
||||
mWidth = w;
|
||||
mHeight = h;
|
||||
|
||||
nativeGraphicsInitialized(w, h);
|
||||
|
||||
showSplashScreen();
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
public void showMainMenu() {
|
||||
if (mMainMenu != null) {
|
||||
Apple2SettingsMenu settingsMenu = mMainMenu.getSettingsMenu();
|
||||
@ -456,18 +392,28 @@ public class Apple2Activity extends Activity {
|
||||
});
|
||||
}
|
||||
|
||||
private synchronized void showSplashScreen() {
|
||||
private void showSplashScreen() {
|
||||
if (mSplashScreen != null) {
|
||||
return;
|
||||
}
|
||||
mSplashScreen = new Apple2SplashScreen(Apple2Activity.this);
|
||||
runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
mSplashScreen.show();
|
||||
Apple2CrashHandler.getInstance().checkForCrashes(Apple2Activity.this);
|
||||
}
|
||||
});
|
||||
mSplashScreen.show();
|
||||
}
|
||||
|
||||
private void setupGLView() {
|
||||
|
||||
boolean glViewFirstTime = false;
|
||||
if (mView == null) {
|
||||
glViewFirstTime = true;
|
||||
mView = new Apple2View(this);
|
||||
mMainMenu = new Apple2MainMenu(this, mView);
|
||||
}
|
||||
|
||||
setContentView(mView);
|
||||
|
||||
if (!glViewFirstTime) {
|
||||
mView.onResume();
|
||||
}
|
||||
}
|
||||
|
||||
public void registerAndShowDialog(AlertDialog dialog) {
|
||||
@ -479,7 +425,7 @@ public class Apple2Activity extends Activity {
|
||||
mMenuStack.add(apple2MenuView);
|
||||
View menuView = apple2MenuView.getView();
|
||||
nativeEmulationPause();
|
||||
addContentView(menuView, new FrameLayout.LayoutParams(mWidth, mHeight));
|
||||
addContentView(menuView, new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT));
|
||||
}
|
||||
|
||||
public synchronized Apple2MenuView popApple2View() {
|
||||
@ -543,6 +489,8 @@ public class Apple2Activity extends Activity {
|
||||
|
||||
private void _disposeApple2View(Apple2MenuView apple2MenuView) {
|
||||
|
||||
boolean dismissedSplashScreen = false;
|
||||
|
||||
// Actually remove View from view hierarchy
|
||||
{
|
||||
View menuView = apple2MenuView.getView();
|
||||
@ -552,15 +500,19 @@ public class Apple2Activity extends Activity {
|
||||
}
|
||||
if (apple2MenuView == mSplashScreen) {
|
||||
mSplashScreen = null;
|
||||
dismissedSplashScreen = true;
|
||||
}
|
||||
}
|
||||
|
||||
// if no more views on menu stack, resume emulation
|
||||
if (mMenuStack.size() == 0) {
|
||||
dismissAllMenus();
|
||||
if (!mPausing.get()) {
|
||||
nativeEmulationResume();
|
||||
}
|
||||
}
|
||||
if (mMenuStack.size() == 0 && !mPausing.get()) {
|
||||
nativeEmulationResume();
|
||||
if (!mPausing.get() && dismissedSplashScreen) {
|
||||
setupGLView();
|
||||
}
|
||||
}
|
||||
|
||||
@ -570,8 +522,12 @@ public class Apple2Activity extends Activity {
|
||||
}
|
||||
}
|
||||
|
||||
public Apple2View getView() {
|
||||
return mView;
|
||||
public boolean isPausing() {
|
||||
return mPausing.get();
|
||||
}
|
||||
|
||||
public int menuStackSize() {
|
||||
return mMenuStack.size();
|
||||
}
|
||||
|
||||
public void maybeQuitApp() {
|
||||
|
@ -16,9 +16,11 @@
|
||||
package org.deadc0de.apple2ix;
|
||||
|
||||
import android.graphics.PixelFormat;
|
||||
import android.graphics.Rect;
|
||||
import android.opengl.GLES20;
|
||||
import android.opengl.GLSurfaceView;
|
||||
import android.util.Log;
|
||||
import android.view.ViewTreeObserver;
|
||||
|
||||
import javax.microedition.khronos.egl.EGL10;
|
||||
import javax.microedition.khronos.egl.EGLConfig;
|
||||
@ -50,13 +52,17 @@ class Apple2View extends GLSurfaceView {
|
||||
|
||||
private Apple2Activity mActivity = null;
|
||||
|
||||
private static native void nativeOnCreate(String dataDir, int sampleRate, int monoBufferSize, int stereoBufferSize);
|
||||
|
||||
private static native void nativeGraphicsInitialized(int width, int height);
|
||||
|
||||
private static native void nativeGraphicsChanged(int width, int height);
|
||||
|
||||
private static native void nativeRender();
|
||||
|
||||
public Apple2View(Apple2Activity activity) {
|
||||
super(activity.getApplication());
|
||||
mActivity = activity;
|
||||
setup(0, 0);
|
||||
}
|
||||
|
||||
private void setup(int depth, int stencil) {
|
||||
|
||||
/* By default, GLSurfaceView() creates a RGB_565 opaque surface.
|
||||
* If we want a translucent one, we should change the surface's
|
||||
@ -75,14 +81,36 @@ class Apple2View extends GLSurfaceView {
|
||||
* custom config chooser. See ConfigChooser class definition
|
||||
* below.
|
||||
*/
|
||||
setEGLConfigChooser(new ConfigChooser(8, 8, 8, 8, depth, stencil));
|
||||
setEGLConfigChooser(new ConfigChooser(8, 8, 8, 8, /*depth:*/0, /*stencil:*/0));
|
||||
|
||||
/* Set the renderer responsible for frame rendering */
|
||||
setRenderer(new Renderer());
|
||||
|
||||
// Another Android Annoyance ...
|
||||
// Even though we no longer use the system soft keyboard (which would definitely trigger width/height changes to our OpenGL canvas),
|
||||
// we still need to listen to dimension changes, because it seems on some janky devices you have an incorrect width/height set when
|
||||
// the initial OpenGL onSurfaceChanged() callback occurs. For now, include this defensive coding...
|
||||
getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
|
||||
public void onGlobalLayout() {
|
||||
Rect rect = new Rect();
|
||||
Apple2View.this.getWindowVisibleDisplayFrame(rect);
|
||||
int h = rect.height();
|
||||
int w = rect.width();
|
||||
if (w < h) {
|
||||
// assure landscape dimensions
|
||||
final int w_ = w;
|
||||
w = h;
|
||||
h = w_;
|
||||
}
|
||||
nativeGraphicsChanged(w, h);
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
private static class ContextFactory implements GLSurfaceView.EGLContextFactory {
|
||||
private static int EGL_CONTEXT_CLIENT_VERSION = 0x3098;
|
||||
|
||||
public EGLContext createContext(EGL10 egl, EGLDisplay display, EGLConfig eglConfig) {
|
||||
Log.w(TAG, "creating OpenGL ES 2.0 context");
|
||||
checkEglError("Before eglCreateContext", egl);
|
||||
@ -295,17 +323,49 @@ class Apple2View extends GLSurfaceView {
|
||||
}
|
||||
|
||||
private class Renderer implements GLSurfaceView.Renderer {
|
||||
|
||||
@Override
|
||||
public void onDrawFrame(GL10 gl) {
|
||||
Apple2View.this.mActivity.nativeRender();
|
||||
nativeRender();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSurfaceChanged(GL10 gl, int width, int height) {
|
||||
Apple2Preferences.GL_VENDOR.saveString(mActivity, GLES20.glGetString(GLES20.GL_VENDOR));
|
||||
Apple2Preferences.GL_RENDERER.saveString(mActivity, GLES20.glGetString(GLES20.GL_RENDERER));
|
||||
Apple2Preferences.GL_VERSION.saveString(mActivity, GLES20.glGetString(GLES20.GL_VERSION));
|
||||
Apple2View.this.mActivity.graphicsInitialized(width, height);
|
||||
|
||||
Log.v(TAG, "graphicsInitialized(" + width + ", " + height + ")");
|
||||
|
||||
if (width < height) {
|
||||
// assure landscape dimensions
|
||||
final int w_ = width;
|
||||
width = height;
|
||||
height = w_;
|
||||
}
|
||||
|
||||
int sampleRate = DevicePropertyCalculator.getRecommendedSampleRate(Apple2View.this.mActivity);
|
||||
int monoBufferSize = DevicePropertyCalculator.getRecommendedBufferSize(Apple2View.this.mActivity, /*isStereo:*/false);
|
||||
int stereoBufferSize = DevicePropertyCalculator.getRecommendedBufferSize(Apple2View.this.mActivity, /*isStereo:*/true);
|
||||
Log.d(TAG, "Device sampleRate:" + sampleRate + " mono bufferSize:" + monoBufferSize + " stereo bufferSize:" + stereoBufferSize);
|
||||
|
||||
String dataDir = Apple2DisksMenu.getDataDir(Apple2View.this.mActivity);
|
||||
nativeOnCreate(dataDir, sampleRate, monoBufferSize, stereoBufferSize);
|
||||
nativeGraphicsInitialized(width, height);
|
||||
|
||||
// first-time initializations #2
|
||||
if (!Apple2Preferences.FIRST_TIME_CONFIGURED.booleanValue(Apple2View.this.mActivity)) {
|
||||
Apple2Preferences.KeypadPreset.IJKM_SPACE.apply(Apple2View.this.mActivity);
|
||||
Apple2Preferences.FIRST_TIME_CONFIGURED.saveBoolean(Apple2View.this.mActivity, true);
|
||||
}
|
||||
Apple2Preferences.loadPreferences(Apple2View.this.mActivity);
|
||||
|
||||
if ((Apple2View.this.mActivity.menuStackSize() == 0) && !Apple2View.this.mActivity.isPausing()) {
|
||||
Apple2View.this.mActivity.nativeEmulationResume();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
|
||||
// Do nothing.
|
||||
}
|
||||
|
@ -99,7 +99,7 @@ static inline int _androidTouchEvent2InterfaceEvent(jint action) {
|
||||
// ----------------------------------------------------------------------------
|
||||
// JNI functions
|
||||
|
||||
void Java_org_deadc0de_apple2ix_Apple2Activity_nativeOnCreate(JNIEnv *env, jobject obj, jstring j_dataDir, jint sampleRate, jint monoBufferSize, jint stereoBufferSize) {
|
||||
void Java_org_deadc0de_apple2ix_Apple2View_nativeOnCreate(JNIEnv *env, jclass cls, jstring j_dataDir, jint sampleRate, jint monoBufferSize, jint stereoBufferSize) {
|
||||
const char *dataDir = (*env)->GetStringUTFChars(env, j_dataDir, 0);
|
||||
|
||||
// Android lifecycle can call onCreate() multiple times...
|
||||
@ -135,14 +135,15 @@ void Java_org_deadc0de_apple2ix_Apple2Activity_nativeOnCreate(JNIEnv *env, jobje
|
||||
#endif
|
||||
}
|
||||
|
||||
void Java_org_deadc0de_apple2ix_Apple2Activity_nativeGraphicsChanged(JNIEnv *env, jobject obj, jint width, jint height) {
|
||||
void Java_org_deadc0de_apple2ix_Apple2View_nativeGraphicsChanged(JNIEnv *env, jclass cls, jint width, jint height) {
|
||||
// WARNING : this can happen on non-GL thread
|
||||
LOG("...");
|
||||
video_backend->reshape(width, height);
|
||||
}
|
||||
|
||||
void Java_org_deadc0de_apple2ix_Apple2Activity_nativeGraphicsInitialized(JNIEnv *env, jobject obj, jint width, jint height) {
|
||||
void Java_org_deadc0de_apple2ix_Apple2View_nativeGraphicsInitialized(JNIEnv *env, jclass cls, jint width, jint height) {
|
||||
// WANRING : this needs to happen on the GL thread only
|
||||
LOG("width:%d height:%d", width, height);
|
||||
|
||||
video_shutdown();
|
||||
video_backend->reshape(width, height);
|
||||
video_backend->init((void *)0);
|
||||
@ -176,7 +177,7 @@ void Java_org_deadc0de_apple2ix_Apple2Activity_nativeEmulationPause(JNIEnv *env,
|
||||
#endif
|
||||
}
|
||||
|
||||
void Java_org_deadc0de_apple2ix_Apple2Activity_nativeRender(JNIEnv *env, jobject obj) {
|
||||
void Java_org_deadc0de_apple2ix_Apple2View_nativeRender(JNIEnv *env, jclass cls) {
|
||||
SCOPE_TRACE_VIDEO("nativeRender");
|
||||
|
||||
if (UNLIKELY(appState != APP_RUNNING)) {
|
||||
|
Loading…
Reference in New Issue
Block a user