From 9950271bb6a1ed51b7c4df09df64d6c007c7045a Mon Sep 17 00:00:00 2001 From: Sam Lantinga Date: Mon, 22 Apr 2019 16:19:52 -0700 Subject: [PATCH] Fixed bug 4580 - Android 8: immersive fullscreen notification causes flickering between fullscreen and non-fullscreen and app is unresponsive Sylvain 2019-04-18 21:22:59 UTC Changes: - SDL_WINDOWEVENT_FOCUS_GAINED and SDL_WINDOWEVENT_FOCUS_LOST are sent when the java method onWindowFocusChanged() is called. - If we have support for MultiWindow (eg API >= 24), SDL event loop is blocked/un-blocked (or simply egl-backed-up or not), when java onStart()/onStop() are called. - If not, this behaves like now, SDL event loop is blocked/un-blocked when onPause()/onResume() are called. So if we have two app on screen and switch from one to the other, only FOCUS events are sent (and onPause()/onResume() are called but empty. onStart()/onStop() are not called). The SDL app, un-focused, would still continue to run and display frames (currently the App would be displayed, but paused). Like a video player app or a chronometer that would still be refreshed, even if the window hasn't the focus. It should work also on ChromeBooks (not tested), with two apps opened at the same time. I am not sure this fix Dan's issue. Because focus lost event triggers Minimize function (which BTW is not provided on android). https://hg.libsdl.org/SDL/file/bb41b3635c34/src/video/SDL_video.c#l2653 https://hg.libsdl.org/SDL/file/bb41b3635c34/src/video/SDL_video.c#l2634 So, in addition, it would need to add by default SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS to 0. So that the lost focus event doesn't try to minimize the window. And this should fix also the issue. --- .../main/java/org/libsdl/app/SDLActivity.java | 66 +++++++++++++++---- src/core/android/SDL_android.c | 18 ++++- 2 files changed, 68 insertions(+), 16 deletions(-) diff --git a/android-project/app/src/main/java/org/libsdl/app/SDLActivity.java b/android-project/app/src/main/java/org/libsdl/app/SDLActivity.java index 420acd7a342eb..5e5eb04a3c053 100644 --- a/android-project/app/src/main/java/org/libsdl/app/SDLActivity.java +++ b/android-project/app/src/main/java/org/libsdl/app/SDLActivity.java @@ -38,6 +38,7 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh private static final String TAG = "SDL"; public static boolean mIsResumedCalled, mHasFocus; + public static final boolean mHasMultiWindow = (Build.VERSION.SDK_INT >= 24); // Cursor types private static final int SDL_SYSTEM_CURSOR_NONE = -1; @@ -274,16 +275,12 @@ public void onClick(DialogInterface dialog,int id) { } } - // Events - @Override - protected void onPause() { - Log.v(TAG, "onPause()"); - super.onPause(); + protected void pauseNativeThread() { mNextNativeState = NativeState.PAUSED; mIsResumedCalled = false; if (SDLActivity.mBrokenLibraries) { - return; + return; } if (mHIDDeviceManager != null) { @@ -293,10 +290,7 @@ protected void onPause() { SDLActivity.handleNativeState(); } - @Override - protected void onResume() { - Log.v(TAG, "onResume()"); - super.onResume(); + protected void resumeNativeThread() { mNextNativeState = NativeState.RESUMED; mIsResumedCalled = true; @@ -311,6 +305,43 @@ protected void onResume() { SDLActivity.handleNativeState(); } + // Events + @Override + protected void onPause() { + Log.v(TAG, "onPause()"); + super.onPause(); + if (!mHasMultiWindow) { + pauseNativeThread(); + } + } + + @Override + protected void onResume() { + Log.v(TAG, "onResume()"); + super.onResume(); + if (!mHasMultiWindow) { + resumeNativeThread(); + } + } + + @Override + protected void onStop() { + Log.v(TAG, "onStop()"); + super.onStop(); + if (mHasMultiWindow) { + pauseNativeThread(); + } + } + + @Override + protected void onStart() { + Log.v(TAG, "onStart()"); + super.onStart(); + if (mHasMultiWindow) { + resumeNativeThread(); + } + } + public static int getCurrentOrientation() { final Context context = SDLActivity.getContext(); final Display display = ((WindowManager) context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay(); @@ -347,15 +378,21 @@ public void onWindowFocusChanged(boolean hasFocus) { return; } - SDLActivity.mHasFocus = hasFocus; + mHasFocus = hasFocus; if (hasFocus) { mNextNativeState = NativeState.RESUMED; SDLActivity.getMotionListener().reclaimRelativeMouseModeIfNeeded(); + + SDLActivity.handleNativeState(); + nativeFocusChanged(true); + } else { - mNextNativeState = NativeState.PAUSED; + nativeFocusChanged(false); + if (!mHasMultiWindow) { + mNextNativeState = NativeState.PAUSED; + SDLActivity.handleNativeState(); + } } - - SDLActivity.handleNativeState(); } @Override @@ -719,6 +756,7 @@ boolean sendCommand(int command, Object data) { public static native void nativeQuit(); public static native void nativePause(); public static native void nativeResume(); + public static native void nativeFocusChanged(boolean hasFocus); public static native void onNativeDropFile(String filename); public static native void nativeSetScreenResolution(int surfaceWidth, int surfaceHeight, int deviceWidth, int deviceHeight, int format, float rate); public static native void onNativeResize(); diff --git a/src/core/android/SDL_android.c b/src/core/android/SDL_android.c index fe0af2675f685..2e7240d2971ee 100644 --- a/src/core/android/SDL_android.c +++ b/src/core/android/SDL_android.c @@ -131,6 +131,9 @@ JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(nativePause)( JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(nativeResume)( JNIEnv *env, jclass cls); +JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(nativeFocusChanged)( + JNIEnv *env, jclass cls, jboolean hasFocus); + JNIEXPORT jstring JNICALL SDL_JAVA_INTERFACE(nativeGetHint)( JNIEnv *env, jclass cls, jstring name); @@ -1034,7 +1037,6 @@ JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(nativePause)( __android_log_print(ANDROID_LOG_VERBOSE, "SDL", "nativePause()"); if (Android_Window) { - SDL_SendWindowEvent(Android_Window, SDL_WINDOWEVENT_FOCUS_LOST, 0, 0); SDL_SendWindowEvent(Android_Window, SDL_WINDOWEVENT_MINIMIZED, 0, 0); SDL_SendAppEvent(SDL_APP_WILLENTERBACKGROUND); SDL_SendAppEvent(SDL_APP_DIDENTERBACKGROUND); @@ -1060,7 +1062,6 @@ JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(nativeResume)( if (Android_Window) { SDL_SendAppEvent(SDL_APP_WILLENTERFOREGROUND); SDL_SendAppEvent(SDL_APP_DIDENTERFOREGROUND); - SDL_SendWindowEvent(Android_Window, SDL_WINDOWEVENT_FOCUS_GAINED, 0, 0); SDL_SendWindowEvent(Android_Window, SDL_WINDOWEVENT_RESTORED, 0, 0); } @@ -1073,6 +1074,19 @@ JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(nativeResume)( SDL_UnlockMutex(Android_ActivityMutex); } +JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(nativeFocusChanged)( + JNIEnv *env, jclass cls, jboolean hasFocus) +{ + SDL_LockMutex(Android_ActivityMutex); + + if (Android_Window) { + __android_log_print(ANDROID_LOG_VERBOSE, "SDL", "nativeFocusChanged()"); + SDL_SendWindowEvent(Android_Window, (hasFocus ? SDL_WINDOWEVENT_FOCUS_GAINED : SDL_WINDOWEVENT_FOCUS_LOST), 0, 0); + } + + SDL_UnlockMutex(Android_ActivityMutex); +} + JNIEXPORT void JNICALL SDL_JAVA_INTERFACE_INPUT_CONNECTION(nativeCommitText)( JNIEnv *env, jclass cls, jstring text, jint newCursorPosition)