I have an activity that's supposed to host a web view in fullscreen with the status and navigation bars fully immersive as I don't want to set a color for the status bar. I tried multiple snippets from S.O and I still have a dark status bar for Android 12 and above devices. I need a fully immersive status and navigation bar. With the implementation below, the navigation bar is displayed as expected; the status bar is still dark.
Here's the activity's theme that I apply to the activity:
<style name="FullScreenTheme" parent="Theme.AppCompat.NoActionBar">
<item name="windowActionBar">false</item>
<item name="windowNoTitle">true</item>
<item name="android:colorBackground">@null</item>
<item name="android:windowBackground">@null</item>
<item name="background">@null</item>
<item name="android:windowFullscreen">true</item>
<item name="android:windowContentOverlay">@null</item>
<item name="android:navigationBarColor">@android:color/transparent</item>
<item name="android:statusBarColor">@android:color/transparent</item>
<item name="android:enforceStatusBarContrast" tools:targetApi="q">false</item>
<item name="android:enforceNavigationBarContrast" tools:targetApi="q">false</item>
</style>
Here's the activity's onCreate()
function:
super.onCreate(savedInstanceState)
WindowCompat.setDecorFitsSystemWindows(window, false)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R){
val windowInsetsController = WindowCompat.getInsetsController(window, window.decorView)
windowInsetsController.systemBarsBehavior = WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
windowInsetsController.hide(WindowInsetsCompat.Type.systemBars())
} else {
@Suppress("DEPRECATION") // Older API support
window.decorView.systemUiVisibility = (View.SYSTEM_UI_FLAG_IMMERSIVE
or View.SYSTEM_UI_FLAG_LAYOUT_STABLE
or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
or View.SYSTEM_UI_FLAG_FULLSCREEN)
}
After this I call the setContentView()
and move forward. Any ideas as to what I'm missing exactly here ? Has any one faced a similar issue lately and has a (tested) workaround for this ?
The issue you're facing is probably related to the fact that you're not enabling cut-out
mode (Enabling cut-out mode means that the full-screen mode will not reserve the space for the notch/camera and will just draw behind it as well, which will expand the screen periphery to the very outer boundaries).
Here's a helper method to enable or disable cut-out mode. Make sure you call it from an activity context (because it's an extension function)
@TargetApi(Build.VERSION_CODES.P)
fun ComponentActivity.cutoutMode(enable: Boolean) {
if (enable) {
window.attributes?.layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES
} else {
window.attributes?.layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER
}
}
Example usage:
this@MainActivity.cutoutMode(enable = true)
//or simply
cutoutMode(enable = true)
If you want a rather static way to do it (in XML), you can edit your app's theme (in your themes.xml
or styles.xml
, wherever it is) to include this following property:
<item name="android:windowLayoutInDisplayCutoutMode">
shortEdges <!-- default, shortEdges, or never -->
</item>
You can find more about cut-out mode in the official docs: Google's Developer Android- Support display cutouts
If you're still having issues going full screen, you can use this helper method :
fun ComponentActivity.hideSystemUI(useDeprecated: Boolean) {
runOnUiThread {
if (!useDeprecated) {
WindowCompat.setDecorFitsSystemWindows(window, false)
WindowInsetsControllerCompat(window, window.decorView).let { controller ->
controller.hide(WindowInsetsCompat.Type.systemBars())
controller.systemBarsBehavior = WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
}
} else {
val decorView: View = window.decorView
val uiOptions = decorView.systemUiVisibility
var newUiOptions = uiOptions
newUiOptions = newUiOptions or View.SYSTEM_UI_FLAG_LOW_PROFILE
newUiOptions = newUiOptions or View.SYSTEM_UI_FLAG_FULLSCREEN
newUiOptions = newUiOptions or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
newUiOptions = newUiOptions or View.SYSTEM_UI_FLAG_IMMERSIVE
newUiOptions = newUiOptions or View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
decorView.systemUiVisibility = newUiOptions
View.OnSystemUiVisibilityChangeListener { newmode ->
if (newmode != newUiOptions) {
hideSystemUI(false)
}
}
window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS)
window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION)
}
}
}
Please note that you can still use the deprecated way to go fullscreen (immersive mode). I personally found it easier and more stable even though it's deprecated ? That's why I don't do 'if-else' SDK version checks to choose one of the two ways, I only do:
hideSystemUI(useDeprecated = true)
even if I am on Android 14.
Hope this helps :)