Posted: 12 June 2012
(updated: 01 July 2012)
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:
You get the much less visually distracting lights-out system bar:
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 (as0x1
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.