Skip to content

Commit dba9725

Browse files
committed
Fix StatusBar not applying to Modal windows on Android
1 parent a8d44bc commit dba9725

2 files changed

Lines changed: 76 additions & 36 deletions

File tree

packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/statusbar/StatusBarModule.kt

Lines changed: 47 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -9,28 +9,62 @@ package com.facebook.react.modules.statusbar
99

1010
import android.animation.ArgbEvaluator
1111
import android.animation.ValueAnimator
12-
import android.os.Build
13-
import android.view.View
14-
import android.view.WindowInsetsController
12+
import android.view.Window
1513
import android.view.WindowManager
14+
import androidx.core.view.ViewCompat
15+
import androidx.core.view.WindowCompat
16+
import androidx.core.view.WindowInsetsCompat
1617
import com.facebook.common.logging.FLog
1718
import com.facebook.fbreact.specs.NativeStatusBarManagerAndroidSpec
1819
import com.facebook.react.bridge.GuardedRunnable
1920
import com.facebook.react.bridge.NativeModule
2021
import com.facebook.react.bridge.ReactApplicationContext
2122
import com.facebook.react.bridge.UiThreadUtil
2223
import com.facebook.react.common.ReactConstants
24+
import com.facebook.react.interfaces.ExtraWindowEventListener
2325
import com.facebook.react.module.annotations.ReactModule
2426
import com.facebook.react.uimanager.DisplayMetricsHolder.getStatusBarHeightPx
2527
import com.facebook.react.uimanager.PixelUtil
2628
import com.facebook.react.views.view.isEdgeToEdgeFeatureFlagOn
29+
import com.facebook.react.views.view.setStatusBarStyle
2730
import com.facebook.react.views.view.setStatusBarTranslucency
2831
import com.facebook.react.views.view.setStatusBarVisibility
32+
import java.util.Collections
33+
import java.util.WeakHashMap
2934

3035
/** [NativeModule] that allows changing the appearance of the status bar. */
3136
@ReactModule(name = NativeStatusBarManagerAndroidSpec.NAME)
3237
internal class StatusBarModule(reactContext: ReactApplicationContext?) :
33-
NativeStatusBarManagerAndroidSpec(reactContext) {
38+
NativeStatusBarManagerAndroidSpec(reactContext), ExtraWindowEventListener {
39+
40+
init {
41+
reactApplicationContext.addExtraWindowEventListener(this)
42+
}
43+
44+
override fun invalidate() {
45+
super.invalidate()
46+
reactApplicationContext.removeExtraWindowEventListener(this)
47+
}
48+
49+
override fun onExtraWindowCreate(window: Window) {
50+
UiThreadUtil.runOnUiThread {
51+
extraWindows.add(window)
52+
53+
reactApplicationContext.currentActivity?.window?.let {
54+
val controller = WindowCompat.getInsetsController(it, it.decorView)
55+
val insets = ViewCompat.getRootWindowInsets(it.decorView)
56+
val style = if (controller.isAppearanceLightStatusBars) "dark-content" else "light-content"
57+
val visible = insets?.isVisible(WindowInsetsCompat.Type.statusBars()) ?: true
58+
59+
window.setStatusBarStyle(style)
60+
window.setStatusBarVisibility(!visible)
61+
}
62+
}
63+
}
64+
65+
override fun onExtraWindowDestroy(window: Window) {
66+
UiThreadUtil.runOnUiThread { extraWindows.remove(window) }
67+
}
3468

3569
@Suppress("DEPRECATION")
3670
override fun getTypedExportedConstants(): Map<String, Any> {
@@ -118,10 +152,12 @@ internal class StatusBarModule(reactContext: ReactApplicationContext?) :
118152
)
119153
return
120154
}
121-
UiThreadUtil.runOnUiThread { activity.window?.setStatusBarVisibility(hidden) }
155+
UiThreadUtil.runOnUiThread {
156+
activity.window?.setStatusBarVisibility(hidden)
157+
extraWindows.forEach { it.setStatusBarVisibility(hidden) }
158+
}
122159
}
123160

124-
@Suppress("DEPRECATION")
125161
override fun setStyle(style: String?) {
126162
val activity = reactApplicationContext.getCurrentActivity()
127163
if (activity == null) {
@@ -131,41 +167,16 @@ internal class StatusBarModule(reactContext: ReactApplicationContext?) :
131167
)
132168
return
133169
}
134-
UiThreadUtil.runOnUiThread(
135-
Runnable {
136-
val window = activity.window ?: return@Runnable
137-
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.R) {
138-
val insetsController = window.insetsController ?: return@Runnable
139-
if ("dark-content" == style) {
140-
// dark-content means dark icons on a light status bar
141-
insetsController.setSystemBarsAppearance(
142-
WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS,
143-
WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS,
144-
)
145-
} else {
146-
insetsController.setSystemBarsAppearance(
147-
0,
148-
WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS,
149-
)
150-
}
151-
} else {
152-
val decorView = window.decorView
153-
var systemUiVisibilityFlags = decorView.systemUiVisibility
154-
systemUiVisibilityFlags =
155-
if ("dark-content" == style) {
156-
systemUiVisibilityFlags or View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR
157-
} else {
158-
systemUiVisibilityFlags and View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR.inv()
159-
}
160-
decorView.systemUiVisibility = systemUiVisibilityFlags
161-
}
162-
}
163-
)
170+
UiThreadUtil.runOnUiThread {
171+
activity.window?.setStatusBarStyle(style)
172+
extraWindows.forEach { it.setStatusBarStyle(style) }
173+
}
164174
}
165175

166176
companion object {
167177
private const val HEIGHT_KEY = "HEIGHT"
168178
private const val DEFAULT_BACKGROUND_COLOR_KEY = "DEFAULT_BACKGROUND_COLOR"
169179
const val NAME: String = NativeStatusBarManagerAndroidSpec.NAME
180+
private val extraWindows = Collections.newSetFromMap<Window>(WeakHashMap())
170181
}
171182
}

packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/view/WindowUtil.kt

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,9 @@ package com.facebook.react.views.view
1010
import android.app.Activity
1111
import android.graphics.Color
1212
import android.os.Build
13+
import android.view.View
1314
import android.view.Window
15+
import android.view.WindowInsetsController
1416
import android.view.WindowManager
1517
import androidx.core.view.ViewCompat
1618
import androidx.core.view.WindowCompat
@@ -93,6 +95,33 @@ internal fun Window.setStatusBarVisibility(isHidden: Boolean) {
9395
}
9496
}
9597

98+
@Suppress("DEPRECATION")
99+
internal fun Window.setStatusBarStyle(style: String?) {
100+
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.R) {
101+
if ("dark-content" == style) {
102+
// dark-content means dark icons on a light status bar
103+
insetsController?.setSystemBarsAppearance(
104+
WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS,
105+
WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS,
106+
)
107+
} else {
108+
insetsController?.setSystemBarsAppearance(
109+
0,
110+
WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS,
111+
)
112+
}
113+
} else {
114+
var systemUiVisibilityFlags = decorView.systemUiVisibility
115+
systemUiVisibilityFlags =
116+
if ("dark-content" == style) {
117+
systemUiVisibilityFlags or View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR
118+
} else {
119+
systemUiVisibilityFlags and View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR.inv()
120+
}
121+
decorView.systemUiVisibility = systemUiVisibilityFlags
122+
}
123+
}
124+
96125
@Suppress("DEPRECATION")
97126
private fun Window.statusBarHide() {
98127
if (isEdgeToEdgeFeatureFlagOn) {

0 commit comments

Comments
 (0)