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
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.