Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions android/app/src/main/res/values-v26/styles.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,12 @@
<!-- App Theme for Android 8.0 and above -->
<style name="AppTheme" parent="BaseAppTheme">
<item name="android:autofilledHighlight">@android:color/transparent</item>
<item name="android:navigationBarColor">@android:color/transparent</item>
<item name="android:windowBackground">@android:color/transparent</item>
<item name="android:windowDrawsSystemBarBackgrounds">true</item>
<item name="android:windowNoTitle">true</item>
<item name="android:windowIsFloating">false</item>
<item name="android:statusBarColor">@android:color/transparent</item>
</style>

</resources>
2 changes: 1 addition & 1 deletion android/app/src/main/res/values-v29/styles.xml
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="Theme.FullScreenDialog">
<item name="android:windowNoTitle">true</item>
Expand All @@ -7,5 +6,6 @@
<item name="android:windowDrawsSystemBarBackgrounds">true</item>
<item name="android:statusBarColor">@android:color/transparent</item>
<item name="android:enforceNavigationBarContrast">false</item>
<item name="android:navigationBarColor">@android:color/transparent</item>
</style>
</resources>
10 changes: 10 additions & 0 deletions android/app/src/main/res/values-v31/styles.xml
Original file line number Diff line number Diff line change
@@ -1,4 +1,14 @@
<resources>
<style name="AppTheme" parent="BaseAppTheme">
<item name="android:autofilledHighlight">@android:color/transparent</item>
<item name="android:navigationBarColor">@android:color/transparent</item>
<item name="android:windowBackground">@android:color/transparent</item>
<item name="android:windowDrawsSystemBarBackgrounds">true</item>
<item name="android:windowNoTitle">true</item>
<item name="android:windowIsFloating">false</item>
<item name="android:statusBarColor">@android:color/transparent</item>
<item name="android:enforceNavigationBarContrast">false</item>
</style>

<!-- Android 12 lets us clips the ripple at the outline, so we do that rather than inset -->
<style name="AppTheme.Popup" parent="Base.ThemeOverlay.AppCompat">
Expand Down
Original file line number Diff line number Diff line change
@@ -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) {
Loading