Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Immersive mode instructions reappear every time the device enters this mode

My app uses the new "immersive mode" by calling (in onCreate):

getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);

This works great, but the "how-to" popup ("Swipe down from the top to exit full screen") appears every time the Activity is launched (if the phone is being locked while the activity was showing), even though the user has acknowledged the popup. As far as I understand, the popup is automatically generated by the system, so there's nothing I can do to change this situation, correct?

This issue is reproducible as follows:

  1. Launch immersive Activity [no popup appears, only on the very first launch (correctly)]
  2. Press the power button to switch off screen while the activity is showing
  3. Press power button again to switch on screen
  4. Close Activity by calling finish() e.g. from a button or menu option
  5. Launch Activity again - popup reappears

The popup does NOT reappear if the activity is launched, closed, and relaunched without hitting the power-button in between. Also, it ONLY reappears if the activity was topmost while the power button was pressed.

Correction: The Activity needs to be closed by calling "finish()" (e.g. from a button or a menu option). It works correctly if the Activity is closed by the back-key.

I've uploaded a sample app here: https://github.com/niko001/com.greatbytes.immersivebug/tree/master/Test5

EDIT: There's now an Xposed module to disable the "panic mode", so I guess I'm not alone in seeing this is an annoyance ;)

like image 441
Nick Avatar asked Nov 19 '13 15:11

Nick


People also ask

What is immersive mode?

Some content is best experienced fullscreen without any indicators on the status bar or the navigation bar. Some examples are videos, games, image galleries, books, and slides in a presentation. This is referred to as immersive mode. This page shows how you can engage users more deeply with content in fullscreen.


2 Answers

More succinctly - in K, users will see the confirmation when entering immersive mode if:

  • They have not yet confirmed it for that app (package).
  • They "panicked" last time they were in immersive mode. "Panic" in this case means toggling the screen off, then back on in under 5 seconds (by default).
like image 31
jspurlock Avatar answered Dec 19 '22 23:12

jspurlock


Really interesting question! Thanks to your clear instructions, reproducing the issue wasn't a problem.

Alright, after digging through the source for almost 30-minutes and saying why would they do this? a bunch of times, I think I finally get it. I'll try to explain the best I can, but this is only my interpretation, and may not be correct:

Someone at android realized that the Immersive Mode will send people into a state of panic: how do i exit? (_sorry, I don't know what else the panic would be about_).

In this state of panic, the user will turn to the POWER BUTTON

.... > Power button --> User turns screen off (at x milliseconds since EPOCH)

.... > Praying that the navigation bar comes back

.... > Power button --> User turns screen on (at y milliseconds since EPOCH)

Now, the duration y - x is of significance. We'll discuss it a bit later, but first, let's look at how panic is defined:

panic happens when Praying the navigation bar comes back lasts less than 5 seconds. This value is held by:

mPanicThresholdMs = context.getResources()
                 .getInteger(R.integer.config_immersive_mode_confirmation_panic);

<!-- Threshold (in ms) under which a screen off / screen on will be considered 
     a reset of the immersive mode confirmation prompt.-->
<integer name="config_immersive_mode_confirmation_panic">5000</integer>

Ah, okay. So, it doesn't matter if the user has already acknowledged once, the prompt will be back if the above-mentioned criterion is met - even on the 100th launch.

And here's where the action happens:

public void onPowerKeyDown(boolean isScreenOn, long time, boolean inImmersiveMode) {
    if (mPanicPackage != null && !isScreenOn && (time - mPanicTime < mPanicThresholdMs)) {
        // turning the screen back on within the panic threshold
        unconfirmPackage(mPanicPackage);
    }
    if (isScreenOn && inImmersiveMode) {
        // turning the screen off, remember if we were in immersive mode
        mPanicTime = time;
        mPanicPackage = mLastPackage;
    } else {
        mPanicTime = 0;
        mPanicPackage = null;
    }
}

(time - mPanicTime < mPanicThresholdMs) ==> ( y - x ) < 5000

unconfirmPackage(mPanicPackage) removes mPanicPackage (yours) from the list of packages stored under Settings.Secure.IMMERSIVE_MODE_CONFIRMATIONS.

Needless to say, I find this strange... and wrong. Even if the user is in panic, and takes the power button route, s/he won't see the helpful reminder until next launch. So, what's the point?

Or may be, I am wrong about the definition of panic.

so there's nothing I can do to change this situation, correct?

Correct. To fix this, you would have to add your package-name to value held by Settings.Secure.IMMERSIVE_MODE_CONFIRMATIONS. But, to write to a secure setting, your app requires WRITE_SECURE_SETTINGS permission - not for use by third-party applications.

Links:

ImmersiveModeConfirmation (helper class that manages showing/hiding of confirmation prompt)

like image 193
Vikram Avatar answered Dec 19 '22 23:12

Vikram