Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Maintaining "lights-out" mode (View.setSystemUiVisibility) across restarts

Tags:

android

I'm setting up "lights-out" mode for my android app when its running on recent phones and tablets. In my onCreate() method, I added:

View rootView = getWindow().getDecorView();
rootView.setSystemUiVisibility(View.STATUS_BAR_HIDDEN); // aka View.SYSTEM_UI_FLAG_LOW_PROFILE

this works better than I thought it would. On my Android 3.2 tablet the status bar starts in low profile mode (all the buttons on the bar are replaced with dots). If I interact with the buttons on the bar it will become normal, and then go back to low-profile mode afterwards (e.g., if I check the config/notifications window from the status bar). So it seems like this is more a property of my app than a "command" to hide the UI directly.

There are two corner cases that are not handled, though. First, If a user taps the status bar without hitting any of the dots, the bar becomes active. It never goes back to low profile mode until the user actually interacts with something on the bar (e.g., looks at the notifications or takes a screenshot). So, if they go back to interacting with my app, the status bar is no longer in low-profile mode. (The Gallery app seems to have this problem, too, so maybe its not just me.) The second corner case is a resume from the lock screen. If I tap the power button to lock the tablet, then unlock it and resume the app, the status bar is fully visible (and interacting with it does not change anything). (The Gallery app does not have this problem.)

A couple blog posts suggest that I could set a handler to listen for system UI visibility changes and then re-hide the UI if it becomes visible. Like this:

rootView.setOnSystemUiVisibilityChangeListener(
  new View.OnSystemUiVisibilityChangeListener() {
    @Override
    public void onSystemUiVisibilityChange(int visibility) {
      if (visibility == View.STATUS_BAR_VISIBLE) {
        game.flagUIIsVisible();
      }
    }
  });

In my case, the method on the game object just sets a flag saying the UI went invisible. Later, if there are any touch events inside my app (they're handled by the same game object), and this flag is set, then I invoke the STATUS_BAR_HIDDEN call again.

However, with these callbacks there is no visibile impact on the UI. I can see that the right handler is being called from some log messages, and I can see the listener is being invoked.

I also tried invoking the STATUS_BAR_HIDDEN call in my onResume path, but that didn't make a difference, either.

I'm looking for information that this is some sort of known bug, or hints for what the Gallery app might be doing (assuming its doing something differently). Or suggestions for other APIs to try (or other details that might be relevant).

I'm using libGDX, and my app only has one view, so its pretty simple. The view is also setup to be fullscreen with no title by libGDX. I've got my targetSdkVersion set to 15 in my manifest.

like image 955
P.T. Avatar asked Jun 14 '12 05:06

P.T.


2 Answers

I suspect there is a bug in Android 3.2, as I can work around the resume-from-lock-screen problem by re-enabling the status bar before disabling it in onResume. No OnSystemUiVisibilityChangeListener is needed.

Specifically, in my onResume path I have code like this:

View rootView = getWindow().getDecorView();
rootView.setSystemUiVisibility(View.STATUS_BAR_VISIBLE);
rootView.setSystemUiVisibility(View.STATUS_BAR_HIDDEN);

The seemingly unnecessary call to make the status bar visible, seems to make the subsequent call to make the status bar hidden actually work after unlocking the device.

like image 86
P.T. Avatar answered Oct 06 '22 01:10

P.T.


Android 4.2 here, on Samsung tablet - your solutions didn't work for me, I actually managed to do this with ValuAnimator fired just after onSystemUiVisibilityChange, with onAnimationEnd listener

        topView.setOnSystemUiVisibilityChangeListener(new View.OnSystemUiVisibilityChangeListener() {
          @Override
          public void onSystemUiVisibilityChange(int visibility) {
             hideMenu();
          }
        });

    private void hideMenu(){

    ValueAnimator hideAnim = ValueAnimator.ofInt(1,2);
    hideAnim.setDuration(1);
    hideAnim.addListener(new AnimatorListenerAdapter() {
        @Override
        public void onAnimationEnd(Animator animation) {
            topView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LOW_PROFILE);
        }
    });
    hideAnim.start();

}
like image 24
Paweł Kozak Avatar answered Oct 05 '22 23:10

Paweł Kozak