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 4657

Summary: Calling SDL_AndroidBackButton minimizes app but cannot return after
Product: SDL Reporter: qufighter
Component: *don't know*Assignee: Sylvain <sylvain.becker>
Status: RESOLVED FIXED QA Contact: Sam Lantinga <slouken>
Severity: normal    
Priority: P2 CC: sylvain.becker
Version: HG 2.0   
Hardware: ARM   
OS: Android (All)   

Description qufighter 2019-06-06 20:42:04 UTC
I'm using the source snapshot SDL-2.0.9-12743

I have this, or this is my intention:

SDL_SetHint(SDL_HINT_ANDROID_TRAP_BACK_BUTTON, "1");

The bug is apparent even when I set 0 there (actually back is still trapped)

I have code like this:

int EventFilter(void* userdata, SDL_Event* event){
    switch ( event->type ){
      case SDL_KEYDOWN:
          if (event->key.keysym.sym == SDLK_AC_BACK){
              //special logic if we have an in-app modal, or by default:
              SDL_AndroidBackButton();
          }
          break;
     }
}

Calling SDL_AndroidBackButton() leaves the app in a state where it cannot be re-entered (transparent window).  I think this is caused after bug #4584 and could be fixed by the related #4580 which is still open as of writing.

Whatever is happening the app seems to enter the paused or stopped state and never able to return.  For now I am able to work around this by commenting out the function, which causes the back button to do nothing.
Comment 1 qufighter 2019-06-06 21:11:12 UTC
I tried out the last release SDL-2.0.9 the issue was apparent there too, so I do not think this is caused by any patches since then.

Maybe its just my phone and this function works for others?
Comment 2 Sylvain 2019-06-10 14:22:23 UTC
This isn't really clear to me what's the issue / what you expect.

SDL_events.h

707  *  If the filter returns 1, then the event will be added to the internal queue.
708  *  If it returns 0, then the event will be dropped from the queue, but the
709  *  internal state will still be updated.  This allows selective filtering of
710  *  dynamically arriving events.
Comment 3 Sylvain 2019-06-10 14:22:57 UTC
I mean't: did you see the event filter function must return a value, maybe that help.
Comment 4 qufighter 2019-06-10 15:23:18 UTC
Sorry for the confusion and thanks for responding, I think the issue title says it best, and my sample code was hastily written.  In my actual test code I "return 0;" instead of "break;"

I traced through at the java code, looks like this is the way its suppose to work:

SDL_AndroidBackButton()
manualBackButton()
pressBackButton()
superOnBackPressed()
super.onBackPressed()

I added some log in superOnBackPressed():

    public void superOnBackPressed() {
        Log.v(TAG, "Actually reaching superOnBackPressed");
        super.onBackPressed();
    }

I added some log in the override:

    @Override
    public void onBackPressed() {
        Log.v(TAG, "Actually reaching override for onBackPressed");

thats where the hint should have an effect possibly... but it seems to not be reached.  I changed my handler to SDK_KEYUP to simplify this log:

06-10 09:52:05.296  9907  9924 I SDL/APP : keyup 1073742094
06-10 09:52:05.297  9907  9907 V SDL     : Actually reaching superOnBackPressed
06-10 09:52:05.309  9907  9907 V SDL     : onPause()
06-10 09:52:05.428  9907  9907 V SDL     : onWindowFocusChanged(): false
06-10 09:52:05.428  9907  9907 V SDL     : nativeFocusChanged()
06-10 09:52:05.458  9907  9924 I SDL/APP :  SDL_WINDOWEVENT_FOCUS_LOST
06-10 09:52:05.498  9907  9907 V SDL     : surfaceDestroyed()
06-10 09:52:05.499  9907  9907 V SDL     : nativePause()
06-10 09:52:05.499  9907  9924 I SDL/APP :  SDL_WINDOWEVENT_MINIMIZED || SDL_WINDOWEVENT_HIDDEN
06-10 09:52:05.500  9907  9924 I SDL/APP : SDL_APP_WILLENTERBACKGROUND !!!!
06-10 09:52:05.500  9907  9924 I SDL/APP : SDL_APP_DIDENTERBACKGROUND !!!!
06-10 09:52:05.742  9907  9907 V SDL     : onStop()
06-10 09:52:05.743  9907  9907 V SDL     : onDestroy()
06-10 09:52:05.754  9907  9924 V SDL     : Finished main function
06-10 09:52:05.756  9907  9907 E SDL     : SDLActivity thread ends (error=ERROR: NumPoints = 0)

so we only see the one log I added... and once we reach this state when we try to resume it doesn't work.

I can try a few things to try to get the intended function to be called, but I'm not sure that will fix the issue.

I just tried calling SDL_AndroidBackButton in a timer so the call isn't tied to the event queue in any way and see what happens.  It was pretty much the same thing.

06-10 10:14:50.025 10969 10986 I SDL/APP : keyup 1073742094
06-10 10:14:50.275 10969 10969 V SDL     : Actually reaching superOnBackPressed
06-10 10:14:50.291 10969 10969 V SDL     : onWindowFocusChanged(): false
06-10 10:14:50.291 10969 10969 V SDL     : nativeFocusChanged()
06-10 10:14:50.291 10969 10969 V SDL     : onPause()
06-10 10:14:50.320 10969 10986 I SDL/APP :  SDL_WINDOWEVENT_FOCUS_LOST
06-10 10:14:50.432 10969 10969 V SDL     : surfaceDestroyed()
06-10 10:14:50.432 10969 10969 V SDL     : nativePause()
06-10 10:14:50.444 10969 10986 I SDL/APP :  SDL_WINDOWEVENT_MINIMIZED || SDL_WINDOWEVENT_HIDDEN
06-10 10:14:50.445 10969 10986 I SDL/APP : SDL_APP_WILLENTERBACKGROUND !!!!
06-10 10:14:50.445 10969 10986 I SDL/APP : SDL_APP_DIDENTERBACKGROUND !!!!
06-10 10:14:50.664 10969 10969 V SDL     : onStop()
06-10 10:14:50.666 10969 10969 V SDL     : onDestroy()
06-10 10:14:50.678 10969 10986 V SDL     : Finished main function
06-10 10:14:50.680 10969 10969 E SDL     : SDLActivity thread ends (error=ERROR: NumPoints = 0)


static Uint32 my_android_back_callbackfunc(Uint32 interval, void* parm){
#ifdef __ANDROID__
    SDL_AndroidBackButton();
#endif
    return 0; // end timer
}

void BackButtonEvent(){
    if( openglApplicationUx->hasCurrentModal() ){
        openglApplicationUx->endCurrentModal();
    }else{
#ifdef __ANDROID__
        //SDL_AndroidBackButton();
        SDL_AddTimer(250, my_android_back_callbackfunc, nullptr);
#endif
    }
}

after calling BackButtonEvent() we returned zero in the SDL_KEYUP case.

findings:

1) the override onBackPressed is not called
2) whatever onBackPressed we do call seems to cause the app to exit (Android 7.0)
Comment 5 qufighter 2019-06-10 15:35:26 UTC
To reword that, it doesn't exit the app, but the main loop exits and when returning to the app nothing will render.

I found the change-set that added this feature:
https://hg.libsdl.org/SDL/rev/320b43d5e5a7

I think that the function seems to work but when looking closer it doesn't work as intended because you cannot return to the app (unless its a bug in android 7 and only on my phone).
Comment 6 qufighter 2019-06-10 16:02:43 UTC
Looks like Activity.onBackPressed always ends the activity, so we never want to call that.

https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/app/Activity.java#3140


this function is easily fixed (super. => this.):

    public void superOnBackPressed() {
        Log.v(TAG, "Actually reaching superOnBackPressed");
        this.onBackPressed();
    }

so now the override gets called... however... the override still calls  super.onBackPressed(); whenever the hint is 0, which ends the activity and main loop, and otherwise it has no effect.

I think we need another way to "minimize" the app so we can avoid super.onBackPressed(); in all cases...

but also probably need to split out where the hint has an effect... since @Override onBackPressed is doing too many things after my change above:

1) handling the default back button behavior, blocking it (trapping it)
2) also being called now (after my change) when calling SDL_AndroidBackButton(); (when calling this function, the SDL_HINT_ANDROID_TRAP_BACK_BUTTON hint shouldn't have any effect... presumably the user is trapping the back button if they wish to manually trigger the "default behavior" by calling this) 

We can't actually use the default behavior though, unless we fully exit the app, which could make it work (clicking the app again would then relaunch and restore it)

I'm not sure the best way to trigger the "minimize" though... I tried calling performStop but that function is not accessible.
Comment 7 Sam Lantinga 2019-06-10 16:14:39 UTC
It seems like SDL_MinimizeWindow() should have the effect you want, if there is only one window. I don't think it does now, but Sylvain, would this be easy to add?
Comment 8 Sylvain 2019-06-10 19:43:07 UTC
Ok, so I fixed the typo in 
  https://hg.libsdl.org/SDL/rev/559c2b342450

onBackPressed behavior is actually to terminate the app, so this is ok, and the hint is to trap it.


I will add the minimize implementation that already exists from bug #4580
Comment 9 Sylvain 2019-06-10 20:10:52 UTC
I've added the minimize window: https://hg.libsdl.org/SDL/rev/f7629f5761d8
Please give a try !
Comment 10 qufighter 2019-06-10 20:39:29 UTC
I will try this out soon, looks promising!  Looks like exactly what the home button does which is what I would expect.

I'm not sure about the typo... I agree it probably makes little difference - but maybe these are truly separate things... or maybe they should be a unified 3rd thing.

It remains unclear to me what the purpose of calling SDL_AndroidBackButton() would be in it's current state, other than make the app require manual exit via task manager in order to use it again.  It seems like the Activity is ended by this but the task continues to run, so the app is in a non working state after calling that (or thats my experience).

At least thats how I'm understanding it having looked at finishAndRemoveTask() vs finishAfterTransition() which is the default.

finish(DONT_FINISH_TASK_WITH_ACTIVITY);
finish(FINISH_TASK_WITH_ROOT_ACTIVITY);

It is still tempting to suggest that if we really want the program to exit we should call finishAndRemoveTask() (not sure if thats available) - or perhaps there is just some other code that is preventing the full exit from occurring after the activity ends.

tl;dr onBackPressed still does something very odd on my device where it does not fully exit the application, just the activity.  Thanks for the minimize patch though I think that will solve the problem for my app and I will test very soon!
Comment 11 qufighter 2019-06-10 21:39:47 UTC
I tested out the gz from https://hg.libsdl.org/SDL/rev/f7629f5761d8

works great when I call SDL_MinimizeWindow(window) in place of where I was calling SDL_AndroidBackButton()... which was not working before this patch.  I am able to switch into and out of the app with either back or the home key now, while still handing special cases where back does something special in my app.

I also tested with SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS 0 and 1 and also split screen mode, this seems to work as expected in all the cases I tried.

I think I'm a little unclear as to the purpose of SDL_HINT_ANDROID_TRAP_BACK_BUTTON though, it seems as though as long as I'm returning 0 from the event handler the button is already trapped, so this hint can only ever have an effect when explicitly calling SDL_AndroidBackButton (which as mentioned above, doesn't fully exit the app, and would only have that effect if TRAP_BACK_BUTTON is 0).  Since its introduction I found this hint to be misleading.  I actually just tried return 1 from both SDL_KEYDOWN and SDL_KEYUP just to see what happens, as far as I can tell onBackPressed is just never called by default for these keys, which sort of makes sense... there is all sorts of special handling of the cases where keydown use to trigger back... and now keyup triggers back, but its all in features of Activity.java which have been overridden I think.... just unclear what TRAP_BACK_BUTTON offers.

Regardless of the confusion about that function, the minimize patch works really nicely, thank you!
Comment 12 Sylvain 2019-06-11 08:18:05 UTC
There are different things:

SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS: if you app loses focus (switch to another window in multiwindow, maybe phone call), should it minimize of not. but this is un-decided now for android.


SDL_HINT_ANDROID_TRAP_BACK_BUTTON:

"A variable to control whether we trap the Android back button to handle it manually.
 872  *        This is necessary for the right mouse button to work on some Android devices, or
 873  *        to be able to trap the back button for use in your code reliably.  If set to true,
 874  *        the back button will show up as an SDL_KEYDOWN / SDL_KEYUP pair with a keycode of 
 875  *        SDL_SCANCODE_AC_BACK."

it seems to me, it's when  you plug a mouse and do a right click on the window. Some device, that's close/terminate the app. so this hint is too prevent and trap this behavior.


SDL_AndroidBackButton() is to actually perform the action. Let's say you trap it,  you do some stuff (save things), then you actually do the pressBack.

so in fact, I think commiting https://hg.libsdl.org/SDL/rev/559c2b342450 was a mistake. I will revert it.
Comment 13 Sylvain 2019-06-11 08:20:33 UTC
Reverted the typo/fix: https://hg.libsdl.org/SDL/rev/5d13e8d106ae
Comment 14 Sam Lantinga 2019-06-11 13:32:46 UTC
Fixed, thanks everyone!