Skip to content

Commit e952685

Browse files
committed
Fix StatusBar not applying to Modal windows on Android
1 parent b1579f0 commit e952685

3 files changed

Lines changed: 101 additions & 37 deletions

File tree

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

Lines changed: 44 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,14 @@ 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
19+
import com.facebook.react.bridge.ExtraWindowEventListener
1820
import com.facebook.react.bridge.GuardedRunnable
1921
import com.facebook.react.bridge.NativeModule
2022
import com.facebook.react.bridge.ReactApplicationContext
@@ -24,13 +26,43 @@ 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
2932

3033
/** [NativeModule] that allows changing the appearance of the status bar. */
3134
@ReactModule(name = NativeStatusBarManagerAndroidSpec.NAME)
3235
internal class StatusBarModule(reactContext: ReactApplicationContext?) :
33-
NativeStatusBarManagerAndroidSpec(reactContext) {
36+
NativeStatusBarManagerAndroidSpec(reactContext), ExtraWindowEventListener {
37+
38+
private val extraWindows = mutableSetOf<Window>()
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+
extraWindows.add(window)
51+
52+
UiThreadUtil.runOnUiThread {
53+
val controller = WindowCompat.getInsetsController(window, window.decorView)
54+
val insets = ViewCompat.getRootWindowInsets(window.decorView)
55+
val style = if (controller.isAppearanceLightStatusBars) "dark-content" else "light-content"
56+
val visible = insets?.isVisible(WindowInsetsCompat.Type.statusBars()) ?: true
57+
58+
window.setStatusBarStyle(style)
59+
window.setStatusBarVisibility(!visible)
60+
}
61+
}
62+
63+
override fun onExtraWindowDestroy(window: Window) {
64+
extraWindows.remove(window)
65+
}
3466

3567
@Suppress("DEPRECATION")
3668
override fun getTypedExportedConstants(): Map<String, Any> {
@@ -118,10 +150,12 @@ internal class StatusBarModule(reactContext: ReactApplicationContext?) :
118150
)
119151
return
120152
}
121-
UiThreadUtil.runOnUiThread { activity.window?.setStatusBarVisibility(hidden) }
153+
UiThreadUtil.runOnUiThread {
154+
activity.window?.setStatusBarVisibility(hidden)
155+
extraWindows.forEach { it.setStatusBarVisibility(hidden) }
156+
}
122157
}
123158

124-
@Suppress("DEPRECATION")
125159
override fun setStyle(style: String?) {
126160
val activity = reactApplicationContext.getCurrentActivity()
127161
if (activity == null) {
@@ -131,36 +165,10 @@ internal class StatusBarModule(reactContext: ReactApplicationContext?) :
131165
)
132166
return
133167
}
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-
)
168+
UiThreadUtil.runOnUiThread {
169+
activity.window?.setStatusBarStyle(style)
170+
extraWindows.forEach { it.setStatusBarStyle(style) }
171+
}
164172
}
165173

166174
companion object {

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
@@ -9,7 +9,9 @@ package com.facebook.react.views.view
99

1010
import android.graphics.Color
1111
import android.os.Build
12+
import android.view.View
1213
import android.view.Window
14+
import android.view.WindowInsetsController
1315
import android.view.WindowManager
1416
import androidx.core.view.ViewCompat
1517
import androidx.core.view.WindowCompat
@@ -65,6 +67,33 @@ internal fun Window.setStatusBarVisibility(isHidden: Boolean) {
6567
}
6668
}
6769

70+
@Suppress("DEPRECATION")
71+
internal fun Window.setStatusBarStyle(style: String?) {
72+
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.R) {
73+
if ("dark-content" == style) {
74+
// dark-content means dark icons on a light status bar
75+
insetsController?.setSystemBarsAppearance(
76+
WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS,
77+
WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS,
78+
)
79+
} else {
80+
insetsController?.setSystemBarsAppearance(
81+
0,
82+
WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS,
83+
)
84+
}
85+
} else {
86+
var systemUiVisibilityFlags = decorView.systemUiVisibility
87+
systemUiVisibilityFlags =
88+
if ("dark-content" == style) {
89+
systemUiVisibilityFlags or View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR
90+
} else {
91+
systemUiVisibilityFlags and View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR.inv()
92+
}
93+
decorView.systemUiVisibility = systemUiVisibilityFlags
94+
}
95+
}
96+
6897
@Suppress("DEPRECATION")
6998
private fun Window.statusBarHide() {
7099
if (isEdgeToEdgeFeatureFlagOn) {

packages/rn-tester/js/examples/Modal/ModalPresentation.js

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,15 @@ import {RNTesterThemeContext} from '../../components/RNTesterTheme';
1919
import RNTOption from '../../components/RNTOption';
2020
import * as React from 'react';
2121
import {useCallback, useContext, useState} from 'react';
22-
import {Modal, Platform, StyleSheet, Switch, Text, View} from 'react-native';
22+
import {
23+
Modal,
24+
Platform,
25+
StatusBar,
26+
StyleSheet,
27+
Switch,
28+
Text,
29+
View,
30+
} from 'react-native';
2331

2432
const animationTypes = ['slide', 'none', 'fade'] as const;
2533
const presentationStyles = [
@@ -312,6 +320,25 @@ function ModalPresentation() {
312320
onPress={() => setProps(prev => ({...prev, visible: false}))}>
313321
Close
314322
</RNTesterButton>
323+
<RNTesterText style={styles.title}>
324+
Status Bar controls
325+
</RNTesterText>
326+
<View style={{flexDirection: 'row'}}>
327+
<RNTesterButton
328+
onPress={() => StatusBar.setBarStyle('light-content')}>
329+
Set light
330+
</RNTesterButton>
331+
<RNTesterButton
332+
onPress={() => StatusBar.setBarStyle('dark-content')}>
333+
Set dark
334+
</RNTesterButton>
335+
<RNTesterButton onPress={() => StatusBar.setHidden(true)}>
336+
Hide
337+
</RNTesterButton>
338+
<RNTesterButton onPress={() => StatusBar.setHidden(false)}>
339+
Show
340+
</RNTesterButton>
341+
</View>
315342
{controls}
316343
</View>
317344
</View>

0 commit comments

Comments
 (0)