diff --git a/android-project/src/org/libsdl/app/SDLActivity.java b/android-project/src/org/libsdl/app/SDLActivity.java index a49184b42..8fbbd7832 100644 --- a/android-project/src/org/libsdl/app/SDLActivity.java +++ b/android-project/src/org/libsdl/app/SDLActivity.java @@ -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() { - /** 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(); + if (mNextNativeState == mCurrentNativeState) { + // Already in same state, discard. + return; } + + // 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; + + /* If the surface has been previously destroyed by onNativeSurfaceDestroyed, recreate it here */ 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 (SDLActivity.mHasFocus && !SDLActivity.mIsPaused) { - SDLActivity.handleResume(); - } + SDLActivity.handleNativeState(); } // Key events