From e6617acef87390bb92a8f41f320a4fea15619116 Mon Sep 17 00:00:00 2001 From: Shubham Agrawal Date: Mon, 11 May 2026 19:15:09 +0530 Subject: [PATCH 1/2] fix: Navigation bar translucency on Android --- .../app/src/main/res/values-v29/styles.xml | 1 + ...fix-modal-transparent-navigation-bar.patch | 135 +++++++++++++++--- 2 files changed, 118 insertions(+), 18 deletions(-) diff --git a/android/app/src/main/res/values-v29/styles.xml b/android/app/src/main/res/values-v29/styles.xml index 24a6c3efcc6f..338f3adae109 100644 --- a/android/app/src/main/res/values-v29/styles.xml +++ b/android/app/src/main/res/values-v29/styles.xml @@ -7,5 +7,6 @@ true @android:color/transparent false + @android:color/transparent \ No newline at end of file diff --git a/patches/react-native/react-native+0.83.1+022+fix-modal-transparent-navigation-bar.patch b/patches/react-native/react-native+0.83.1+022+fix-modal-transparent-navigation-bar.patch index 966af101c2fa..196d9a5c13df 100644 --- a/patches/react-native/react-native+0.83.1+022+fix-modal-transparent-navigation-bar.patch +++ b/patches/react-native/react-native+0.83.1+022+fix-modal-transparent-navigation-bar.patch @@ -1,25 +1,124 @@ diff --git a/node_modules/react-native/ReactAndroid/src/main/java/com/facebook/react/views/modal/ReactModalHostView.kt b/node_modules/react-native/ReactAndroid/src/main/java/com/facebook/react/views/modal/ReactModalHostView.kt -index c711027..7255545 100644 +index 994d4ce..a7c9f34 100644 --- a/node_modules/react-native/ReactAndroid/src/main/java/com/facebook/react/views/modal/ReactModalHostView.kt +++ b/node_modules/react-native/ReactAndroid/src/main/java/com/facebook/react/views/modal/ReactModalHostView.kt -@@ -382,6 +382,20 @@ public class ReactModalHostView(context: ThemedReactContext) : - } - } +@@ -18,6 +18,7 @@ import android.os.Build + import android.view.KeyEvent + import android.view.MotionEvent + import android.view.View ++import android.view.WindowInsetsController + import android.view.ViewGroup + import android.view.ViewStructure + import android.view.WindowManager +@@ -340,6 +341,8 @@ public class ReactModalHostView(context: ThemedReactContext) : + if (currentActivity?.isFinishing == false) { + newDialog.show() + updateSystemAppearance() ++ // Activity and dialog insets can settle after attach; re-sync so nav icon style matches. ++ window.decorView.post { updateSystemAppearance() } + window.clearFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE) + } + } +@@ -388,7 +391,18 @@ public class ReactModalHostView(context: ThemedReactContext) : -+ // If enforceNavigationBarContrast is explicitly set in the app theme (AppTheme), -+ // we need to override the default behaviour for edge-to-edge mode in WindowUtils.setSystemBarsTranslucency. -+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { -+ val attrs = intArrayOf(android.R.attr.enforceNavigationBarContrast) -+ val ta = context.obtainStyledAttributes(R.style.Theme_FullScreenDialog, attrs) -+ -+ if (ta.length() == 1) { -+ val enforceNavigationBarContrastStyleValue = ta.getBoolean(0, false) -+ dialogWindow.isNavigationBarContrastEnforced = enforceNavigationBarContrastStyleValue + // Navigation bar cannot be translucent without status bar being translucent too + if (navigationBarTranslucent) { +- dialogWindow.enableEdgeToEdge() ++ // Do not set nav icon appearance from UI mode here; it overrides the activity and is ++ // re-applied every updateProperties() while the dialog is open without showOrUpdate(). ++ dialogWindow.enableEdgeToEdge(applyNavigationBarIconAppearanceFromUiMode = false) ++ if (activityWindow != null) { ++ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { ++ dialogWindow.isStatusBarContrastEnforced = activityWindow.isStatusBarContrastEnforced ++ dialogWindow.isNavigationBarContrastEnforced = ++ activityWindow.isNavigationBarContrastEnforced ++ } ++ dialogWindow.statusBarColor = activityWindow.statusBarColor ++ dialogWindow.navigationBarColor = activityWindow.navigationBarColor + } + } else { + dialogWindow.disableEdgeToEdge() + dialogWindow.setStatusBarTranslucency(statusBarTranslucent) +@@ -409,6 +423,10 @@ public class ReactModalHostView(context: ThemedReactContext) : + // window manager + FLog.e(TAG, "ReactModalHostView: error while setting window flags: ", e.message) + } + -+ ta.recycle() ++ if (dialog.isShowing) { ++ updateSystemAppearance() ++ } + } + + /** +@@ -435,8 +453,21 @@ public class ReactModalHostView(context: ThemedReactContext) : + WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE + } + +- dialogWindowInsetsController.isAppearanceLightStatusBars = +- activityWindowInsetsController.isAppearanceLightStatusBars ++ val activityNativeInsetsController = activityWindow.insetsController ++ val dialogNativeInsetsController = dialogWindow.insetsController ++ if (activityNativeInsetsController != null && dialogNativeInsetsController != null) { ++ val appearanceMask = ++ WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS or ++ WindowInsetsController.APPEARANCE_LIGHT_NAVIGATION_BARS ++ val activityAppearance = ++ activityNativeInsetsController.systemBarsAppearance and appearanceMask ++ dialogNativeInsetsController.setSystemBarsAppearance(activityAppearance, appearanceMask) ++ } else { ++ dialogWindowInsetsController.isAppearanceLightStatusBars = ++ activityWindowInsetsController.isAppearanceLightStatusBars ++ dialogWindowInsetsController.isAppearanceLightNavigationBars = ++ activityWindowInsetsController.isAppearanceLightNavigationBars + } -+ - // Navigation bar cannot be translucent without status bar being translucent too - if (navigationBarTranslucent) { - dialogWindow.enableEdgeToEdge() + + activityWindow.decorView.rootWindowInsets?.let { insets -> + val activityRootWindowInsets = WindowInsetsCompat.toWindowInsetsCompat(insets) +diff --git a/node_modules/react-native/ReactAndroid/src/main/java/com/facebook/react/views/view/WindowUtil.kt b/node_modules/react-native/ReactAndroid/src/main/java/com/facebook/react/views/view/WindowUtil.kt +index 0cff3bc..a679c33 100644 +--- a/node_modules/react-native/ReactAndroid/src/main/java/com/facebook/react/views/view/WindowUtil.kt ++++ b/node_modules/react-native/ReactAndroid/src/main/java/com/facebook/react/views/view/WindowUtil.kt +@@ -16,6 +16,7 @@ import androidx.core.view.WindowCompat + import androidx.core.view.WindowInsetsCompat + import androidx.core.view.WindowInsetsControllerCompat + import com.facebook.react.views.common.UiModeUtils ++import kotlin.jvm.JvmOverloads + + // The light scrim color used in the platform API 29+ + // https://cs.android.com/android/platform/superproject/+/master:frameworks/base/core/java/com/android/internal/policy/DecorView.java;drc=6ef0f022c333385dba2c294e35b8de544455bf19;l=142 +@@ -103,14 +104,19 @@ private fun Window.statusBarShow() { + } + + @Suppress("DEPRECATION") +-internal fun Window.enableEdgeToEdge() { ++@JvmOverloads ++internal fun Window.enableEdgeToEdge(applyNavigationBarIconAppearanceFromUiMode: Boolean = true) { + WindowCompat.setDecorFitsSystemWindows(this, false) + + val isDarkMode = UiModeUtils.isDarkMode(context) + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { + isStatusBarContrastEnforced = false +- isNavigationBarContrastEnforced = true ++ // Respect app theme so android:enforceNavigationBarContrast is applied (e.g. false for transparent nav bar). ++ val contrastAttrs = intArrayOf(android.R.attr.enforceNavigationBarContrast) ++ val ta = context.theme.obtainStyledAttributes(contrastAttrs) ++ isNavigationBarContrastEnforced = if (ta.length() == 1) ta.getBoolean(0, false) else false ++ ta.recycle() + } + + statusBarColor = Color.TRANSPARENT +@@ -121,8 +127,11 @@ internal fun Window.enableEdgeToEdge() { + else -> DarkNavigationBarColor + } + +- WindowInsetsControllerCompat(this, decorView).run { +- isAppearanceLightNavigationBars = !isDarkMode ++ // Modal windows should not force UI-mode-based nav icons; they sync from the activity instead. ++ if (applyNavigationBarIconAppearanceFromUiMode) { ++ WindowInsetsControllerCompat(this, decorView).run { ++ isAppearanceLightNavigationBars = !isDarkMode ++ } + } + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { \ No newline at end of file From 5893d800d73c3ff89c0f5673a59d28ac755c3b7a Mon Sep 17 00:00:00 2001 From: Shubham Agrawal Date: Mon, 11 May 2026 19:40:17 +0530 Subject: [PATCH 2/2] Experiment 1 --- android/app/src/main/res/values-v26/styles.xml | 6 ++++++ android/app/src/main/res/values-v29/styles.xml | 1 - android/app/src/main/res/values-v31/styles.xml | 10 ++++++++++ 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/android/app/src/main/res/values-v26/styles.xml b/android/app/src/main/res/values-v26/styles.xml index fbef3b91f60f..6a037e463a84 100644 --- a/android/app/src/main/res/values-v26/styles.xml +++ b/android/app/src/main/res/values-v26/styles.xml @@ -3,6 +3,12 @@ diff --git a/android/app/src/main/res/values-v29/styles.xml b/android/app/src/main/res/values-v29/styles.xml index 338f3adae109..ff8218f2e4d0 100644 --- a/android/app/src/main/res/values-v29/styles.xml +++ b/android/app/src/main/res/values-v29/styles.xml @@ -1,4 +1,3 @@ -