From 3b8b08351291dd72f3f89a60af92cd1ad0baa34c Mon Sep 17 00:00:00 2001 From: Mathieu Acthernoene Date: Mon, 7 Jul 2025 23:30:53 -0700 Subject: [PATCH 1/2] Fix Dimensions window values on Android < 15 (#47554) Summary: This PR (initially created for edge-to-edge opt-in support, rebased multiple times) fixes the `Dimensions` API `window` values on Android < 15, when edge-to-edge is enabled. Currently the window height doesn't include the status and navigation bar heights (but it does on Android >= 15): Screenshot 2025-06-27 at 16 23 02 Using `WindowMetricsCalculator` from AndroidX: Screenshot 2025-06-27 at 16 34 01 Fixes https://github.com/facebook/react-native/issues/47080 ## Changelog: [Android] [Fixed] Fix `Dimensions` `window` values on Android < 15 when edge-to-edge is enabled Test Plan: Run the example app on an Android < 15 device. Rollback Plan: Differential Revision: D77906644 Pulled By: alanleedev --- .../react-native/ReactAndroid/build.gradle.kts | 1 + .../react/uimanager/DisplayMetricsHolder.kt | 16 +++++++++++++++- packages/react-native/gradle/libs.versions.toml | 2 ++ 3 files changed, 18 insertions(+), 1 deletion(-) diff --git a/packages/react-native/ReactAndroid/build.gradle.kts b/packages/react-native/ReactAndroid/build.gradle.kts index 1b3991d467933c..3208e4d832df3e 100644 --- a/packages/react-native/ReactAndroid/build.gradle.kts +++ b/packages/react-native/ReactAndroid/build.gradle.kts @@ -618,6 +618,7 @@ dependencies { api(libs.androidx.autofill) api(libs.androidx.swiperefreshlayout) api(libs.androidx.tracing) + api(libs.androidx.window) api(libs.fbjni) api(libs.fresco) diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/DisplayMetricsHolder.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/DisplayMetricsHolder.kt index 9f6c9310a690c4..994990b83c4acf 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/DisplayMetricsHolder.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/DisplayMetricsHolder.kt @@ -13,8 +13,10 @@ import android.util.DisplayMetrics import android.view.WindowManager import androidx.core.view.ViewCompat import androidx.core.view.WindowInsetsCompat +import androidx.window.layout.WindowMetricsCalculator import com.facebook.react.bridge.WritableMap import com.facebook.react.bridge.WritableNativeMap +import com.facebook.react.views.view.isEdgeToEdgeFeatureFlagOn /** * Holds an instance of the current DisplayMetrics so we don't have to thread it through all the @@ -62,9 +64,19 @@ public object DisplayMetricsHolder { @JvmStatic public fun initDisplayMetrics(context: Context) { val displayMetrics = context.resources.displayMetrics - windowDisplayMetrics = displayMetrics + val windowDisplayMetrics = DisplayMetrics() val screenDisplayMetrics = DisplayMetrics() + + windowDisplayMetrics.setTo(displayMetrics) screenDisplayMetrics.setTo(displayMetrics) + + if (isEdgeToEdgeFeatureFlagOn) { + WindowMetricsCalculator.getOrCreate().computeCurrentWindowMetrics(context).let { + windowDisplayMetrics.widthPixels = it.bounds.width() + windowDisplayMetrics.heightPixels = it.bounds.height() + } + } + val wm = context.getSystemService(Context.WINDOW_SERVICE) as WindowManager // Get the real display metrics if we are using API level 17 or higher. // The real metrics include system decor elements (e.g. soft menu bar). @@ -72,6 +84,8 @@ public object DisplayMetricsHolder { // See: // http://developer.android.com/reference/android/view/Display.html#getRealMetrics(android.util.DisplayMetrics) @Suppress("DEPRECATION") wm.defaultDisplay.getRealMetrics(screenDisplayMetrics) + + DisplayMetricsHolder.windowDisplayMetrics = windowDisplayMetrics DisplayMetricsHolder.screenDisplayMetrics = screenDisplayMetrics } diff --git a/packages/react-native/gradle/libs.versions.toml b/packages/react-native/gradle/libs.versions.toml index f0902b7441de85..db117f7dfc8b7d 100644 --- a/packages/react-native/gradle/libs.versions.toml +++ b/packages/react-native/gradle/libs.versions.toml @@ -16,6 +16,7 @@ androidx-swiperefreshlayout = "1.1.0" androidx-test = "1.5.0" androidx-test-junit = "1.2.1" androidx-tracing = "1.1.0" +androidx-window = "1.4.0" assertj = "3.21.0" binary-compatibility-validator = "0.13.2" download = "5.4.0" @@ -63,6 +64,7 @@ androidx-test-rules = { module = "androidx.test:rules", version.ref = "androidx- androidx-test-runner = { module = "androidx.test:runner", version.ref = "androidx-test" } androidx-tracing = { module = "androidx.tracing:tracing", version.ref = "androidx-tracing" } androidx-uiautomator = { group = "androidx.test.uiautomator", name = "uiautomator", version.ref = "uiautomator" } +androidx-window = { module = "androidx.window:window", version.ref = "androidx-window" } fbjni = { module = "com.facebook.fbjni:fbjni", version.ref = "fbjni" } fresco = { module = "com.facebook.fresco:fresco", version.ref = "fresco" } From 7565ebadc199f36508604d1af6ab85a17e4bd768 Mon Sep 17 00:00:00 2001 From: Mathieu Acthernoene Date: Mon, 14 Jul 2025 17:45:53 +0200 Subject: [PATCH 2/2] Use UI context to init display metrics --- .../src/main/java/com/facebook/react/ReactRootView.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/ReactRootView.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/ReactRootView.java index 6c625367010a9a..e421de963ef7c4 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/ReactRootView.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/ReactRootView.java @@ -865,7 +865,7 @@ private class CustomGlobalLayoutListener implements ViewTreeObserver.OnGlobalLay private int mDeviceRotation = 0; /* package */ CustomGlobalLayoutListener() { - DisplayMetricsHolder.initDisplayMetricsIfNotInitialized(getContext().getApplicationContext()); + DisplayMetricsHolder.initDisplayMetricsIfNotInitialized(getContext()); mVisibleViewArea = new Rect(); mMinKeyboardHeightDetected = (int) PixelUtil.toPixelFromDIP(60); } @@ -988,7 +988,7 @@ private void checkForDeviceOrientationChanges() { return; } mDeviceRotation = rotation; - DisplayMetricsHolder.initDisplayMetrics(getContext().getApplicationContext()); + DisplayMetricsHolder.initDisplayMetrics(getContext()); emitOrientationChanged(rotation); }