From 78b42d7fb7180102c1e8ec917dcccd2d9d4076db Mon Sep 17 00:00:00 2001 From: Joshua Gross Date: Fri, 11 Sep 2020 13:40:56 -0700 Subject: [PATCH] Take viewport offset into account in UIManager.measureInWindow Summary: D23021903 (https://github.com/facebook/react-native/commit/154ce789723f6e65785bcfc00da399ad9184bdfb) but for Android. Changelog: [Internal] Reviewed By: sammy-SC Differential Revision: D23640968 fbshipit-source-id: 7a743ebd0ea2b573d6ef17b418ad98ec616b11d3 --- .../com/facebook/react/ReactRootView.java | 34 +++++++++++++++++-- .../com/facebook/react/bridge/UIManager.java | 5 +-- .../com/facebook/react/fabric/Binding.java | 4 +++ .../react/fabric/FabricUIManager.java | 15 +++++++- .../com/facebook/react/fabric/jni/Binding.cpp | 8 +++++ .../com/facebook/react/fabric/jni/Binding.h | 4 +++ .../react/uimanager/UIManagerModule.java | 8 +++-- 7 files changed, 71 insertions(+), 7 deletions(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/ReactRootView.java b/ReactAndroid/src/main/java/com/facebook/react/ReactRootView.java index 45049cb5a65..2af6a23fbd9 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/ReactRootView.java +++ b/ReactAndroid/src/main/java/com/facebook/react/ReactRootView.java @@ -14,6 +14,7 @@ import static com.facebook.systrace.Systrace.TRACE_TAG_REACT_JAVA_BRIDGE; import android.content.Context; import android.graphics.Canvas; +import android.graphics.Point; import android.graphics.Rect; import android.os.Bundle; import android.util.AttributeSet; @@ -291,7 +292,12 @@ public class ReactRootView extends FrameLayout implements RootView, ReactRoot { @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { - // No-op since UIManagerModule handles actually laying out children. + // No-op in non-Fabric since UIManagerModule handles actually laying out children. + + // In Fabric, update LayoutSpecs just so we update the offsetX and offsetY. + if (mWasMeasured && getUIManagerType() == FABRIC) { + updateRootLayoutSpecs(mWidthMeasureSpec, mHeightMeasureSpec); + } } @Override @@ -405,6 +411,20 @@ public class ReactRootView extends FrameLayout implements RootView, ReactRoot { return appProperties != null ? appProperties.getString("surfaceID") : null; } + public static Point getViewportOffset(View v) { + int[] locationInWindow = new int[2]; + v.getLocationInWindow(locationInWindow); + + // we need to subtract visibleWindowCoords - to subtract possible window insets, split + // screen or multi window + Rect visibleWindowFrame = new Rect(); + v.getWindowVisibleDisplayFrame(visibleWindowFrame); + locationInWindow[0] -= visibleWindowFrame.left; + locationInWindow[1] -= visibleWindowFrame.top; + + return new Point(locationInWindow[0], locationInWindow[1]); + } + private void updateRootLayoutSpecs(final int widthMeasureSpec, final int heightMeasureSpec) { if (mReactInstanceManager == null) { FLog.w(TAG, "Unable to update root layout specs for uninitialized ReactInstanceManager"); @@ -418,7 +438,17 @@ public class ReactRootView extends FrameLayout implements RootView, ReactRoot { UIManagerHelper.getUIManager(reactApplicationContext, getUIManagerType()); // Ignore calling updateRootLayoutSpecs if UIManager is not properly initialized. if (uiManager != null) { - uiManager.updateRootLayoutSpecs(getRootViewTag(), widthMeasureSpec, heightMeasureSpec); + // In Fabric only, get position of view within screen + int offsetX = 0; + int offsetY = 0; + if (getUIManagerType() == FABRIC) { + Point viewportOffset = getViewportOffset(this); + offsetX = viewportOffset.x; + offsetY = viewportOffset.y; + } + + uiManager.updateRootLayoutSpecs( + getRootViewTag(), widthMeasureSpec, heightMeasureSpec, offsetX, offsetY); } } } diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/UIManager.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/UIManager.java index 0bd6a2c649a..74af261f5b4 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/bridge/UIManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/UIManager.java @@ -41,11 +41,12 @@ public interface UIManager extends JSIModule, PerformanceCounter { /** * Updates the layout specs of the RootShadowNode based on the Measure specs received by - * parameters. + * parameters. offsetX and offsetY are the position of the RootView within the screen. */ @UiThread @ThreadConfined(UI) - void updateRootLayoutSpecs(int rootTag, int widthMeasureSpec, int heightMeasureSpec); + void updateRootLayoutSpecs( + int rootTag, int widthMeasureSpec, int heightMeasureSpec, int offsetX, int offsetY); /** * Dispatches the commandId received by parameter to the view associated with the reactTag. The diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/Binding.java b/ReactAndroid/src/main/java/com/facebook/react/fabric/Binding.java index cbe49ce51d2..ea080bd4e07 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/Binding.java +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/Binding.java @@ -52,6 +52,8 @@ public class Binding { float maxWidth, float minHeight, float maxHeight, + float offsetX, + float offsetY, boolean isRTL, boolean doLeftAndRightSwapInRTL); @@ -67,6 +69,8 @@ public class Binding { float maxWidth, float minHeight, float maxHeight, + float offsetX, + float offsetY, boolean isRTL, boolean doLeftAndRightSwapInRTL); diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java b/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java index 740809e39ea..bf95f6e7da3 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java @@ -22,6 +22,7 @@ import static com.facebook.react.uimanager.common.UIManagerType.FABRIC; import android.annotation.SuppressLint; import android.content.Context; +import android.graphics.Point; import android.os.SystemClock; import android.view.View; import androidx.annotation.AnyThread; @@ -34,6 +35,7 @@ import com.facebook.debug.holder.PrinterHolder; import com.facebook.debug.tags.ReactDebugOverlayTags; import com.facebook.infer.annotation.ThreadConfined; import com.facebook.proguard.annotations.DoNotStrip; +import com.facebook.react.ReactRootView; import com.facebook.react.bridge.LifecycleEventListener; import com.facebook.react.bridge.NativeMap; import com.facebook.react.bridge.ReactApplicationContext; @@ -230,6 +232,9 @@ public class FabricUIManager implements UIManager, LifecycleEventListener { } mMountingManager.addRootView(rootTag, rootView); mReactContextForRootTag.put(rootTag, reactContext); + + Point viewportOffset = ReactRootView.getViewportOffset(rootView); + mBinding.startSurfaceWithConstraints( rootTag, moduleName, @@ -238,6 +243,8 @@ public class FabricUIManager implements UIManager, LifecycleEventListener { getMaxSize(widthMeasureSpec), getMinSize(heightMeasureSpec), getMaxSize(heightMeasureSpec), + viewportOffset.x, + viewportOffset.y, I18nUtil.getInstance().isRTL(context), I18nUtil.getInstance().doLeftAndRightSwapInRTL(context)); return rootTag; @@ -957,7 +964,11 @@ public class FabricUIManager implements UIManager, LifecycleEventListener { @UiThread @ThreadConfined(UI) public void updateRootLayoutSpecs( - final int rootTag, final int widthMeasureSpec, final int heightMeasureSpec) { + final int rootTag, + final int widthMeasureSpec, + final int heightMeasureSpec, + final int offsetX, + final int offsetY) { if (ENABLE_FABRIC_LOGS) { FLog.d(TAG, "Updating Root Layout Specs"); @@ -977,6 +988,8 @@ public class FabricUIManager implements UIManager, LifecycleEventListener { getMaxSize(widthMeasureSpec), getMinSize(heightMeasureSpec), getMaxSize(heightMeasureSpec), + offsetX, + offsetY, isRTL, doLeftAndRightSwapInRTL); } diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/Binding.cpp b/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/Binding.cpp index 0764559764f..9fb51e79fd7 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/Binding.cpp +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/Binding.cpp @@ -101,6 +101,8 @@ void Binding::startSurfaceWithConstraints( jfloat maxWidth, jfloat minHeight, jfloat maxHeight, + jfloat offsetX, + jfloat offsetY, jboolean isRTL, jboolean doLeftAndRightSwapInRTL) { SystraceSection s("FabricUIManagerBinding::startSurfaceWithConstraints"); @@ -123,6 +125,8 @@ void Binding::startSurfaceWithConstraints( Size{maxWidth / pointScaleFactor_, maxHeight / pointScaleFactor_}; LayoutContext context; + context.viewportOffset = + Point{offsetX / pointScaleFactor_, offsetY / pointScaleFactor_}; context.pointScaleFactor = {pointScaleFactor_}; context.swapLeftAndRightInRTL = doLeftAndRightSwapInRTL; LayoutConstraints constraints = {}; @@ -178,6 +182,8 @@ void Binding::setConstraints( jfloat maxWidth, jfloat minHeight, jfloat maxHeight, + jfloat offsetX, + jfloat offsetY, jboolean isRTL, jboolean doLeftAndRightSwapInRTL) { SystraceSection s("FabricUIManagerBinding::setConstraints"); @@ -194,6 +200,8 @@ void Binding::setConstraints( Size{maxWidth / pointScaleFactor_, maxHeight / pointScaleFactor_}; LayoutContext context; + context.viewportOffset = + Point{offsetX / pointScaleFactor_, offsetY / pointScaleFactor_}; context.pointScaleFactor = {pointScaleFactor_}; context.swapLeftAndRightInRTL = doLeftAndRightSwapInRTL; LayoutConstraints constraints = {}; diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/Binding.h b/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/Binding.h index fe279817098..635b74185c0 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/Binding.h +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/Binding.h @@ -48,6 +48,8 @@ class Binding : public jni::HybridClass, jfloat maxWidth, jfloat minHeight, jfloat maxHeight, + jfloat offsetX, + jfloat offsetY, jboolean isRTL, jboolean doLeftAndRightSwapInRTL); @@ -74,6 +76,8 @@ class Binding : public jni::HybridClass, jfloat maxWidth, jfloat minHeight, jfloat maxHeight, + jfloat offsetX, + jfloat offsetY, jboolean isRTL, jboolean doLeftAndRightSwapInRTL); diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModule.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModule.java index 17480d628e7..c5340ae3b75 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModule.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModule.java @@ -926,10 +926,14 @@ public class UIManagerModule extends ReactContextBaseJavaModule /** * Updates the styles of the {@link ReactShadowNode} based on the Measure specs received by - * parameters. + * parameters. offsetX and offsetY aren't used in non-Fabric, so they're ignored here. */ public void updateRootLayoutSpecs( - final int rootViewTag, final int widthMeasureSpec, final int heightMeasureSpec) { + final int rootViewTag, + final int widthMeasureSpec, + final int heightMeasureSpec, + int offsetX, + int offsetY) { ReactApplicationContext reactApplicationContext = getReactApplicationContext(); reactApplicationContext.runOnNativeModulesQueueThread( new GuardedRunnable(reactApplicationContext) {