Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android Immersive mode reset when changing activity

I'm facing a problem when using immersive mode. Here is the code I put on all activities:

 @Override
 public void onWindowFocusChanged(boolean hasFocus) {
     super.onWindowFocusChanged(hasFocus);
     if (hasFocus) {
         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_HIDE_NAVIGATION
                 | View.SYSTEM_UI_FLAG_FULLSCREEN
                 | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
         );
     }
 }

The navigationBar and statusBar are invisible, this is good.

The problem is that every time I go to another activity, the navigationBar appears, then disappears. I would like that the navigationBar to not appear like that.

like image 899
Valentin Avatar asked Mar 21 '15 17:03

Valentin


4 Answers

The simplest working way is to create a base activity class like the following:

public abstract class BaseActivity extends AppCompatActivity {

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        enableImmersiveMode();
    }

    @Override
    public void onWindowFocusChanged(boolean hasFocus) {
        super.onWindowFocusChanged(hasFocus);

        if(hasFocus) {
            enableImmersiveMode();
        }
    }

    protected void enableImmersiveMode() {
        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_HIDE_NAVIGATION
                    | View.SYSTEM_UI_FLAG_FULLSCREEN
                    | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
            );
        }
    }
}

And all activities that should work in immersive mode should inherit from above base class.

I've just tested it. It prevents an on-screen menu to hide and reveal while changing activities.

like image 132
Tomasz Dzieniak Avatar answered Nov 11 '22 17:11

Tomasz Dzieniak


If you invoque this short of code in method onCreate of activity like the next example:

 @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
            hideSystemUI();
            ...
   }

 // This snippet hides the system bars.
    private void hideSystemUI() {
        // Set the IMMERSIVE flag.
        // Set the content to appear under the system bars so that the content
        // doesn't resize when the system bars hide and show.
        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_HIDE_NAVIGATION // hide nav bar
                        | View.SYSTEM_UI_FLAG_FULLSCREEN // hide status bar
                        | View.SYSTEM_UI_FLAG_IMMERSIVE);
    }

And you must invoke the method on onWindowFocusChanged too.

I hope this help you =)

like image 25
Ricardo Pessoa Avatar answered Nov 11 '22 19:11

Ricardo Pessoa


maybe it's late but right now I faced same issue as you, and stumbled upon this post. By curiosity I found solution that worked for me. I manually called function "onWindowFocusChanged" and passed the "true" parameter. I called that function in OnCreate, before "setContentView(R.layout.activity_main);". That executed the function and set immersive mode (fullscreen), before layout was added, and now I don't see hiding animation of navigation and status bars. I hope that I helped you.

This is the code:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    onWindowFocusChanged(true);
    setContentView(R.layout.activity_main);
}

@Override
public void onWindowFocusChanged(boolean hasFocus) {
    super.onWindowFocusChanged(hasFocus);
    if (hasFocus) {
        getWindow().getDecorView().setSystemUiVisibility(
                View.SYSTEM_UI_FLAG_LAYOUT_STABLE
                        | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
                        | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
                        | View.SYSTEM_UI_FLAG_FULLSCREEN
                        | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
                        | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);}
}
like image 43
VPetrovic Avatar answered Nov 11 '22 19:11

VPetrovic


I was also faced with this issue. It seems there is no way to stop Android from showing the navigation bar again after the configuration changes.

What's worse, it is also not guaranteed when exactly the system UI will be restored. According to my tests on some devices the nav bar can reappear even after onWindowFocusChanged and onResume have been called.

The only reliable way I've found to prevent undesired UI reappearing is to add isInFullScreenModeboolean flag and implement View.OnSystemUiVisibilityChangeListener something like this:

@Override
public void onSystemBarsVisible() {
    if (isInFullScreenMode) {
        // If Android presented system bars 
        // but our app doesn't need them at this point 
        // just call hideSystemUi() again
        hideSystemUi();
        return;
    }
}

@Override
public void onSystemBarsHidden() {
    if (!isInFullScreenMode) {
        // Similar technique as shown above
        showSystemUi();
        return;
    }
}

Of course, sometimes on rotation we can see how the system bars quickly appear and disappear. But at least we can be sure that our app's UI state will be reliably restored.

Edit: To prevent possible confusion (as can be seen in the comments), I will clarify a couple of things:

  • onSystemBarsVisible and onSystemBarsHidden are custom methods which were defined in my app. You won't find them in Android frameworks;
  • The override keywords are used here because these methods were part of a contract (interface);
  • The app I used this functionality in is obsolete now. However, I still remember that the basic idea was as follows (snippet in Kotlin):
fun onSystemUiVisibilityChange(visibility: Int) {
    if (visibility and View.SYSTEM_UI_FLAG_FULLSCREEN == 0) {
        // The system bars are visible
        onSystemBarsVisible()
    } else {
        // The system bars are NOT visible.
        onSystemBarsHidden()
    }
}
like image 28
Stan Mots Avatar answered Nov 11 '22 17:11

Stan Mots