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 2242

Summary: Android app is running while the screen is locked, on Samsung !
Product: SDL Reporter: Sylvain <sylvain.becker>
Component: *don't know*Assignee: Gabriel Jacobo <gabomdq>
Status: RESOLVED FIXED QA Contact: Sam Lantinga <slouken>
Severity: normal    
Priority: P2 CC: gabomdq, joeleveque
Version: HG 2.1   
Hardware: ARM   
OS: Android (All)   

Description Sylvain 2013-11-14 17:07:29 UTC
Hello, 

I saw this bug has been fixed : 

Bug 1896 - Android app is running while the screen is locked
https://bugzilla.libsdl.org/show_bug.cgi?id=1896

It actually fixed on my HTC ONE : the apps is paused as expected while the device is locked (black screen), and also it is paused while the mobile is in the locked screen (screen if ON, but before the user has entered its drawing password).


But this seems not to be fixed on the Galaxy Samsun S4 !

While the screen is OFF, the app is paused as expected.

When the user is in the locked screen : the app is running underneath !


Cheers,

Sylvain
Comment 1 Gabriel Jacobo 2013-11-14 19:15:53 UTC
adb logcat please :)
Comment 2 Sylvain 2013-11-14 22:15:53 UTC
As usual no logcat :)

but I will try to get one ...

In the meantimes, I found some interesing stuff :

http://stackoverflow.com/questions/11731285/onresume-being-called-over-and-over-while-phone-screen-is-locked

http://developer.android.com/reference/android/app/Activity.html#onResume%28%29

Keep in mind that onResume is not the best indicator that your activity is visible to the user; a system window such as the keyguard may be in front. Use onWindowFocusChanged(boolean) to know for certain that your activity is visible to the user (for example, to resume a game).
Comment 3 Sylvain 2013-11-14 22:18:28 UTC
sorry I looked at the java code which seems correct as it already uses "onWindowFocusChanged".
Comment 4 Joe LeVeque 2013-11-17 04:42:24 UTC
Hey. I'm also developing a game using for Android using SDL and a T-Mobile Galaxy S4, so I thought I'd try to reproduce your bug. I downloaded your Spider Solitare apk (I found your post in the SDL forum http://forums.libsdl.org/viewtopic.php?t=9746), and I was unsuccessful at reproducing the bug. Your instructions on the forum were a bit hard to understand, but here's what I did (I think this is what you were requesting):

- Start the app.
- Play a card (I noticed the timer didn't start until I did this)
- Waited for the screen to turn off - recorded the timer
- Waited 10 seconds
- Pressed power button - brought up lockscreen
- Waited 10 seconds
- Unlocked phone - recorded timer (same value as previous or 1 second ahead at most).

I tried this a few times, as well as sending your app into the background, and also pressing power to force the screen off, and not once did I notice anything that would lead me to believe the app is not pausing correctly.

As a side note, I found this bug because I have a semi-related issue. My app pauses fine in all instances, and resumes fine after being sent to the background via the Home key, however, if the app is is in the foreground and the power button is pressed (or the screen is allowed to turn off due to inactivity), upon unlocking the screen the device just hangs indefinitely - it can't restore the app, so it never leaves the lockscreen. I noticed your app does not have this issue. May I ask what you are calling to pause/unpause your app?
Comment 5 Sylvain 2013-11-17 08:29:07 UTC
Hello.

I wanted to make this mail to Jonathan privately but it goes somehow public to the mailing list :)

You are right : you have to start the timer by placing one card.

So confirmation about the way to go on/off: 
- you dont need to wait the screen to go off.
- you dont need to put the app in background.

Pressing the hold button is enough (the on/off button).

At least this is what was reported by Samsung, and what I see on another S4.
The S4 I saw, has a "drawing password". Did you have it ? could you double check with this ? The timer was increasing while behing the "password lock" or behing.



Here's what I am using for Background/Foreground : 
- Flagging that we go to background (event SDL_WINDOW_EVENT_FOCUS_LOCUS) or to foreground (event SDL_WINDOW_EVENT_FOCUS_GAIN)
- Then, while in background : forbid any creation/update of textures, and any call to RenderPresent.
- Also in the Java Code : I put an "SDLActivity.mSingleton.finish()" after the call "SDLActivity.nativeInit()" so that the app exit when it ends.
Comment 6 Joe LeVeque 2013-11-17 18:12:22 UTC
On my previous test, I did not have a lockscreen password set. I assume by a "drawing" password you mean the kind where you have to trace a pattern across a grid of dots, so I set one up and tried again. As before, I could not reproduce the bug. I appears as though your game pauses/resumes properly.

One thing to note: I am running Cyanogenmod 10.2 on my phone, NOT the stock Samsung GS4 firmware. I wonder if your bug only occurs with the proprietary Samsung firmware. If this is the case, it would appear to be a bug in their firmware, not SDL, as Cyanogenmod is closer to stock Android than the Samsung crap firmware is.

So, I assume you meant you're using SDL_WINDOWEVENT_FOCUS_GAINED and SDL_WINDOWEVENT_FOCUS_LOST events to pause/resume your app. I was under the assumption we should use the SDL_APP* events (SDL_APP_WILLENTERBACKGROUND, SDL_APP_WILLENTERFOREGROUND, etc), which are what I'm using. This makes more sense to me anyway, because my app is cross-platform, and using the FOCUS_GAINED/LOST events would cause the game to pause on desktop platforms as well (which may or may not be desired behavior - undesired in my case). You may want to try keying off the SDL_APP* events and try it on a stock GS4 to see if the issue persists.
Comment 7 Sylvain 2013-11-17 18:24:08 UTC
Yes I meant SDL_WINDOWEVENT_FOCUS_GAINED and SDL_WINDOWEVENT_FOCUS_LOST.


Ok, good to know it's probably the samsung firmware. I will try to get a logcat of this issue.
Comment 8 Sylvain 2013-11-17 18:28:01 UTC
Yes, maybe I should rely on only SDL_APP_WILLENTERBACKGROUND or SDL_APP_WILLENTERFOREGROUND.
Comment 9 Sylvain 2013-11-29 10:39:46 UTC
Hello,

So this is indeed a bug in my application :)
I used to rely on SDL_WINDOWEVENT_FOCUS_GAINED to resynchronize my internal "current time".

Occasionaly, there is 10 ms between SDL_APP_WILLENTERFOREGROUND and SDL_WINDOWEVENT_FOCUS_GAINED, which is enough for my application to process the mainloop with an old time reference and then virtually try to catch up a wrong  time gap.

Most of the time, this delay is < 1ms and so it were looking fine.


Otherwise I noticed on Android that SDL_APP_WILLENTERBACKGROUND and SDL_APP_DIDENTERBACKGROUND were actually recieved when the application is entering in the foreground.

(SDL_WINDOWEVENT_FOCUS_LOST is correctly recieved before application is in background)


thanks,
Sylvain
Comment 10 Gabriel Jacobo 2013-11-29 13:07:25 UTC
The order of events should be fixed here: https://hg.libsdl.org/SDL/rev/3b0346b37e0f

Thanks!
Comment 11 Sylvain 2013-11-29 14:25:51 UTC
By the way, I use the default configuration : BLOCK_ON_PAUSE.

Now WILL_ENTER_BG and DID_ENTER_BG arrives when entering to BG, so this is correct.
(Maybe the DID_ENTER_BG should never arrive ? and be posted after blocking the evenloop? but I dont use it anyway)

but foreground happens sometimes lately (here 16 ms ! with SDL_GetTicks())

V/SDL     ( 6417): Window size:1920x1080
V/SDL     ( 6417): onWindowFocusChanged(): true
V/SDL     ( 6417): nativeResume()
E/void make_app()( 6417): SDL _is_foreground  670715
********** 400 times those lines ! ******
E/void make_app()( 6417): SDL _is_foreground  670723
I/SensorManager( 6417): protected boolean registerListenerImpl(SensorEventListener .....
E/void app()( 6417): SDL _is_foreground  670731
E/int app::pollEvent()( 6417): SDL_APP_WILLENTERFOREGROUND at t=670731
E/int app::pollEvent()( 6417): SDL_APP_DIDENTERFOREGROUND at t=670731
E/int app::pollEvent()( 6417): SDL_WINDOWEVENT_FOCUS_GAINED at t=670731


I guess FOREGROUND events should be sent before signaling the Resume Semaphore !
So they are already in the buffer of events (?) when the app can run.

thanks
Comment 12 Sylvain 2013-12-02 18:55:07 UTC
Hello,

Sorry to show up again, but I would like re-open the issue !
At least, to discuss this.

I believe the commit
https://hg.libsdl.org/SDL/rev/3b0346b37e0f introduces a new small random delay between the app been unlocked for running ("SDL_SemPost(Android_ResumeSem)"), and the event informing the app that it has been waked-up (SDL_SendAppEvent(SDL_APP_WILLENTERFOREGROUND)).

Since this is a multi-thread issue, there can no delay (as before) or a big delay.

Here's an example. I believe, lots of apps use this simplified "event loop" :

while (1)
{
    // process all events
    while (SDL_pollevent(&event) != -1)
    { 
       process_the_event(&event)
    }

    // compute, time, rendering ...
    main_process();
}


Before:
We always had the following sequence :

main_process()
event SDL_APP_DIDENTERBACKGROUND
event SDL_APP_WILLENTERFOREGROUND
main_process()

Currently, because of the delay, we can also have this case :

main_process()
event SDL_APP_DIDENTERBACKGROUND
// SDL_SemPost(Android_ResumeSem)
main_process() // N times !
event SDL_APP_WILLENTERFOREGROUND
main_process()


I use the SDL_APP_WILLENTERFOREGROUND to resynchronize my application : therefore, the "main_process()" sees no time gap because of the background/foreground. So the time seems elapse continuously.

Of course, user application can handle this by remembering to be in "background" state. But I believe this is better to make this as transparent as possible to the user application.

... I just mean to replace : 

(!SDL_SemValue(Android_ResumeSem) SDL_SemPost(Android_ResumeSem);        
SDL_SendAppEvent(SDL_APP_WILLENTERFOREGROUND);

by : 

SDL_SendAppEvent(SDL_APP_WILLENTERFOREGROUND);
(!SDL_SemValue(Android_ResumeSem) SDL_SemPost(Android_ResumeSem);        

Thanks,

Sylvain
Comment 13 Gabriel Jacobo 2013-12-02 19:07:52 UTC
I'm not saying the order should be as is, AFAIK we can change it without repercussions...ironically we can pretty much do this because you don't need any of the "post resume" messages actually.

You can probably achieve what you want by just waiting for SDL_APP_DIDENTERBACKGROUND. When that event comes in, you know the next SDL_PollEvent will block itself, so you just measure the time before calling SDL_PollEvent and after, you get the time the app was paused, no multithreading issues to worry about.

Or you could just take the time at the start of each frame :)

All the SDL_APP_* events are there to make things similar to the way the iOS backend works, but as you can probably notice there's lots of redundant stuff.
Comment 14 Sylvain 2013-12-02 20:09:29 UTC
I dont use frames as a time reference, because there are many devices which have low/high cpu, different timings, and I want reproductably.

I am not very familiar with the IOS port. I use it, but never read deep into it.
Though,  I read that "applicationWillEnterForeground" would be called before application gets active. IMHO, I think this is not the case currently for Android port : SDL_WILLENTERFOREGROUND is sent whereas the app is already active.



Yes, I will probably patch anyway my application to make a weaker assumption on this event.
Comment 15 Sylvain 2013-12-03 14:43:18 UTC
Sorry for being picky, (maybe you'll get some usefull information) :


> You can probably achieve what you want by just waiting for SDL_APP_DIDENTERBACKGROUND. 
> When that event comes in, you know the next SDL_PollEvent will block itself,

This is not correct. Even after SDL_APP_DIDENTERBACKGROUND, you can have a few calls to PollEvent (with no event received) before being actually blocked by the semaphore inside SDL_PollEvent.


A Solution would be to insert this event by the application thread when it gets the semaphore.
Another Solution would be to make SDL_PollEvent auto-block when just after it decodes SDL_APP_DIDENTERBACKGROUND (but difficult to unlock then).

> so you just measure the time before calling SDL_PollEvent and after,
> you get the time the app was paused, no multithreading issues to worry about.

Then it gets more difficult to detect the "after". (I mean to detect the first call to SDL_PollEvent when being back in foreground).
So far, I can only make it work with a "timeout".
Comment 16 Gabriel Jacobo 2013-12-03 15:10:35 UTC
Ok, you win :)

https://hg.libsdl.org/SDL/rev/a5270cef21a7
Comment 17 Sylvain 2013-12-03 15:16:20 UTC
Hey, 

I dont mean to force a modification. I just bring some information and maybe spot a bug!

(I have already added some robustess on my code anyway as you suggested).

Thanks!