Posted: (updated: )

libGDX and Android's "lights-out" mode

In recent Android releases (starting in API v11 -- Honeycomb) you can put the always-on soft "System UI" bar at the bottom of the screen in a "lights-out" mode, so it is less visually distracting and harder to hit unintentionally. So, instead of the standard bright and busy system bar:

Android System Bar with Lights up

You get the much less visually distracting lights-out system bar:

Android System Bar with Lights out

Once the bar is darkened, the user can brighten it by touching it. The bar will automatically go back into lights-out mode when the interaction completes (for example, if the user opens and then closes the notifications area). As far as I can tell, this behavior isn't documented anywhere.

Controlling System Bar Visibility

To enable support for light's out mode, you need to make sure your application targets at least Honeycomb. Specifically, that means setting the android:targetSdkVersion to at least 11 in the uses-sdk section of your manifest.

Once enabled, the next step is to get the root 'view' for your application. You can generally use getWindow().getDecorView() from an Activity context to look up the root view. However, while this works for me, I'm not really sure what the limitations of this call are. I am using libGDX, which may make the root view discovery simpler or more complicated. All I can state is that "this works for me".

Once you have the correct view, to put the system bar in "light's out" mode invoke setSystemUiVisibility(x) on the view. Where x is one of the following:

  • View.SYSTEM_UI_FLAG_LOW_PROFILE (available when compiling against API versions 14 and above)
  • View.STATUS_BAR_HIDDEN (available when compiling against API versions 11, 12 or 13, deprecated in API v14 and above).
  • 0x1 if you don't care about pretty names or compile-time API compatibility (as 0x1 is what the above pretty names both boil down to).

Since the setSystemUiVisibility() method on the View class was introduced in API version 11, you may need to use one of the backwards compatibility hacks like run-time lookup if you are trying to preserve compatibility with earlier API versions.

Also note that setSystemUiVisibility() needs to be invoked on the UI thread that created the View. Generally, this shouldn't be an issue unless you are changing visibility up and down in response to application changes. (I used a Handler to make sure it was happening in the correct context.)

You probably want to invoke setSystemUiVisibility() in your application's onResume path. While the visibility state seems to persist on a view (and thus just invoking on the onCreate path would be sufficient) there are some cases where it seems to be lost.

Additionally, there is a bug (at least on my Android 3.2 Samsung tablet) where, after a resume from a locked screen the bar comes back enabled. Just invoking setSystemUiVisibility(0x1) in onResume should fix this, but it does not. You have to programmatically brighten the bar before the call to dim it will work. Since its otherwise harmless, I always do a call to make the bar visible before the the call to make it invisible.

The following code snippet will gracefully change the system UI visibility if the current system supports the API.

   if (Build.VERSION.SDK_INT > 11) {
      View rootView = getWindow().getDecorView();
      try {
         Method m = View.class.getMethod("setSystemUiVisibility", int.class);
         m.invoke(rootView, 0x0); // Make it visible to work-around lockscreen resume bug
         m.invoke(rootView, 0x1); // Make it invisible
      } catch (Exception e) {
         // Ignored
      }
   }

Note that there is an OnViewSystemUiVisibilityChangeListener interface. You only need to register one of these if you want to update some part of your interface (e.g., to show/hide some menu options) in tandem with the System UI visiblity changing. You do not need this listener if you are just hiding/showing the system bar.

Comments or Questions?

Subscribe via RSS | Atom Feed