From be7ec70005c2e3933bba9e4cfd5f24150ba4ff06 Mon Sep 17 00:00:00 2001 From: Mathieu Acthernoene Date: Wed, 11 Mar 2026 13:49:15 +0100 Subject: [PATCH 1/2] Fix measureInWindow on Android --- .../react/runtime/ReactSurfaceView.kt | 18 ++++++++++++++ .../facebook/react/uimanager/RootViewUtil.kt | 24 +++++++++++++------ 2 files changed, 35 insertions(+), 7 deletions(-) diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/runtime/ReactSurfaceView.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/runtime/ReactSurfaceView.kt index 1ab36cda87df..79011ddc807c 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/runtime/ReactSurfaceView.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/runtime/ReactSurfaceView.kt @@ -15,6 +15,8 @@ import android.graphics.Rect import android.view.KeyEvent import android.view.MotionEvent import android.view.View +import androidx.core.view.ViewCompat +import androidx.core.view.WindowInsetsCompat import com.facebook.common.logging.FLog import com.facebook.react.ReactRootView import com.facebook.react.bridge.ReactContext @@ -27,6 +29,7 @@ import com.facebook.react.uimanager.JSKeyDispatcher import com.facebook.react.uimanager.JSPointerDispatcher import com.facebook.react.uimanager.JSTouchDispatcher import com.facebook.react.uimanager.common.UIManagerType +import com.facebook.react.views.view.isEdgeToEdgeFeatureFlagOn import com.facebook.systrace.Systrace import java.util.Objects import kotlin.math.max @@ -56,6 +59,21 @@ public class ReactSurfaceView(context: Context?, internal val surface: ReactSurf getWindowVisibleDisplayFrame(visibleWindowFrame) locationOnScreen[0] -= visibleWindowFrame.left locationOnScreen[1] -= visibleWindowFrame.top + + if (isEdgeToEdgeFeatureFlagOn) { + // In edge-to-edge mode the viewport spans the full window, so add the top system bar + // insets back to convert the content-area offset above into a window-relative offset. + ViewCompat.getRootWindowInsets(this)?.apply { + val insets = + getInsets( + WindowInsetsCompat.Type.statusBars() or WindowInsetsCompat.Type.displayCutout() + ) + + locationOnScreen[0] += insets.left + locationOnScreen[1] += insets.top + } + } + return Point(locationOnScreen[0], locationOnScreen[1]) } diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/RootViewUtil.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/RootViewUtil.kt index 2dc7c22624cd..1894f9d2e1ec 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/RootViewUtil.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/RootViewUtil.kt @@ -8,10 +8,12 @@ package com.facebook.react.uimanager import android.graphics.Point -import android.graphics.Rect import android.view.View import androidx.annotation.UiThread +import androidx.core.view.ViewCompat +import androidx.core.view.WindowInsetsCompat import com.facebook.infer.annotation.Assertions +import com.facebook.react.views.view.isEdgeToEdgeFeatureFlagOn public object RootViewUtil { /** Returns the root view of a given view in a react application. */ @@ -34,12 +36,20 @@ public object RootViewUtil { val locationInWindow = IntArray(2) v.getLocationInWindow(locationInWindow) - // we need to subtract visibleWindowCoords - to subtract possible window insets, split - // screen or multi window - val visibleWindowFrame = Rect() - v.getWindowVisibleDisplayFrame(visibleWindowFrame) - locationInWindow[0] -= visibleWindowFrame.left - locationInWindow[1] -= visibleWindowFrame.top + if (!isEdgeToEdgeFeatureFlagOn) { + // When not in edge-to-edge mode, subtract the top system bar insets so the offset is + // relative to the content area (below the status bar / cutout). + ViewCompat.getRootWindowInsets(v)?.apply { + val insets = + getInsets( + WindowInsetsCompat.Type.statusBars() or WindowInsetsCompat.Type.displayCutout() + ) + + locationInWindow[0] -= insets.left + locationInWindow[1] -= insets.top + } + } + return Point(locationInWindow[0], locationInWindow[1]) } } From d0ea897ee33f4560c95591560fc34e32d4923078 Mon Sep 17 00:00:00 2001 From: Mathieu Acthernoene Date: Fri, 17 Apr 2026 13:35:42 +0200 Subject: [PATCH 2/2] Use locationInWindow --- .../react/runtime/ReactSurfaceView.kt | 23 +++++++------------ 1 file changed, 8 insertions(+), 15 deletions(-) diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/runtime/ReactSurfaceView.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/runtime/ReactSurfaceView.kt index 79011ddc807c..9d62d7917a13 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/runtime/ReactSurfaceView.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/runtime/ReactSurfaceView.kt @@ -50,31 +50,24 @@ public class ReactSurfaceView(context: Context?, internal val surface: ReactSurf private val viewportOffset: Point get() { - val locationOnScreen = IntArray(2) - getLocationOnScreen(locationOnScreen) + val locationInWindow = IntArray(2) + getLocationInWindow(locationInWindow) - // we need to subtract visibleWindowCoords - to subtract possible window insets, split - // screen or multi window - val visibleWindowFrame = Rect() - getWindowVisibleDisplayFrame(visibleWindowFrame) - locationOnScreen[0] -= visibleWindowFrame.left - locationOnScreen[1] -= visibleWindowFrame.top - - if (isEdgeToEdgeFeatureFlagOn) { - // In edge-to-edge mode the viewport spans the full window, so add the top system bar - // insets back to convert the content-area offset above into a window-relative offset. + if (!isEdgeToEdgeFeatureFlagOn) { + // When not in edge-to-edge mode, subtract the top system bar insets so the offset is + // relative to the content area (below the status bar / cutout). ViewCompat.getRootWindowInsets(this)?.apply { val insets = getInsets( WindowInsetsCompat.Type.statusBars() or WindowInsetsCompat.Type.displayCutout() ) - locationOnScreen[0] += insets.left - locationOnScreen[1] += insets.top + locationInWindow[0] -= insets.left + locationInWindow[1] -= insets.top } } - return Point(locationOnScreen[0], locationOnScreen[1]) + return Point(locationInWindow[0], locationInWindow[1]) } init {