1

I have 2 functions, which help me to enable and disable full-screen mode in my app. By default, my app is not in full-screen mode. The behavior that I want is when the user opens a fragment, after 5 seconds I enable full-screen mode. When the user touches the screen, I disable the full-screen mode, but after 3 seconds I enable it again. Here's the code, that I wrote (I'm using the legacy version)

private fun enableFullScreen() {
    fullScreenModeEnabled = true
    // From docs
    decorView.systemUiVisibility = (View.SYSTEM_UI_FLAG_IMMERSIVE
            or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
            or View.SYSTEM_UI_FLAG_FULLSCREEN)
}

private fun disableFullScreen() {
    if (fullScreenModeEnabled) {
        // From docs
        decorView.systemUiVisibility = (View.SYSTEM_UI_FLAG_LAYOUT_STABLE
                or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
                or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN)

        fullScreenModeEnabled = false
    }

    handler.removeCallbacks(enableFullScreenRunnable)
    handler.postDelayed(enableFullScreenRunnable, 3000)
}

The enableFullScreenRunnable is a simple runnable which calls the enableFullScreen() function after a certain delay. When the user opens the fragment, after 5 seconds I call the enableFullScreen() function using the handler and the runnable. I have a click listener for the root view, so when the user clicks on the screen, I call disableFullScreen().

rootView.setOnClickListener {
        disableFullScreen()
}

And lastly, I have some UI elements, e.g. a textView, which needs to be synced with the state of my app. So when the app goes to full-screen mode, I have to hide my textView and vice versa.

 decorView.setOnSystemUiVisibilityChangeListener { visibility ->
        if (visibility and View.SYSTEM_UI_FLAG_FULLSCREEN == 0) {
            textView.visibility = View.VISIBLE
        } else {
            textView.visibility = View.INVISIBLE
        }
 }

The thing is, that all these flags are deprecated for Android 11. And in Android studio, it says to use WindowsInsets instead of these flags. How can I achieve the same functionality using WindowInsets? In the official docs, the code doesn't up to date and still it uses the old flags here

Hayk Mkrtchyan
  • 2,835
  • 3
  • 19
  • 61

1 Answers1

2

ANSWER

So we can make it more easier using extension functions, cause we need also the legacy code.

fun Activity.enableFullScreen() {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
        window.insetsController?.let {
            it.systemBarsBehavior = WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
            it.hide(WindowInsets.Type.systemBars())
        }
    } else {
        @Suppress("DEPRECATION")
        window.decorView.systemUiVisibility = (
             View.SYSTEM_UI_FLAG_IMMERSIVE
                 // Set the content to appear under the system bars so that the
                 // content doesn't resize when the system bars hide and show.
                 or View.SYSTEM_UI_FLAG_LAYOUT_STABLE
                 or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
                 or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
                 // Hide the nav bar and status bar
                 or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
                 or View.SYSTEM_UI_FLAG_FULLSCREEN
            )
    }
}

fun Activity.disableFullScreen() {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
        window.setDecorFitsSystemWindows(false)
        window.insetsController?.show(WindowInsets.Type.systemBars())
    } else {
        @Suppress("DEPRECATION")
        window.decorView.systemUiVisibility = (View.SYSTEM_UI_FLAG_LAYOUT_STABLE
            or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
            or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN)
    }
}

So in my fragment I have only one function.

private fun disableFullScreen() {
    if (fullScreenModeEnabled) {
        requireActivity().disableFullScreen()
    }

    handler.removeCallbacks(enableFullScreenRunnable)
    handler.postDelayed(enableFullScreenRunnable, 5000)
}

When user clicks on the screen, I disable the fullScreen like this.

rootView.setOnClickListener {
    disableFullScreen()
}

The only thing left is the listener. So for it we also create an extension function like this.

fun Window.addSystemUIVisibilityListener(visibilityListener: (Boolean) -> Unit) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
        decorView.setOnApplyWindowInsetsListener { v, insets ->
            val suppliedInsets = v.onApplyWindowInsets(insets)
            // only check for statusBars() and navigationBars(), because captionBar() is not always
            // available and isVisible() could return false, although showSystemUI() had been called:
            visibilityListener(suppliedInsets.isVisible(WindowInsets.Type.statusBars() or WindowInsets.Type.navigationBars()))
            suppliedInsets
        }
    } else {
        @Suppress("DEPRECATION")
        decorView.setOnSystemUiVisibilityChangeListener {
            visibilityListener((it and View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) == 0)
        }
    }
}

And in our fragment we use it like this.

requireActivity().window.addSystemUIVisibilityListener { isVisible ->
    if (isVisible) {
        textView.visibility = View.VISIBLE
        fullScreenModeEnabled = false
    } else {
        textView.visibility = View.INVISIBLE
        fullScreenModeEnabled = true
    }
}

That's all. For me it works both with the legacy code and the new code. Thank you.

Hayk Mkrtchyan
  • 2,835
  • 3
  • 19
  • 61