0

I am facing an issue with the full-screen immersive mode in Android 11. My Main activity layout file look something like this,

<DrawerLayout .... android:fitsSystemWindows="true">
    <CoordinatorLayout>
          <AppBarLayout>
              <FragmentContainerView>

I am trying to show a full-screen mode from my Fragment. Pre Android 11, I used to call the below function from my Fragment's onCreate view

fun hideStatusBar (activity: AppCompatActivity?) {
activity?.window?.addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN) }

I replaced that with,

fun hideStatusBar(activity: AppCompatActivity?) {
@Suppress("DEPRECATION")
if (isAtLeastAndroid11()) {
    val controller = activity?.window?.insetsController
    controller?.hide(WindowInsets.Type.statusBars())
} else {
    activity?.window?.addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN)
}
}

This removes the status bar as intended but leaves a blank space at the top of the screen in the status bar area

With status bar:

enter image description here

Status bar removed:

enter image description here

I tried to measure the Window Insets inside my fragment and adjust the height of my fragment container

override fun onActivityCreated(savedInstanceState: Bundle?) {
    super.onActivityCreated(savedInstanceState)
    if(isAtLeastAndroid11()){
        WindowCompat.setDecorFitsSystemWindows(requireActivity().window, false)
        setUiWindowInsets()
    }
}

private fun setUiWindowInsets() {
    ViewCompat.setOnApplyWindowInsetsListener(rootView) { _, insets ->
    
        posTop = insets.getInsets(WindowInsetsCompat.Type.systemBars()).top
        posBottom = insets.getInsets(WindowInsetsCompat.Type.systemBars()).bottom

        rootView.updateLayoutParams<ViewGroup.MarginLayoutParams> {
            updateMargins(
                top = posTop,
                bottom = posBottom)
        }

        insets
    }
}

But my ViewCompat.setOnApplyWindowInsetsListener is never called. As per this article, Coordinator Layout consumes onApplyWindowInsets callbacks and the child won't get any callbacks. rootView is the root view of my Fragment (a relative layout) which was placed in FragmentContainer in my layout hierarchy.

Comparison between Android 10 and 11

enter image description here

My Question:

  1. How should I get the call to my setOnApplyWindowInsetsListener method in fragment?
  2. How should I let my coordinator layout know to occupy full screen when status bar is hidden?

References: Coordinator layout consumes callbacks:

  1. setOnApplyWindowInsetsListener never called
  2. https://medium.com/androiddevelopers/why-would-i-want-to-fitssystemwindows-4e26d9ce1eec
  3. https://newbedev.com/fitssystemwindows-effect-gone-for-fragments-added-via-fragmenttransaction
Madhan
  • 361
  • 4
  • 17

2 Answers2

0

The problem is from the App bar. even though it is full screen it will try to prevent content from colliding with status bar even if it is hidden. this is a new implementation also to prevent the phone notch from covering content.

You should remove the app bar if you want to utilize the whole screen. if really need a tooltip for actions use a bottom bar.

user16930239
  • 6,319
  • 2
  • 9
  • 33
  • Thank you, when you say remove - you mean to remove completely from layout or just hide it when I need full screen. I will try and update – Madhan Oct 02 '21 at 00:09
0

You may have to set fitsSystemWindows flag off (where window is Window instance):

window.setDecorFitsSystemWindows(false);

So I do like this:

private void hideSystemUI() {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
        windowInsetsController.hide(WindowInsets.Type.statusBars());
        window.setDecorFitsSystemWindows(false);
    }
}

Of course, you also need to set the flag on when showing status bar:

private void showSystemUI() {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
        windowInsetsController.show(WindowInsets.Type.statusBars());
        window.setDecorFitsSystemWindows(true);
    }
}

FYI, you may have to trigger hideSystemUI or showSystemUI in Activity.onWindowFocusChanged.

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

    if (hasFocus) {
        if (isImmersive) {
            hideSystemUI();
        } else {
            showSystemUI();
        }
    }
}

(above is in Java. Please translate it into Kotlin)

hata
  • 11,633
  • 6
  • 46
  • 69
  • I have `setDecorFitsSystemWindows` in `onActivityCreated()`. I moved that to `hideSystemUI()` as you suggested, which I am calling from `onViewCreated()`. It has no effect. – Madhan Oct 02 '21 at 03:38
  • @Madhan I updated my answer. You may have to override `onWindowFocusChanged`. – hata Oct 02 '21 at 04:02
  • `onWindowFocusChanged` is called once when the activity loads for the first time, I launch full screen from a fragment. I don't receive any callback in `onWindowFocusChanged` when fragment expands to full screen. Do you know why I am not receiving any calls to `ViewCompat.setOnApplyWindowInsetsListener` in Fragment which sets the margin? – Madhan Oct 02 '21 at 04:34
  • @Madhan I have no idea about that. – hata Oct 02 '21 at 05:11