I had the same problem, and I solved it with a simple workaround. Even though I couldn't find the theoretical reason of this workaround, but it worked for me anyway.
It seems like when a volume button is pressed, the 'flags' related to the 'immersive mode' are cleared. And I think that's why the immersive mode is disabled and the immersive mode is not restored automatically.
Therefore, I tried to set the 'flags' after pressing the volume button with 'runnable' object.
So, it works like this:
immersive mode -> volume button pressed(flags cleared) -> 500ms later, the runnable object sets the flags again -> immersive mode restored
1. First, define the runnable object to set the flags
private Runnable decor_view_settings = new Runnable()
{
public void run()
{
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);
}
};
2. Post the runnable object with some delay to a handler when a volume button is pressed
private Handler mHandler = new Handler();
...
@Override
public boolean onKeyDown(int keyCode, KeyEvent event)
{
if(keyCode == KeyEvent.KEYCODE_BACK)
{
finish();
}
else if(keyCode == KeyEvent.KEYCODE_VOLUME_DOWN || keyCode == KeyEvent.KEYCODE_VOLUME_UP)
{
mHandler.postDelayed(decor_view_settings, 500);
}
return super.onKeyDown(keyCode, event);
}
I just delayed it for 500ms with no reason, it's not important.
3. The basic code for immersive mode with runnable object
@Override
public void onWindowFocusChanged(boolean hasFocus)
{
super.onWindowFocusChanged(hasFocus);
if(hasFocus)
{
mHandler.post(decor_view_settings);
}
}
It worked perfectly on my app.
So, when I press a volume button, the immersive mode is disabled and the volume rocker pops up.
after a few seconds, the volume rocker disappears and so does the status bar and the navigation bar.
Hope this work for you.