We are currently migrating Bugzilla to GitHub issues.
Any changes made to the bug tracker now will be lost, so please do not post new bugs or make changes to them.
When we're done, all bug URLs will redirect to their equivalent location on the new bug tracker.

Bug 4580 - Android 8: immersive fullscreen notification causes flickering between fullscreen and non-fullscreen and app is unresponsive
Summary: Android 8: immersive fullscreen notification causes flickering between fullsc...
Status: ASSIGNED
Alias: None
Product: SDL
Classification: Unclassified
Component: video (show other bugs)
Version: HG 2.1
Hardware: ARM Android (All)
: P2 normal
Assignee: Sam Lantinga
QA Contact: Sam Lantinga
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2019-04-04 21:02 UTC by Dan Ginsburg
Modified: 2019-06-11 13:22 UTC (History)
4 users (show)

See Also:


Attachments
patch (3.95 KB, patch)
2019-04-06 13:35 UTC, Sylvain
Details | Diff
patch 2 (multi-window) (5.53 KB, patch)
2019-04-18 21:22 UTC, Sylvain
Details | Diff
patch MinimizeWindow (7.10 KB, patch)
2019-04-23 19:54 UTC, Sylvain
Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Dan Ginsburg 2019-04-04 21:02:38 UTC
I am testing an SDL app on Android 8 (Sony Xperia XZ Premium) and ran into a bug that happens when the System.Settings.IMMERSIVE_MODE_CONFIRMATIONS comes up.  Basically, when that notification comes up, the app is toggled out of fullscreen making the system UI visible.  Shortly thereafter, the app toggles itself back to fullscreen hiding the system UI.  

Here's my triaging of the bug.  To review, on Android there is a security setting for immersive fullscreen apps that forces the user to acknowledge this message once.  It can be reset in adb shell with:

$ settings put secure immersive_mode_confirmations 0

What is happening is that in SDLActivity.java it is constantly getting messages toggling it in and out of fullscreen state.  This causes the app to show/hide the system menu on each toggle:

    case COMMAND_CHANGE_WINDOW_STYLE:
                if (Build.VERSION.SDK_INT < 19) {
                    // This version of Android doesn't support the immersive fullscreen mode
                    break;
                }
                if (context instanceof Activity) {
                    Window window = ((Activity) context).getWindow();
                    if (window != null) {
                        if ((msg.obj instanceof Integer) && (((Integer) msg.obj).intValue() != 0)) {
                            int flags = View.SYSTEM_UI_FLAG_FULLSCREEN |
                                        View.SYSTEM_UI_FLAG_HIDE_NAVIGATION |
                                        View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY |
                                        View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN |
                                        View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION |
                                        View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.INVISIBLE;
                            window.getDecorView().setSystemUiVisibility(flags);
                            window.addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
                            window.clearFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
                            SDLActivity.mFullscreenModeActive = true;
                        } else {
                            int flags = View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_VISIBLE;
                            window.getDecorView().setSystemUiVisibility(flags);
                            window.addFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
                            window.clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
                            SDLActivity.mFullscreenModeActive = false;
                        }
                    }
                } else {
                    Log.e(TAG, "error handling message, getContext() returned no Activity");
                }
                break;

One thing that fixes the symptoms of the bug is if I remove the code to setSystemUiVisibilityFlags in the else case there.  But digging further, I tried to figure out why is it that we’re getting the message to toggle out of fullscreen.  The reason is because when that Android fullscreen warning pops up we’re getting an onPause invocation from Android.

    protected void onPause() {
        Log.v(TAG, "onPause()");
        super.onPause();
        mNextNativeState = NativeState.PAUSED;
        mIsResumedCalled = false;

        if (SDLActivity.mBrokenLibraries) {
           return;
        }

        if (mHIDDeviceManager != null) {
            mHIDDeviceManager.setFrozen(true);
        }

        SDLActivity.handleNativeState();
    }

..which ends up calling nativePause.  Back over in the native code, we end up with this callstack which is setting fullscreen = false. 


libSDL2.so!Android_JNI_SetWindowStyle(SDL_bool fullscreen) Line 1257      C
             libSDL2.so!Android_SetWindowFullscreen(SDL_VideoDevice * _this, SDL_Window * window, SDL_VideoDisplay * display, SDL_bool fullscreen) Line 122              C
             libSDL2.so!SDL_UpdateFullscreenMode(SDL_Window * window, SDL_bool fullscreen) Line 1333  C
             libSDL2.so!SDL_MinimizeWindow_REAL(SDL_Window * window) Line 2219      C
>            libSDL2.so!SDL_SendWindowEvent(SDL_Window * window, Uint8 windowevent, int data1, int data2) Line 174       C
             libSDL2.so!Java_org_libsdl_app_SDLActivity_nativePause(JNIEnv * env, jclass cls) Line 1046              C
             [Unknown/Just-In-Time compiled code]              

What’s triggering the fullscreen toggle is the SDL_WINDOWEVENT_MINIMIZED message which calls SDL_MinimizeWindow which then toggles the fullscreen state to off.

NIEXPORT void JNICALL SDL_JAVA_INTERFACE(nativePause)(
                                    JNIEnv *env, jclass cls)
{
    SDL_LockMutex(Android_ActivityMutex);

    __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);
    }

    /* *After* sending the relevant events, signal the pause semaphore
     * so the event loop knows to pause and (optionally) block itself.
     * Sometimes 2 pauses can be queued (eg pause/resume/pause), so it's
     * always increased. */
    SDL_SemPost(Android_PauseSem);

    SDL_UnlockMutex(Android_ActivityMutex);
}


One possible idea I have is that we are misinterpreting onPause to mean something that it doesn't.  From what I've read, there is a difference between onPause and onStop.  In the case of this message, we get an onPause to notify us that we no longer have focus, but we are not minimized.  In the case we would be minimized, we would also get onStop.

I wonder if maybe a solution here is to only send SDL_WINDOWEVENT_FOCUS_LOST in onPause and have a separate nativeStop that sends the SDL_WINDOWEVENT_MINIMIZED?
Comment 1 Sam Lantinga 2019-04-04 21:08:00 UTC
Sylvain, can you look at this?

I think he's correct that onPause() doesn't necessarily mean minimized, especially in multi-window environments like ChromeOS.
Comment 2 Sylvain 2019-04-05 07:42:26 UTC
I'll really try next week I think.
But in the meantimes: 
- how can we simulate/trigger such notifications ? 

during those notifications, you only Pause/Resume and no Stop/Restart (you have to add and log them in SDLActivity )?

Is that working if you comment out "SDL_SendWindowEvent(Android_Window, SDL_WINDOWEVENT_MINIMIZED, 0, 0);" in src/core/android/SDL_android.c ?
Comment 3 Dan Ginsburg 2019-04-05 14:32:46 UTC
(In reply to Sylvain from comment #2)
> - how can we simulate/trigger such notifications ? 

Before launching a fullscreen immersive SDL app, run this command in adb shell:

$ settings put secure immersive_mode_confirmations 0

That resets the system setting that determines whether the user has ever confirmed the notification before.

> 
> during those notifications, you only Pause/Resume and no Stop/Restart (you
> have to add and log them in SDLActivity )?
> 

That is correct.  I added onStop/onRestart logging and this is what the sequence of events looks like as it flickers in and out:

04-05 10:28:34.205 12238 12238 V SDL     : Device: G8142
04-05 10:28:34.205 12238 12238 V SDL     : Model: G8142
04-05 10:28:34.205 12238 12238 V SDL     : onCreate()
04-05 10:28:34.206 12238 12238 V SDL     : nativeSetupJNI()
04-05 10:28:34.206 12238 12238 V SDL     : AUDIO nativeSetupJNI()
04-05 10:28:34.206 12238 12238 V SDL     : CONTROLLER nativeSetupJNI()
04-05 10:28:34.221 12238 12238 V SDL     : onResume()
04-05 10:28:34.264 12238 12238 V SDL     : surfaceCreated()
04-05 10:28:34.264 12238 12238 V SDL     : surfaceChanged()
04-05 10:28:34.264 12238 12238 V SDL     : pixel format RGB_565
04-05 10:28:34.265 12238 12238 V SDL     : Window size: 1776x1008
04-05 10:28:34.265 12238 12238 V SDL     : Device size: 1920x1080
04-05 10:28:34.271 12238 12280 V SDL     : Running main function SDL_main from library [removed]
04-05 10:28:34.271 12238 12280 V SDL     : nativeRunMain()
04-05 10:28:34.272 12238 12238 V SDL     : onWindowFocusChanged(): true
04-05 10:28:35.419 12238 12307 V SDL     : setOrientation() orientation=6 width=1 height=1 resizable=false hint=LandscapeLeft LandscapeRight
04-05 10:28:35.431 12238 12238 V SDL     : surfaceDestroyed()
04-05 10:28:35.431 12238 12238 V SDL     : nativePause()
04-05 10:28:35.435 12238 12238 V SDL     : surfaceCreated()
04-05 10:28:35.435 12238 12238 V SDL     : surfaceChanged()
04-05 10:28:35.435 12238 12238 V SDL     : pixel format RGBA_8888
04-05 10:28:35.436 12238 12238 V SDL     : Window size: 1776x1008
04-05 10:28:35.436 12238 12238 V SDL     : Device size: 1920x1080
04-05 10:28:35.438 12238 12238 V SDL     : nativeResume()
04-05 10:28:35.458 12238 12280 V SDL     : setOrientation() orientation=6 width=1920 height=1080 resizable=false hint=LandscapeLeft LandscapeRight
04-05 10:28:35.504 12238 12238 V SDL     : surfaceChanged()
04-05 10:28:35.504 12238 12238 V SDL     : pixel format RGBA_8888
04-05 10:28:35.504 12238 12238 V SDL     : Window size: 1920x1080
04-05 10:28:35.504 12238 12238 V SDL     : Device size: 1920x1080
04-05 10:28:36.313 12238 12238 V SDL     : onWindowFocusChanged(): false
04-05 10:28:36.313 12238 12238 V SDL     : nativePause()
04-05 10:28:36.890 12238 12238 V SDL     : surfaceChanged()
04-05 10:28:36.890 12238 12238 V SDL     : pixel format RGBA_8888
04-05 10:28:36.891 12238 12238 V SDL     : Window size: 1776x1008
04-05 10:28:36.891 12238 12238 V SDL     : Device size: 1920x1080
04-05 10:28:36.899 12238 12238 V SDL     : onWindowFocusChanged(): true
04-05 10:28:36.899 12238 12238 V SDL     : nativeResume()
04-05 10:28:37.468 12238 12238 V SDL     : surfaceChanged()
04-05 10:28:37.468 12238 12238 V SDL     : pixel format RGBA_8888
04-05 10:28:37.469 12238 12238 V SDL     : Window size: 1920x1080
04-05 10:28:37.469 12238 12238 V SDL     : Device size: 1920x1080

04-05 10:28:38.258 12238 12238 V SDL     : onWindowFocusChanged(): false
04-05 10:28:38.258 12238 12238 V SDL     : nativePause()
04-05 10:28:38.839 12238 12238 V SDL     : surfaceChanged()
04-05 10:28:38.839 12238 12238 V SDL     : pixel format RGBA_8888
04-05 10:28:38.840 12238 12238 V SDL     : Window size: 1776x1008
04-05 10:28:38.840 12238 12238 V SDL     : Device size: 1920x1080
04-05 10:28:38.851 12238 12238 V SDL     : onWindowFocusChanged(): true
04-05 10:28:38.851 12238 12238 V SDL     : nativeResume()
04-05 10:28:38.920 12238 12280 V SDL     : SDL audio: opening device for output
04-05 10:28:39.417 12238 12238 V SDL     : surfaceChanged()
04-05 10:28:39.417 12238 12238 V SDL     : pixel format RGBA_8888
04-05 10:28:39.417 12238 12238 V SDL     : Window size: 1920x1080
04-05 10:28:39.417 12238 12238 V SDL     : Device size: 1920x1080
04-05 10:28:40.189 12238 12238 V SDL     : onWindowFocusChanged(): false
04-05 10:28:40.189 12238 12238 V SDL     : nativePause()
04-05 10:28:40.754 12238 12238 V SDL     : surfaceChanged()
04-05 10:28:40.754 12238 12238 V SDL     : pixel format RGBA_8888
04-05 10:28:40.755 12238 12238 V SDL     : Window size: 1776x1008
04-05 10:28:40.755 12238 12238 V SDL     : Device size: 1920x1080
04-05 10:28:40.764 12238 12238 V SDL     : onWindowFocusChanged(): true
04-05 10:28:40.764 12238 12238 V SDL     : nativeResume()
04-05 10:28:41.348 12238 12238 V SDL     : surfaceChanged()
04-05 10:28:41.348 12238 12238 V SDL     : pixel format RGBA_8888
04-05 10:28:41.349 12238 12238 V SDL     : Window size: 1920x1080
04-05 10:28:41.349 12238 12238 V SDL     : Device size: 1920x1080
04-05 10:28:42.133 12238 12238 V SDL     : onWindowFocusChanged(): false
04-05 10:28:42.133 12238 12238 V SDL     : nativePause()

When I finally exit the app, I do see my message:

04-05 10:28:47.972 12238 12238 V SDL     : surfaceChanged()
04-05 10:28:47.972 12238 12238 V SDL     : pixel format RGBA_8888
04-05 10:28:47.973 12238 12238 V SDL     : Window size: 1080x1704
04-05 10:28:47.973 12238 12238 V SDL     : Device size: 1080x1920
04-05 10:28:47.974 12238 12238 V SDL     : Skip .. Surface is not ready.
04-05 10:28:47.984 12238 12238 V SDL     : onWindowFocusChanged(): false
04-05 10:28:47.998 12238 12238 V SDL     : surfaceDestroyed()
04-05 10:28:48.078 12238 12238 V SDL     : onStop()


> Is that working if you comment out "SDL_SendWindowEvent(Android_Window,
> SDL_WINDOWEVENT_MINIMIZED, 0, 0);" in src/core/android/SDL_android.c ?

Not entirely, no.  If I do this, it still sets the UI visbible (so exits fullscreen) which seems to clear the notifcation but it never goes back to fullscreen, so this is not the desired behavior.

If I remove the SDL_WINDOWEVENT_FOCUS_LOST as well then it does seem to behave as I would expect (the fullscreen message stays there and the UI never becomes invisible).
Comment 4 Sylvain 2019-04-05 20:33:44 UTC
Yes SDL_WINDOWEVENT_FOCUS_LOST event doesn't do much.
But SDL_WINDOWEVENT_MINIMIZED, call:

SDL_OnWindowMinimized()
SDL_UpdateFullscreenMode()
 _this->SetWindowFullscreen()
Android_SetWindowFullscreen()
Android_JNI_SetWindowStyle()
and java: setWindowStyle() and COMMAND_CHANGE_WINDOW_STYLE

In activity lifecyle:
https://developer.android.com/guide/components/activities/activity-lifecycle
There is onPause -> onResume() that we already use
and also onStop()  -> onRestart() -> onStart() we can use

In: 
https://developer.android.com/reference/android/opengl/GLSurfaceView

Activity Life-cycle
A GLSurfaceView must be notified when to pause and resume rendering. 
GLSurfaceView clients are required to call onPause() when the activity stops and onResume() when the activity starts.
These calls allow GLSurfaceView to pause and resume the rendering thread, and also allow GLSurfaceView to release and recreate the OpenGL display. 

So we still should block and backup egl in onPause()/onResume().
But maybe we can move the Minimized to onStart/onStop()

e.g.
move SDL_SendWindowEvent(Android_Window, SDL_WINDOWEVENT_RESTORED, 0, 0);   in (future) nativeStart() / nativeRestart()
move SDL_SendWindowEvent(Android_Window, SDL_WINDOWEVENT_MINIMIZED, 0, 0);  in (future) nativeStop()

I'll try a patch
Comment 5 Sylvain 2019-04-06 13:35:45 UTC
Created attachment 3731 [details]
patch

Here's a patch to move focus lost/gain, and maximize/minized events into onRestart/onStop().
I don't know if this going to solve the issue, but this is what you test as  you said.


I can't reproduce the issue with my Samsung s7 Android8 phone. 
adb shell settings put secure immersive_mode_confirmations 0

I see no notification :( 
I tried to use targetSdk 26 or 28 ... No sure how to get this.


The thing I see with the patch is that we sent the event when the app event loop is already paused.
so the app will recevied the events when it goes to foreground ... not sure if this can hurt.

Also the order of the event seem wrong (I didn't touch it, but maybe this could tried)

on Pause, it sends:
- SDL_WINDOWEVENT_FOCUS_LOST
- SDL_WINDOWEVENT_MINIMIZED
on Resume, it sends:
- SDL_WINDOWEVENT_FOCUS_GAINED
- SDL_WINDOWEVENT_RESTORED

I think that should be:

on Pause, it sends:
- same
on Resume, it sends:
- SDL_WINDOWEVENT_RESTORED
- SDL_WINDOWEVENT_FOCUS_GAINED

Very likely not important ..
Comment 6 Sylvain 2019-04-07 11:20:27 UTC
Just wondering, what about setting: 

SDL_SetHint(SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS, "0");
Comment 7 Dan Ginsburg 2019-04-16 12:37:40 UTC
(In reply to Sylvain from comment #5)
> Created attachment 3731 [details]
> patch
> 
> Here's a patch to move focus lost/gain, and maximize/minized events into
> onRestart/onStop().

I can confirm that your patch fixes the issue on my Sony Xperia XZ (Android 8).  The patch looks good to me, can you commit it?

> Just wondering, what about setting: 
> SDL_SetHint(SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS, "0");

That did not do anything to fix the symptoms of the bug, but your patch fixed it.

Thanks!
Comment 8 Sam Lantinga 2019-04-17 03:08:20 UTC
You're right, I think the order of the events on restore should be reversed. Can you confirm that's the order on Windows?

I think this patch is the right approach, do you see any regressions with other testing?
Comment 9 Ellie 2019-04-17 07:05:05 UTC
Is it still sending minimized even though the window is still visible? Because I would have assumed after a minimize event that the window is no longer visible -> drawing can be suspended for perf reasons. So to me it seems wrong that minimize/restore is send in this case at all
Comment 10 Ellie 2019-04-17 07:34:34 UTC
Oh right, I missed that part mentioning the hint to control that behavior, my bad!
Comment 11 Ellie 2019-04-17 07:37:17 UTC
Ok sorry to barge in seconds later, but after reading the description of SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS it sounds like either 1. SDL2 should not minimize and not send a minimize event with SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS=0, or 2. actually minimize (= window is no longer visible) and send a minimize event SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS=1.

So a situation where I get minimize and the window is still visible still doesn't make too much sense to me (sorry if that never happens and I just got that incorrectly from the comments above)
Comment 12 Sylvain 2019-04-18 21:22:59 UTC
Created attachment 3752 [details]
patch 2 (multi-window)

Sam, on Windows 10, it seems also to have the wrong order:
https://hg.libsdl.org/SDL/annotate/c3e9a2b93517/src/core/winrt/SDL_winrtapp_direct3d.cpp#l466

I am not really happy with the previous patch.

Here's a different patch that handles or not multi-windows. As said in https://developer.android.com/guide/topics/ui/multi-window, it exists for API >= 24.
And also, it sends Focus events more appropriately.

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/8703488687ca/src/video/SDL_video.c#l2653
https://hg.libsdl.org/SDL/file/8703488687ca/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.
Comment 13 Ellie 2019-04-19 01:50:18 UTC
IMHO SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS should default to 1 on all platforms, and if you think about it if you tab out of the app normally (which is the best equivalent to ALT+TAB on desktop) then this is also the behavior you get: you lose focus out of fullscreen, it minimizes.

Switching to side by side enabled out of fullscreen on the other hand, that's simply is an operation that no current desktop environment currently offers. So to me it seems like it's just entirely out of the scope of what the hint was supposed to cover, and it's fair to just ignore it for that.

Additionally, I think SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS=1 should mean "attempt to minimize, and only send minimize events if it actually succeeds", not "send minimize event and then also attempt to minimize which may not be applicable" (which is what it feels like on Android in side by side if you send minimize).

Summed up, I think SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS=1 is an okay default everywhere, it just shouldn't have an influence on side by side
Comment 14 Sylvain 2019-04-19 07:45:59 UTC
But the default for any environment, 
when you have two open windows and you switch from one to the one, 
is that you only switch focus. It never minimizes, isn't it?

So that should be SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS = 0
Comment 15 Ellie 2019-04-19 12:07:11 UTC
Yes, but on home-button-leave-app it will ALWAYS minimize like SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS = 1. (While side by side it never will, alike to SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS = 0)

My point is the hint is really meaningless for Android right now, so why switch the default value if it doesn't match what is happening in either case anyway - I would suggest it should just be ignored on Android I think.
Comment 16 Sylvain 2019-04-19 12:47:57 UTC
"home button" triggers onWindowFocusChanged() -> lost focus,
and then, it also triggers both onPause() and onStop() -> Minimized.

So we doesn't need any SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS in that case. It will get minimized anyway.


The default value is SDL_TRUE for SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS.
Which seems to me problematic on Android with apps in multi-window/side-by-side.
Because, in that case, losing the focus does trigger minimize. (which wouldn't happen without the feature).
And it doesn't not actually minimize, it only pauses the event loop.
Comment 17 Ellie 2019-04-19 13:11:44 UTC
> The default value is SDL_TRUE for SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS.
> Which seems to me problematic on Android with apps in multi-window/side-by-side.
> Because, in that case, losing the focus does trigger minimize. (which wouldn't happen without the feature).

Ok, let me be more clear then: I would consider it problematic if you now changed the default to 0 (that part is fine although I think semantically it's kinda useless) but now if someone set it to 1, SDL2 would again send minimize events it side by side even though nothing was minimized. (that I think should be considered a bug/error-inviting nonsense)

So that is what I mean by changing the default seems useless to me. I just don't think it does anything for the actual issue of "if the window didn't minimize SDL2 shouldn't ever send a minimize event" which I think should be addressed
Comment 18 Sylvain 2019-04-19 13:56:47 UTC
This is problematic because:
- if losing focus triggers minimize, it also produces the issue of the current ticket e.g. toggling the status-bar.

- if losing focus triggers the pause, it blocks the apps and the rendering. We don't really want that, because the app is visible: it may have something to display. Blocking the apps is only for saving battery, when the app is really not used in background.
  

Changing the default seems important for me. Because if you don't set the hint, 
you have the fact that "losing focus triggers minimize".
Comment 19 Ellie 2019-04-19 14:40:37 UTC
Right, I'm with you there in terms of behavior! Nothing other than not ever attempting this "minimize" makes sense.

Just let me describe what specific scenario I'm kind of afraid of:

I think some devs may work mainly on desktop and set SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS=1 without being aware of this, and it appears to work fine on all platforms and at a first glance on android, and suddenly side by side is broken for them but they never realize. Do you get what I mean? Because on desktop there is just no equivalent for this where this would ever be a problem, and for the full dedicated fullscreen it DOES make sense to set it to 1.

This is why I keep suggesting that the android code should just be HARDCODED to pretend SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS=0 always for side by side, no matter what the hint says. And then it becomes kind of irrelevant what the default value even is, and SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS=1 could stay for all platforms for consistency

But of course I agree if you just change the default it will also work for most, and I am starting to repeat myself so I will bow out! Just for the sake of preventing developers from their own stumbling, I think what I propose would make sense. But in the end of course it's up to you!
Comment 20 Dan Ginsburg 2019-04-22 18:15:44 UTC
(In reply to Sylvain from comment #12)

> 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/8703488687ca/src/video/SDL_video.c#l2653
> https://hg.libsdl.org/SDL/file/8703488687ca/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.

I can confirm that your latest patch fixes the issue as long as I also set SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS to 0.

It also happens to fix another bug we had which was that we were getting SDL_WINDOWEVENT_FOCUS_LOST but never SDL_WINDOWEVENT_FOCUS_GAINED during startup so our app would think we did not have focus until the app was backgrounded and brought back to the foreground.  So it seems to fix two bugs in one shot for us.
Comment 21 Ellie 2019-04-22 18:43:32 UTC
Btw, another thing occurred to me:

Android 10 apparently has an experimental desktop mode now, which may actually offer going fullscreen and tabbing out and a subsequent actual distinction of whether to minimize or not. It would only be natural if SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS controlled behavior in that situation.

However, if you tie SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS to side by side working properly or sending a bogus nonsensical minimize, then once that desktop mode actually offers this distinction the hint can no longer be used freely to configure that desktop mode situation.

I hope this additional piece of info helps you rethink whether SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS=1 should really break side by side / whether side by side operating properly should really depend on SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS=0
Comment 22 Sam Lantinga 2019-04-22 23:35:08 UTC
Thanks Sylvain, I pushed your second patch:
https://hg.libsdl.org/SDL/rev/d268ce129edb

I also made a change so we don't leave fullscreen mode if we can't actually minimize on this platform:
https://hg.libsdl.org/SDL/rev/6c510e7c6884
https://hg.libsdl.org/SDL/rev/60b397c49d36

Thanks everyone!
Comment 23 Sylvain 2019-04-23 13:03:03 UTC
Ok! Great!

I've just thinking about it again and have noticed:

- In Android, we are always in *fullscreen*. 


- Maybe we can provide the MinimizeWindow implementation for Android.

    Intent startMain = new Intent(Intent.ACTION_MAIN);
    startMain.addCategory(Intent.CATEGORY_HOME);
    startMain.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    startActivity(startMain);


or

    this.moveTaskToBack(true);

https://stackoverflow.com/questions/28162815/i-need-to-minimize-the-android-application-on-back-button-click
Comment 24 Ellie 2019-04-23 14:29:30 UTC
@ always fullscreen: for what it's worth/just to make sure it's not missed, SDL_SetWindowFullScreen() and the window creation flag for fullscreen do toggle the visibility of the status bar, so SDL2 does appear to have some notion of windowed vs fullscreen (which android calls immersive) mode right now, so that seems to me to be different to a notion of "always fullscreen". Whether side by side should or will leave immersive fullscreen to go to windowed is something I don't know though
Comment 25 Ellie 2019-04-23 14:33:16 UTC
(also for what it's worth as elaborated above, IMHO side by side really should never trigger a minimize, not even with SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS=1 - even if that would actually be possible)
Comment 26 Sam Lantinga 2019-04-23 15:05:50 UTC
I agree with Jonas, side by side mode shouldn't minimize the app. And when not in side by side mode, putting the task in the background is already minimized, so I think this only becomes relevant in the new Android desktop mode.

Thoughts?
Comment 27 Sylvain 2019-04-23 15:18:27 UTC
Also agreed, 


There is a isInMultiWindowMode() method

https://developer.android.com/reference/android/app/Activity.html#isInMultiWindowMode()


I'll make a patch:
- to add the android MinimizeWindow(), and discard it in multi-window.
(same is done for cocoa: https://hg.libsdl.org/SDL/file/9b7633bd0aa0/src/video/SDL_video.c#l2648 )

Not sure how it will behave on ChromeOS or DeX ..
Comment 28 Sylvain 2019-04-23 15:19:59 UTC
I think some notifications could also make the app lose focus ?! and so minimize it ?
Comment 29 Sylvain 2019-04-23 19:54:03 UTC
Created attachment 3762 [details]
patch MinimizeWindow

Here's a patch to minimize window on Android.
And also not to do it in multi-window (nor in picture in picture).

Only tested in multi-window:
with FULLSCREEN window flag, if you change focus, it would minimize the app.
and with test of isInMultiWindowMode(), it doesn't do it. (so it's no op).

But maybe it has some application on ChromeOs, Dex, etc.
Comment 30 Sam Lantinga 2019-04-23 21:14:59 UTC
We don't want to minimize on focus loss ever, on Android, unless we're in a desktop environment. Right? If we're multi-window, we want to stay visible, if the settings overlay pops up, we want to stay visible, if we're actually task switched away, we'll be automatically minimized...
Comment 31 Ellie 2019-04-23 23:11:47 UTC
> We don't want to minimize on focus loss ever, on Android, unless we're in a desktop environment. Right?

Not sure whether I'm meant to answer, but from all I've seen I believe that's true. Android 10's experimental desktop UI (which sadly I cannot test due to lack of Android 10 device) is the only situation where I can imagine a minimize to make any sense at all.
Comment 32 Sylvain 2019-04-24 16:35:53 UTC
I agree I wouldn't use the minimize on phone mode, but on ChromeOs or Android desktop, it would similar as other desktop os.
Comment 33 Sam Lantinga 2019-04-24 19:46:04 UTC
Sounds good. Can you adjust the patch to reflect that?
Comment 34 Sylvain 2019-04-28 19:26:20 UTC
So I'm re-opening the issue in case this present any interest to be merged.

But I am not able to really test it: no chromeos, nor dex, nor android 10 desktop.

From the patch, maybe:

shouldMinimizeOnFocusLoss() should be changed so that:
by default return false, 
and true when: 
isChromebook() or isDeXMode() or is-android-desktop ?
Comment 35 Ellie 2019-05-18 09:02:31 UTC
If shouldMinimizeOnFocusLoss()==true means that tabbing out of fullscreen will minimize, then yes that sounds like a good suggestion to me!

However, I don't actually know if any of these desktop modes for android even support fullscreen, or minimizing windows. They are all made for office productivity and not for gaming where fullscreen would be more important, so I'm not sure if they do... (sadly I hadn't had the opportunity to try one of these modes myself either)
Comment 36 Ryan C. Gordon 2019-05-18 17:31:50 UTC
(In reply to Sylvain from comment #34)
> So I'm re-opening the issue in case this present any interest to be merged.
> 
> But I am not able to really test it: no chromeos, nor dex, nor android 10
> desktop.

I'm inclined to say merge it and see if anyone complains.

--ryan.
Comment 37 Sylvain 2019-06-10 20:12:18 UTC
I have added MinimizeWindow() as requested in bug 4657

but shouldMinimizeOnFocusLoss() remains false for android
https://hg.libsdl.org/SDL/annotate/f7629f5761d8/android-project/app/src/main/java/org/libsdl/app/SDLActivity.java#l867
Comment 38 Sam Lantinga 2019-06-11 13:22:28 UTC
Great, I can test this on DeX and enable shouldMinimizeOnFocusLoss() for testing.