77
88package com.facebook.react.modules.statusbar
99
10- import android.animation.ArgbEvaluator
11- import android.animation.ValueAnimator
12- import android.os.Build
13- import android.view.View
14- import android.view.WindowInsetsController
15- import android.view.WindowManager
10+ import android.view.Window
11+ import androidx.core.view.ViewCompat
12+ import androidx.core.view.WindowCompat
13+ import androidx.core.view.WindowInsetsCompat
1614import com.facebook.common.logging.FLog
1715import com.facebook.fbreact.specs.NativeStatusBarManagerAndroidSpec
18- import com.facebook.react.bridge.GuardedRunnable
16+ import com.facebook.react.bridge.ExtraWindowEventListener
1917import com.facebook.react.bridge.NativeModule
2018import com.facebook.react.bridge.ReactApplicationContext
2119import com.facebook.react.bridge.UiThreadUtil
@@ -24,13 +22,44 @@ import com.facebook.react.module.annotations.ReactModule
2422import com.facebook.react.uimanager.DisplayMetricsHolder.getStatusBarHeightPx
2523import com.facebook.react.uimanager.PixelUtil
2624import com.facebook.react.views.view.isEdgeToEdgeFeatureFlagOn
25+ import com.facebook.react.views.view.setStatusBarColor
26+ import com.facebook.react.views.view.setStatusBarStyle
2727import com.facebook.react.views.view.setStatusBarTranslucency
2828import com.facebook.react.views.view.setStatusBarVisibility
2929
3030/* * [NativeModule] that allows changing the appearance of the status bar. */
3131@ReactModule(name = NativeStatusBarManagerAndroidSpec .NAME )
3232internal class StatusBarModule (reactContext : ReactApplicationContext ? ) :
33- NativeStatusBarManagerAndroidSpec (reactContext) {
33+ NativeStatusBarManagerAndroidSpec (reactContext), ExtraWindowEventListener {
34+
35+ private val extraWindows = mutableSetOf<Window >()
36+
37+ init {
38+ reactApplicationContext.addExtraWindowEventListener(this )
39+ }
40+
41+ override fun invalidate () {
42+ super .invalidate()
43+ reactApplicationContext.removeExtraWindowEventListener(this )
44+ }
45+
46+ override fun onExtraWindowCreate (window : Window ) {
47+ extraWindows.add(window)
48+
49+ UiThreadUtil .runOnUiThread {
50+ val controller = WindowCompat .getInsetsController(window, window.decorView)
51+ val insets = ViewCompat .getRootWindowInsets(window.decorView)
52+ val style = if (controller.isAppearanceLightStatusBars) " dark-content" else " light-content"
53+ val visible = insets?.isVisible(WindowInsetsCompat .Type .statusBars()) ? : true
54+
55+ window.setStatusBarStyle(style)
56+ window.setStatusBarVisibility(! visible)
57+ }
58+ }
59+
60+ override fun onExtraWindowDestroy (window : Window ) {
61+ extraWindows.remove(window)
62+ }
3463
3564 @Suppress(" DEPRECATION" )
3665 override fun getTypedExportedConstants (): Map <String , Any > {
@@ -45,7 +74,6 @@ internal class StatusBarModule(reactContext: ReactApplicationContext?) :
4574 )
4675 }
4776
48- @Suppress(" DEPRECATION" )
4977 override fun setColor (colorDouble : Double , animated : Boolean ) {
5078 val color = colorDouble.toInt()
5179 val activity = reactApplicationContext.getCurrentActivity()
@@ -63,25 +91,7 @@ internal class StatusBarModule(reactContext: ReactApplicationContext?) :
6391 )
6492 return
6593 }
66- UiThreadUtil .runOnUiThread(
67- object : GuardedRunnable (reactApplicationContext) {
68- override fun runGuarded () {
69- val window = activity.window ? : return
70- window.addFlags(WindowManager .LayoutParams .FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS )
71- if (animated) {
72- val curColor = window.statusBarColor
73- val colorAnimation = ValueAnimator .ofObject(ArgbEvaluator (), curColor, color)
74- colorAnimation.addUpdateListener { animator ->
75- activity.window?.statusBarColor = (animator.animatedValue as Int )
76- }
77- colorAnimation.setDuration(300 ).startDelay = 0
78- colorAnimation.start()
79- } else {
80- window.statusBarColor = color
81- }
82- }
83- }
84- )
94+ UiThreadUtil .runOnUiThread { activity.window?.setStatusBarColor(color, animated) }
8595 }
8696
8797 override fun setTranslucent (translucent : Boolean ) {
@@ -100,13 +110,7 @@ internal class StatusBarModule(reactContext: ReactApplicationContext?) :
100110 )
101111 return
102112 }
103- UiThreadUtil .runOnUiThread(
104- object : GuardedRunnable (reactApplicationContext) {
105- override fun runGuarded () {
106- activity.window?.setStatusBarTranslucency(translucent)
107- }
108- }
109- )
113+ UiThreadUtil .runOnUiThread { activity.window?.setStatusBarTranslucency(translucent) }
110114 }
111115
112116 override fun setHidden (hidden : Boolean ) {
@@ -118,10 +122,12 @@ internal class StatusBarModule(reactContext: ReactApplicationContext?) :
118122 )
119123 return
120124 }
121- UiThreadUtil .runOnUiThread { activity.window?.setStatusBarVisibility(hidden) }
125+ UiThreadUtil .runOnUiThread {
126+ activity.window?.setStatusBarVisibility(hidden)
127+ extraWindows.forEach { it.setStatusBarVisibility(hidden) }
128+ }
122129 }
123130
124- @Suppress(" DEPRECATION" )
125131 override fun setStyle (style : String? ) {
126132 val activity = reactApplicationContext.getCurrentActivity()
127133 if (activity == null ) {
@@ -131,36 +137,10 @@ internal class StatusBarModule(reactContext: ReactApplicationContext?) :
131137 )
132138 return
133139 }
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- )
140+ UiThreadUtil .runOnUiThread {
141+ activity.window?.setStatusBarStyle(style)
142+ extraWindows.forEach { it.setStatusBarStyle(style) }
143+ }
164144 }
165145
166146 companion object {
0 commit comments