|
@@ -36,8 +36,16 @@ import android.content.pm.ActivityInfo;
|
|
|
public class SDLActivity extends Activity {
|
|
|
private static final String TAG = "SDL";
|
|
|
|
|
|
- // Keep track of the paused state
|
|
|
- public static boolean mIsPaused, mIsSurfaceReady, mHasFocus;
|
|
|
+ public static boolean mIsResumedCalled, mIsSurfaceReady, mHasFocus;
|
|
|
+
|
|
|
+ // Handle the state of the native layer
|
|
|
+ public enum NativeState {
|
|
|
+ INIT, RESUMED, PAUSED
|
|
|
+ }
|
|
|
+
|
|
|
+ public static NativeState mNextNativeState;
|
|
|
+ public static NativeState mCurrentNativeState;
|
|
|
+
|
|
|
public static boolean mExitCalledFromJava;
|
|
|
|
|
|
/** If shared libraries (e.g. SDL or the native application) could not be loaded. */
|
|
@@ -110,9 +118,11 @@ public class SDLActivity extends Activity {
|
|
|
mAudioRecord = null;
|
|
|
mExitCalledFromJava = false;
|
|
|
mBrokenLibraries = false;
|
|
|
- mIsPaused = false;
|
|
|
+ mIsResumedCalled = false;
|
|
|
mIsSurfaceReady = false;
|
|
|
mHasFocus = true;
|
|
|
+ mNextNativeState = NativeState.INIT;
|
|
|
+ mCurrentNativeState = NativeState.INIT;
|
|
|
}
|
|
|
|
|
|
// Setup
|
|
@@ -195,24 +205,28 @@ public class SDLActivity extends Activity {
|
|
|
protected void onPause() {
|
|
|
Log.v(TAG, "onPause()");
|
|
|
super.onPause();
|
|
|
+ mNextNativeState = NativeState.PAUSED;
|
|
|
+ mIsResumedCalled = false;
|
|
|
|
|
|
if (SDLActivity.mBrokenLibraries) {
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
- SDLActivity.handlePause();
|
|
|
+ SDLActivity.handleNativeState();
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
protected void onResume() {
|
|
|
Log.v(TAG, "onResume()");
|
|
|
super.onResume();
|
|
|
+ mNextNativeState = NativeState.RESUMED;
|
|
|
+ mIsResumedCalled = true;
|
|
|
|
|
|
if (SDLActivity.mBrokenLibraries) {
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
- SDLActivity.handleResume();
|
|
|
+ SDLActivity.handleNativeState();
|
|
|
}
|
|
|
|
|
|
|
|
@@ -227,8 +241,12 @@ public class SDLActivity extends Activity {
|
|
|
|
|
|
SDLActivity.mHasFocus = hasFocus;
|
|
|
if (hasFocus) {
|
|
|
- SDLActivity.handleResume();
|
|
|
+ mNextNativeState = NativeState.RESUMED;
|
|
|
+ } else {
|
|
|
+ mNextNativeState = NativeState.PAUSED;
|
|
|
}
|
|
|
+
|
|
|
+ SDLActivity.handleNativeState();
|
|
|
}
|
|
|
|
|
|
@Override
|
|
@@ -247,6 +265,9 @@ public class SDLActivity extends Activity {
|
|
|
protected void onDestroy() {
|
|
|
Log.v(TAG, "onDestroy()");
|
|
|
|
|
|
+ mNextNativeState = NativeState.PAUSED;
|
|
|
+ SDLActivity.handleNativeState();
|
|
|
+
|
|
|
if (SDLActivity.mBrokenLibraries) {
|
|
|
super.onDestroy();
|
|
|
// Reset everything in case the user re opens the app
|
|
@@ -295,28 +316,68 @@ public class SDLActivity extends Activity {
|
|
|
return super.dispatchKeyEvent(event);
|
|
|
}
|
|
|
|
|
|
- /** Called by onPause or surfaceDestroyed. Even if surfaceDestroyed
|
|
|
- * is the first to be called, mIsSurfaceReady should still be set
|
|
|
- * to 'true' during the call to onPause (in a usual scenario).
|
|
|
- */
|
|
|
- public static void handlePause() {
|
|
|
- if (!SDLActivity.mIsPaused && SDLActivity.mIsSurfaceReady) {
|
|
|
- SDLActivity.mIsPaused = true;
|
|
|
- SDLActivity.nativePause();
|
|
|
- mSurface.handlePause();
|
|
|
+ /* Transition to next state */
|
|
|
+ public static void handleNativeState() {
|
|
|
+
|
|
|
+ if (mNextNativeState == mCurrentNativeState) {
|
|
|
+ // Already in same state, discard.
|
|
|
+ return;
|
|
|
}
|
|
|
- }
|
|
|
|
|
|
- /** Called by onResume or surfaceCreated. An actual resume should be done only when the surface is ready.
|
|
|
- * Note: Some Android variants may send multiple surfaceChanged events, so we don't need to resume
|
|
|
- * every time we get one of those events, only if it comes after surfaceDestroyed
|
|
|
- */
|
|
|
- public static void handleResume() {
|
|
|
- if (SDLActivity.mIsPaused && SDLActivity.mIsSurfaceReady && SDLActivity.mHasFocus) {
|
|
|
- SDLActivity.mIsPaused = false;
|
|
|
- SDLActivity.nativeResume();
|
|
|
- mSurface.handleResume();
|
|
|
+ // Try a transition to init state
|
|
|
+ if (mNextNativeState == NativeState.INIT) {
|
|
|
+
|
|
|
+ mCurrentNativeState = mNextNativeState;
|
|
|
+ return;
|
|
|
}
|
|
|
+
|
|
|
+ // Try a transition to paused state
|
|
|
+ if (mNextNativeState == NativeState.PAUSED) {
|
|
|
+ nativePause();
|
|
|
+ mSurface.handlePause();
|
|
|
+ mCurrentNativeState = mNextNativeState;
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // Try a transition to resumed state
|
|
|
+ if (mNextNativeState == NativeState.RESUMED) {
|
|
|
+
|
|
|
+ if (mIsSurfaceReady && mHasFocus && mIsResumedCalled) {
|
|
|
+
|
|
|
+ if (mSDLThread == null) {
|
|
|
+ // This is the entry point to the C app.
|
|
|
+ // Start up the C app thread and enable sensor input for the first time
|
|
|
+
|
|
|
+ final Thread sdlThread = new Thread(new SDLMain(), "SDLThread");
|
|
|
+ mSurface.enableSensor(Sensor.TYPE_ACCELEROMETER, true);
|
|
|
+ sdlThread.start();
|
|
|
+
|
|
|
+ // Set up a listener thread to catch when the native thread ends
|
|
|
+ mSDLThread = new Thread(new Runnable(){
|
|
|
+ @Override
|
|
|
+ public void run(){
|
|
|
+ try {
|
|
|
+ sdlThread.join();
|
|
|
+ }
|
|
|
+ catch(Exception e){}
|
|
|
+ finally{
|
|
|
+ // Native thread has finished
|
|
|
+ if (! mExitCalledFromJava) {
|
|
|
+ handleNativeExit();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }, "SDLThreadListener");
|
|
|
+ mSDLThread.start();
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ nativeResume();
|
|
|
+ mSurface.handleResume();
|
|
|
+ mCurrentNativeState = mNextNativeState;
|
|
|
+ }
|
|
|
+ return;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
/* The native thread has finished */
|
|
@@ -1099,8 +1160,11 @@ class SDLSurface extends SurfaceView implements SurfaceHolder.Callback,
|
|
|
@Override
|
|
|
public void surfaceDestroyed(SurfaceHolder holder) {
|
|
|
Log.v("SDL", "surfaceDestroyed()");
|
|
|
- // Call this *before* setting mIsSurfaceReady to 'false'
|
|
|
- SDLActivity.handlePause();
|
|
|
+
|
|
|
+ // Transition to pause, if needed
|
|
|
+ SDLActivity.mNextNativeState = SDLActivity.NativeState.PAUSED;
|
|
|
+ SDLActivity.handleNativeState();
|
|
|
+
|
|
|
SDLActivity.mIsSurfaceReady = false;
|
|
|
SDLActivity.onNativeSurfaceDestroyed();
|
|
|
}
|
|
@@ -1193,45 +1257,17 @@ class SDLSurface extends SurfaceView implements SurfaceHolder.Callback,
|
|
|
|
|
|
if (skip) {
|
|
|
Log.v("SDL", "Skip .. Surface is not ready.");
|
|
|
+ SDLActivity.mIsSurfaceReady = false;
|
|
|
return;
|
|
|
}
|
|
|
-
|
|
|
-
|
|
|
- // Set mIsSurfaceReady to 'true' *before* making a call to handleResume
|
|
|
+
|
|
|
+ /* Surface is ready */
|
|
|
SDLActivity.mIsSurfaceReady = true;
|
|
|
- SDLActivity.onNativeSurfaceChanged();
|
|
|
-
|
|
|
-
|
|
|
- if (SDLActivity.mSDLThread == null) {
|
|
|
- // This is the entry point to the C app.
|
|
|
- // Start up the C app thread and enable sensor input for the first time
|
|
|
-
|
|
|
- final Thread sdlThread = new Thread(new SDLMain(), "SDLThread");
|
|
|
- enableSensor(Sensor.TYPE_ACCELEROMETER, true);
|
|
|
- sdlThread.start();
|
|
|
|
|
|
- // Set up a listener thread to catch when the native thread ends
|
|
|
- SDLActivity.mSDLThread = new Thread(new Runnable(){
|
|
|
- @Override
|
|
|
- public void run(){
|
|
|
- try {
|
|
|
- sdlThread.join();
|
|
|
- }
|
|
|
- catch(Exception e){}
|
|
|
- finally{
|
|
|
- // Native thread has finished
|
|
|
- if (! SDLActivity.mExitCalledFromJava) {
|
|
|
- SDLActivity.handleNativeExit();
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- }, "SDLThreadListener");
|
|
|
- SDLActivity.mSDLThread.start();
|
|
|
- }
|
|
|
+ /* If the surface has been previously destroyed by onNativeSurfaceDestroyed, recreate it here */
|
|
|
+ SDLActivity.onNativeSurfaceChanged();
|
|
|
|
|
|
- if (SDLActivity.mHasFocus && !SDLActivity.mIsPaused) {
|
|
|
- SDLActivity.handleResume();
|
|
|
- }
|
|
|
+ SDLActivity.handleNativeState();
|
|
|
}
|
|
|
|
|
|
// Key events
|