I\'ve been battling with setSystemUiVisibility() to try to hide the soft navigation buttons for a while (for a video player). It does not seem to work as advertised. Here is
I implemented this as below however I get a blank gap at the bottom (see screenshot)
@Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
if (hasFocus) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
getWindow().getDecorView().setSystemUiVisibility(
View.SYSTEM_UI_FLAG_LAYOUT_STABLE
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
| View.SYSTEM_UI_FLAG_LOW_PROFILE
| View.SYSTEM_UI_FLAG_HIDE_NAVIGATION // hide nav bar
| View.SYSTEM_UI_FLAG_FULLSCREEN // hide status bar
| View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
);
}
}
}
Are you sure no user interaction is going on? i.e. emulating a touch which causes the controls to instantly reappear?
From the docs:
SYSTEM_UI_FLAG_HIDE_NAVIGATION
: There is a limitation: because navigation controls are so important, the least user interaction will cause them to reappear immediately. When this happens, both this flag andSYSTEM_UI_FLAG_FULLSCREEN
will be cleared automatically, so that both elements reappear at the same time.
On a side note, I've noticed issues with the view not resizing under some circumstances even with the stock video player in JB. I think it's (or was) a bug.
I found that if the user interacted with the device then the navigation bar would return.
Immediately setting the flags in the OnSystemUiVisibilityChangeListener
handler method would not work. It would work if you changed them after a one second delay.
protected static final int requiredDecorViewFlags = View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_LAYOUT_STABLE
| View.SYSTEM_UI_FLAG_LOW_PROFILE
| View.SYSTEM_UI_FLAG_FULLSCREEN
| View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
protected void listenToUiVisibilityChange() {
Window window = getWindow();
if(window == null) {
return;
}
final View view = window.getDecorView();
if(view == null) {
return;
}
view.setOnSystemUiVisibilityChangeListener(
new View.OnSystemUiVisibilityChangeListener() {
@Override
public void onSystemUiVisibilityChange(int visibility) {
Handler handler = new Handler(
getMainLooper()
);
handler.postDelayed(
new Runnable() {
@Override
public void run() {
Window activityWindow = getWindow();
if(activityWindow == null) {
return;
}
View decorView = activityWindow.getDecorView();
if(decorView == null) {
return;
}
decorView.setSystemUiVisibility(requiredDecorViewFlags);
}
},
1000
);
}
}
);
}
@Override
protected void onResume() {
super.onResume();
listenToUiVisibilityChange();
}
I use setOnSystemUiVisibilityChangeListener() to make this full screen mode work for me including hiding the navigation bar.
@Override
protected void onResume() {
if (Build.VERSION.SDK_INT >= 16) {
getWindow().getDecorView().setOnSystemUiVisibilityChangeListener(
new OnSystemUiVisibilityChangeListener() {
@Override
public void onSystemUiVisibilityChange(int visibility) {
if ((visibility & View.SYSTEM_UI_FLAG_FULLSCREEN) == 0) {
getActionBar().show();
} else {
int mUIFlag = View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_LAYOUT_STABLE
| View.SYSTEM_UI_FLAG_LOW_PROFILE
| View.SYSTEM_UI_FLAG_FULLSCREEN
| View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
getWindow().getDecorView()
.setSystemUiVisibility(mUIFlag);
getActionBar().hide();
}
}
});
}
super.onResume();
}
it seems that android only trigger the setSystemUiVisibility() when inside the listener.
Hmm apparently I duplicated my own question! But anyway I found the answer: After reading the source code - which is often the only way to find things out in Android-land - I discovered the following undocumented fact:
setSystemUiVisibility() only has effect when the view you call it from is visible!
Even more: The view in which you call setSystemUiVisibility() must remain visible for the nav bar to remain hidden. Thanks for documenting that guys, really great.
Here is the relevant code, in View.java
.
void performCollectViewAttributes(AttachInfo attachInfo, int visibility) {
if ((visibility & VISIBILITY_MASK) == VISIBLE) {
if ((mViewFlags & KEEP_SCREEN_ON) == KEEP_SCREEN_ON) {
attachInfo.mKeepScreenOn = true;
}
attachInfo.mSystemUiVisibility |= mSystemUiVisibility;
ListenerInfo li = mListenerInfo;
if (li != null && li.mOnSystemUiVisibilityChangeListener != null) {
attachInfo.mHasSystemUiListeners = true;
}
}
}