7

I am trying to hide status bar in Android 10. I've already read a lot of answers to similar questions, but they don't work for my device. The goal is to use the space of the status bar as a part of application view:

enter image description here

Some of the solutions described below work on emulator, but don't work on my physical device (Redmi Note 10, API version 29).

I would appreciate any advice.

What I have tried:
  • Using different predefined styles like @android:style/Theme.NoTitleBar.Fullscreen and so on.
  • Using different style attributes including: android:windowFullscreen, fitsSystemWindows etc.
  • Setting different styles in program code using setSystemUiVisibility including SYSTEM_UI_FLAG_FULLSCREEN, SYSTEM_UI_FLAG_IMMERSIVE_STICKY, SYSTEM_UI_FLAG_HIDE_NAVIGATION, SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN, SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION, SYSTEM_UI_FLAG_LAYOUT_STABLE.
  • Adding and removing different flags using clearFlags, addFlags and setFlags.
  • Setting status bar color to transparent using setStatusBarColor.
  • Requesting different features using requestWindowFeature.
  • Changing layout top padding to negative values.
  • Using insets by defining applyTopWindowInsetsForView and onApplyWindowInsets functions.
What I've managed to do.

I've managed to get two results, but neither of them is good for me.

  1. Translucent status bar.

enter image description here

  1. Completely black status bar without taking its space for app view.

enter image description here

UPDATE 10 May 2022:

According to the following answer it is impossible to use WindowInsetsController on API 29 or earlier: How do I hide the status bar in my Android 11 app?

SOLUTION 1

Proposed by @Zain.

Activity:

protected void onCreate(Bundle savedInstanceState) {
    ...
    WindowCompat.setDecorFitsSystemWindows(getWindow(), false);
    WindowInsetsControllerCompat windowInsetsCompat = new WindowInsetsControllerCompat(getWindow(), getWindow().getDecorView());
    windowInsetsCompat.hide(WindowInsetsCompat.Type.statusBars());        
    windowInsetsCompat.setSystemBarsBehavior(WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE);
    ...

theme.xml:

<item name="android:windowLayoutInDisplayCutoutMode">shortEdges</item>

SOLUTION 2

Activity:

protected void onCreate(Bundle savedInstanceState) {
    ...        
    getWindow().getDecorView().setSystemUiVisibility(
            View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
            | 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_LOW_PROFILE
    );        
    ...

theme.xml:

<item name="android:windowLayoutInDisplayCutoutMode">shortEdges</item>
Ivan Bychkov
  • 269
  • 3
  • 8

2 Answers2

7

You need to display contents content edge-to-edge in your app (Documentation reference)

Step 1: Use: WindowCompat.setDecorFitsSystemWindows(window, false)

This is the primary step for ensuring that your app goes edge-to-edge, that is, laid out using the entire width and height of the display. Use WindowCompat.setDecorFitsSystemWindows(window, false) to lay out your app behind the system bars, as shown in the following code example:

Step 2: Hide the status bar using WindowInsetsControllerCompat:

    WindowInsetsControllerCompat(window, window.decorView).apply {
        // Hide the status bar
        hide(WindowInsetsCompat.Type.statusBars())
        // Allow showing the status bar with swiping from top to bottom
        systemBarsBehavior =
            WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
    }

Step 3: As from step 1 the activity contents at the bottom will be obscured by the bottom navigation bar; then you need to adjust the bottom margin of the root layout of the activity to height of the navigation bar by using WindowInsetsListener:

Kotlin:

// root layout of your activity
val root = findViewById<ConstraintLayout>(R.id.root)
ViewCompat.setOnApplyWindowInsetsListener(
    root
) { view: View, windowInsets: WindowInsetsCompat ->
    val insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars())
    view.layoutParams = (view.layoutParams as FrameLayout.LayoutParams).apply {
        // draw on top of the bottom navigation bar
        bottomMargin = insets.bottom
    }

    // Return CONSUMED if you don't want the window insets to keep being
    // passed down to descendant views.
    WindowInsetsCompat.CONSUMED
}

Java:

WindowInsetsControllerCompat windowInsetsCompat = new WindowInsetsControllerCompat(getWindow(), getWindow().getDecorView());

windowInsetsCompat.hide(WindowInsetsCompat.Type.statusBars());
windowInsetsCompat.setSystemBarsBehavior(WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE);

// root layout of your activity
ConstraintLayout root = findViewById(R.id.root);

ViewCompat.setOnApplyWindowInsetsListener(
        root
        , (view, windowInsets) -> {
            Insets insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars());
            FrameLayout.LayoutParams params = (FrameLayout.LayoutParams) view.getLayoutParams();
            params.bottomMargin = insets.bottom;
            return WindowInsetsCompat.CONSUMED;
        });

Step 4: Finally make sure that drawing in cutout area is allowed in your app's theme:

<item name="android:windowLayoutInDisplayCutoutMode">always</item>
Zain
  • 37,492
  • 7
  • 60
  • 84
  • I tried to adopt your solution to Java and my minSdk=26 using the documentation reference you provided. But the following code gives null: `WindowInsetsControllerCompat windowInsetsController = ViewCompat.getWindowInsetsController(getWindow().getDecorView());` – Ivan Bychkov May 10 '22 at 07:43
  • Clarification: `windowInsetsController` equals zero only on my physical device. On emularor it is a valid `WindowInsetsControllerCompat`. – Ivan Bychkov May 10 '22 at 09:41
  • I replaced `WindowInsetsControllerCompat windowInsetsController = ViewCompat.getWindowInsetsController(getWindow().getDecorView());` with `WindowInsetsControllerCompat windowInsetsController = WindowCompat.getInsetsController(getWindow(), getWindow().getDecorView());` and `windowInsetsController` started to be filled. But if `windowInsetsController.hide(WindowInsetsCompat.Type.systemBars());` is called, then I get completely black status bar (which is wrong). – Ivan Bychkov May 10 '22 at 10:28
  • My device SDK version is 29. And according to this answer it is impossible to use `WindowInsetsController` on API-29 or earlier): https://stackoverflow.com/questions/66075399/how-do-i-hide-the-status-bar-in-my-android-11-app – Ivan Bychkov May 10 '22 at 13:19
  • @IvanBychkov I just added the java equivalent can you test that now. – Zain May 10 '22 at 19:25
  • 1
    Thank you. This code works if `always` is changed to `shortEdges` (`always` is incorrect value). Also, `setOnApplyWindowInsetsListener` appears to be not required (it works without this code). – Ivan Bychkov May 10 '22 at 20:33
1

I found the solution. The following line was necessary:

<item name="android:windowLayoutInDisplayCutoutMode">shortEdges</item>

Ivan Bychkov
  • 269
  • 3
  • 8