77
88package com.facebook.react.modules.statusbar
99
10- import android.view.Window
11- import androidx.core.view.ViewCompat
12- import androidx.core.view.WindowCompat
13- import androidx.core.view.WindowInsetsCompat
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
1416import com.facebook.common.logging.FLog
1517import com.facebook.fbreact.specs.NativeStatusBarManagerAndroidSpec
16- import com.facebook.react.bridge.ExtraWindowEventListener
18+ import com.facebook.react.bridge.GuardedRunnable
1719import com.facebook.react.bridge.NativeModule
1820import com.facebook.react.bridge.ReactApplicationContext
1921import com.facebook.react.bridge.UiThreadUtil
@@ -22,44 +24,13 @@ import com.facebook.react.module.annotations.ReactModule
2224import com.facebook.react.uimanager.DisplayMetricsHolder.getStatusBarHeightPx
2325import com.facebook.react.uimanager.PixelUtil
2426import 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), 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- }
33+ NativeStatusBarManagerAndroidSpec (reactContext) {
6334
6435 @Suppress(" DEPRECATION" )
6536 override fun getTypedExportedConstants (): Map <String , Any > {
@@ -74,6 +45,7 @@ internal class StatusBarModule(reactContext: ReactApplicationContext?) :
7445 )
7546 }
7647
48+ @Suppress(" DEPRECATION" )
7749 override fun setColor (colorDouble : Double , animated : Boolean ) {
7850 val color = colorDouble.toInt()
7951 val activity = reactApplicationContext.getCurrentActivity()
@@ -91,7 +63,25 @@ internal class StatusBarModule(reactContext: ReactApplicationContext?) :
9163 )
9264 return
9365 }
94- UiThreadUtil .runOnUiThread { activity.window?.setStatusBarColor(color, animated) }
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+ )
9585 }
9686
9787 override fun setTranslucent (translucent : Boolean ) {
@@ -110,7 +100,13 @@ internal class StatusBarModule(reactContext: ReactApplicationContext?) :
110100 )
111101 return
112102 }
113- UiThreadUtil .runOnUiThread { activity.window?.setStatusBarTranslucency(translucent) }
103+ UiThreadUtil .runOnUiThread(
104+ object : GuardedRunnable (reactApplicationContext) {
105+ override fun runGuarded () {
106+ activity.window?.setStatusBarTranslucency(translucent)
107+ }
108+ }
109+ )
114110 }
115111
116112 override fun setHidden (hidden : Boolean ) {
@@ -122,12 +118,10 @@ internal class StatusBarModule(reactContext: ReactApplicationContext?) :
122118 )
123119 return
124120 }
125- UiThreadUtil .runOnUiThread {
126- activity.window?.setStatusBarVisibility(hidden)
127- extraWindows.forEach { it.setStatusBarVisibility(hidden) }
128- }
121+ UiThreadUtil .runOnUiThread { activity.window?.setStatusBarVisibility(hidden) }
129122 }
130123
124+ @Suppress(" DEPRECATION" )
131125 override fun setStyle (style : String? ) {
132126 val activity = reactApplicationContext.getCurrentActivity()
133127 if (activity == null ) {
@@ -137,10 +131,36 @@ internal class StatusBarModule(reactContext: ReactApplicationContext?) :
137131 )
138132 return
139133 }
140- UiThreadUtil .runOnUiThread {
141- activity.window?.setStatusBarStyle(style)
142- extraWindows.forEach { it.setStatusBarStyle(style) }
143- }
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+ )
144164 }
145165
146166 companion object {
0 commit comments