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
This commit is contained in:
Joshua Gross
2020-09-11 13:40:56 -07:00
committed by Facebook GitHub Bot
parent a315e4cd30
commit 78b42d7fb7
7 changed files with 71 additions and 7 deletions
@@ -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);
}
}
}
@@ -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
@@ -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);
@@ -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);
}
@@ -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 = {};
@@ -48,6 +48,8 @@ class Binding : public jni::HybridClass<Binding>,
jfloat maxWidth,
jfloat minHeight,
jfloat maxHeight,
jfloat offsetX,
jfloat offsetY,
jboolean isRTL,
jboolean doLeftAndRightSwapInRTL);
@@ -74,6 +76,8 @@ class Binding : public jni::HybridClass<Binding>,
jfloat maxWidth,
jfloat minHeight,
jfloat maxHeight,
jfloat offsetX,
jfloat offsetY,
jboolean isRTL,
jboolean doLeftAndRightSwapInRTL);
@@ -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) {