Home » Android » android – setSystemUiVisibility(SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) does not work

android – setSystemUiVisibility(SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) does not work

Posted by: admin May 14, 2020 Leave a comment

Questions:

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 my code, inside a visible FrameLayout.

void setNavVisibility(boolean visible)
{
    int newVis = SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
    if (!visible)
    {
        newVis |= SYSTEM_UI_FLAG_LOW_PROFILE | SYSTEM_UI_FLAG_HIDE_NAVIGATION;
    }
    setSystemUiVisibility(newVis);
}

Slightly modified from the SDK example:

    void setNavVisibility(boolean visible) {
        int newVis = SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
                | SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
                | SYSTEM_UI_FLAG_LAYOUT_STABLE;
        if (!visible) {
            newVis |= SYSTEM_UI_FLAG_LOW_PROFILE | SYSTEM_UI_FLAG_FULLSCREEN
                    | SYSTEM_UI_FLAG_HIDE_NAVIGATION;
        }

Neither do anything when called. I had some success when I called them from a different View, but the documentation doesn’t mention that the View you are calling from has any effect? I assume that the documentation is (surprise surprise) somewhat lacking here. Does anyone know what’s really going on?

How to&Answers:

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;
        }
    }
}

Answer:

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.

Answer:

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
            );
        }
    }
}

enter image description here

Answer:

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 and SYSTEM_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.