@@ -25,6 +25,7 @@ object SystemUiUtils {
2525 private const val THREE_BUTTON_NAV_BAR_OPACITY = 0.8f
2626
2727 private var statusBarBackgroundView: View ? = null
28+ private var statusBarBackgroundActivity: java.lang.ref.WeakReference <Activity >? = null
2829 private var navBarBackgroundView: View ? = null
2930 @JvmStatic
3031 var isEdgeToEdgeActive = false
@@ -69,11 +70,11 @@ object SystemUiUtils {
6970 * Initializes view-based system bar backgrounds for edge-to-edge.
7071 * Call from Activity.onPostCreate after the navigator content layout is set.
7172 *
72- * Status bar: reuses the system's android:id/statusBarBackground DecorView child.
73+ * Status bar: reuses the system's android:id/statusBarBackground DecorView child
74+ * when available. On API 35+ with EdgeToEdge, this view may not exist, so a
75+ * manual view is created in the content layout, sized by status bar insets.
7376 * Navigation bar: creates a view in [contentLayout] sized by WindowInsets,
7477 * since the system's navigationBarBackground is not available with EdgeToEdge.
75- *
76- * Both fall back to deprecated window APIs when the views are unavailable.
7778 */
7879 @JvmStatic
7980 fun setupSystemBarBackgrounds (activity : Activity , contentLayout : ViewGroup ) {
@@ -85,9 +86,35 @@ object SystemUiUtils {
8586 if (statusBarBackgroundView != null ) return
8687 val sbView = activity.window.decorView.findViewById<View >(android.R .id.statusBarBackground)
8788 if (sbView != null ) {
88- sbView.setBackgroundColor(Color .BLACK )
8989 statusBarBackgroundView = sbView
90+ } else {
91+ statusBarBackgroundActivity = java.lang.ref.WeakReference (activity)
92+ }
93+ }
94+
95+ private fun ensureStatusBarBackgroundView (): View ? {
96+ statusBarBackgroundView?.let { return it }
97+ val activity = statusBarBackgroundActivity?.get() ? : return null
98+ val contentLayout = activity.findViewById<ViewGroup >(android.R .id.content) ? : return null
99+ val view = View (activity)
100+ val params = FrameLayout .LayoutParams (
101+ FrameLayout .LayoutParams .MATCH_PARENT , 0 , Gravity .TOP
102+ )
103+ contentLayout.addView(view, params)
104+ statusBarBackgroundView = view
105+ statusBarBackgroundActivity = null
106+
107+ ViewCompat .setOnApplyWindowInsetsListener(view) { v, insets ->
108+ val sbHeight = insets.getInsets(WindowInsetsCompat .Type .statusBars()).top
109+ val lp = v.layoutParams
110+ if (lp.height != sbHeight) {
111+ lp.height = sbHeight
112+ v.layoutParams = lp
113+ }
114+ insets
90115 }
116+ view.requestApplyInsets()
117+ return view
91118 }
92119
93120 private fun setupNavigationBarBackground (contentLayout : ViewGroup ) {
@@ -131,6 +158,14 @@ object SystemUiUtils {
131158 return Color .argb(alpha, Color .red(DEFAULT_NAV_BAR_COLOR ), Color .green(DEFAULT_NAV_BAR_COLOR ), Color .blue(DEFAULT_NAV_BAR_COLOR ))
132159 }
133160
161+ /* *
162+ * Returns true when the system statusBarBackground view was not found during setup,
163+ * meaning a manual view will be lazily created on the first setStatusBarColor call.
164+ * Use this to decide whether to apply a theme-based initial status bar color.
165+ */
166+ @JvmStatic
167+ fun needsManualStatusBarBackground (): Boolean = statusBarBackgroundActivity != null
168+
134169 /* *
135170 * Marks edge-to-edge as active. Call after EdgeToEdge.enable() in the activity.
136171 * This flag controls whether navigation bar insets are forwarded to SafeAreaView
@@ -148,6 +183,7 @@ object SystemUiUtils {
148183 @JvmStatic
149184 fun tearDown () {
150185 statusBarBackgroundView = null
186+ statusBarBackgroundActivity = null
151187 navBarBackgroundView = null
152188 isEdgeToEdgeActive = false
153189 isThreeButtonNav = false
@@ -196,15 +232,26 @@ object SystemUiUtils {
196232 Color .green(color),
197233 Color .blue(color)
198234 )
199- setStatusBarColor (window, opaqueColor)
235+ applyStatusBarColor (window, opaqueColor)
200236 }
201237
202238 /* *
203- * Sets the status bar background color.
204- * Uses the view-based background when available (edge-to-edge),
205- * falls back to the deprecated window API on older configurations .
239+ * Sets the status bar background color, lazily creating a manual view on API 35+
240+ * if the system view wasn't available at setup time. Use this for explicit app-level
241+ * color requests (e.g. from MainActivity or NavigationActivity) .
206242 */
243+ @JvmStatic
207244 fun setStatusBarColor (window : Window ? , color : Int ) {
245+ val view = ensureStatusBarBackgroundView()
246+ if (view != null ) {
247+ view.setBackgroundColor(color)
248+ } else {
249+ @Suppress(" DEPRECATION" )
250+ window?.statusBarColor = color
251+ }
252+ }
253+
254+ private fun applyStatusBarColor (window : Window ? , color : Int ) {
208255 statusBarBackgroundView?.setBackgroundColor(color) ? : run {
209256 @Suppress(" DEPRECATION" )
210257 window?.statusBarColor = color
0 commit comments