Add backward compatible support for onLayout event in Fabric
Reviewed By: achen1 Differential Revision: D8231722 fbshipit-source-id: 3d0641a7813e742ca81b98576f9ffc30ee597f30
This commit is contained in:
parent
6c989fe7c6
commit
6aea98441a
|
@ -37,7 +37,9 @@ import com.facebook.react.modules.core.PermissionListener;
|
|||
import com.facebook.react.shell.MainReactPackage;
|
||||
import com.facebook.react.testing.idledetection.ReactBridgeIdleSignaler;
|
||||
import com.facebook.react.testing.idledetection.ReactIdleDetectionUtil;
|
||||
import com.facebook.react.uimanager.events.EventDispatcher;
|
||||
import com.facebook.react.uimanager.UIImplementationProvider;
|
||||
import com.facebook.react.uimanager.UIManagerModule;
|
||||
import com.facebook.react.uimanager.ViewManager;
|
||||
import com.facebook.react.uimanager.ViewManagerRegistry;
|
||||
import java.util.Arrays;
|
||||
|
@ -265,8 +267,10 @@ public class ReactAppTestActivity extends FragmentActivity
|
|||
public FabricUIManager get() {
|
||||
List<ViewManager> viewManagers =
|
||||
mReactInstanceManager.getOrCreateViewManagers(reactApplicationContext);
|
||||
EventDispatcher eventDispatcher =
|
||||
reactApplicationContext.getNativeModule(UIManagerModule.class).getEventDispatcher();
|
||||
FabricUIManager fabricUIManager =
|
||||
new FabricUIManager(reactApplicationContext, new ViewManagerRegistry(viewManagers), jsContext);
|
||||
new FabricUIManager(reactApplicationContext, new ViewManagerRegistry(viewManagers), jsContext, eventDispatcher);
|
||||
new FabricJSCBinding().installFabric(jsContext, fabricUIManager);
|
||||
return fabricUIManager;
|
||||
}
|
||||
|
|
|
@ -25,6 +25,8 @@ import com.facebook.react.testing.idledetection.IdleWaiter;
|
|||
public abstract class ReactInstrumentationTest extends
|
||||
ActivityInstrumentationTestCase2<ReactAppTestActivity> implements IdleWaiter {
|
||||
|
||||
protected StringRecordingModule mRecordingModule;
|
||||
|
||||
public ReactInstrumentationTest() {
|
||||
super(ReactAppTestActivity.class);
|
||||
}
|
||||
|
@ -36,6 +38,7 @@ public abstract class ReactInstrumentationTest extends
|
|||
Intent intent = new Intent();
|
||||
intent.putExtra(ReactAppTestActivity.EXTRA_IS_FABRIC_TEST, isFabricTest());
|
||||
setActivityIntent(intent);
|
||||
mRecordingModule = new StringRecordingModule();
|
||||
final ReactAppTestActivity activity = getActivity();
|
||||
activity.loadBundle(
|
||||
createReactInstanceSpecForTest(),
|
||||
|
@ -95,7 +98,7 @@ public abstract class ReactInstrumentationTest extends
|
|||
* Override this method to provide extra native modules to be loaded before the app starts
|
||||
*/
|
||||
protected ReactInstanceSpecForTest createReactInstanceSpecForTest() {
|
||||
return new ReactInstanceSpecForTest();
|
||||
return new ReactInstanceSpecForTest().addNativeModule(mRecordingModule);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -10,6 +10,7 @@ package com.facebook.react.fabric;
|
|||
import static android.view.View.MeasureSpec.AT_MOST;
|
||||
import static android.view.View.MeasureSpec.EXACTLY;
|
||||
import static android.view.View.MeasureSpec.UNSPECIFIED;
|
||||
import static com.facebook.react.uimanager.common.UIManagerType.FABRIC;
|
||||
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
|
@ -24,9 +25,11 @@ import com.facebook.react.bridge.WritableMap;
|
|||
import com.facebook.react.bridge.WritableNativeMap;
|
||||
import com.facebook.react.common.ReactConstants;
|
||||
import com.facebook.react.common.annotations.VisibleForTesting;
|
||||
import com.facebook.react.fabric.events.FabricEventEmitter;
|
||||
import com.facebook.react.modules.i18nmanager.I18nUtil;
|
||||
import com.facebook.react.uimanager.DisplayMetricsHolder;
|
||||
import com.facebook.react.uimanager.NativeViewHierarchyManager;
|
||||
import com.facebook.react.uimanager.OnLayoutEvent;
|
||||
import com.facebook.react.uimanager.ReactRootViewTagGenerator;
|
||||
import com.facebook.react.uimanager.ReactShadowNode;
|
||||
import com.facebook.react.uimanager.ReactShadowNodeImpl;
|
||||
|
@ -37,6 +40,7 @@ import com.facebook.react.uimanager.ViewManager;
|
|||
import com.facebook.react.uimanager.ViewManagerRegistry;
|
||||
import com.facebook.react.uimanager.common.MeasureSpecProvider;
|
||||
import com.facebook.react.uimanager.common.SizeMonitoringFrameLayout;
|
||||
import com.facebook.react.uimanager.events.EventDispatcher;
|
||||
import com.facebook.yoga.YogaDirection;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedList;
|
||||
|
@ -61,13 +65,15 @@ public class FabricUIManager implements UIManager, JSHandler {
|
|||
private final JavaScriptContextHolder mJSContext;
|
||||
private volatile int mCurrentBatch = 0;
|
||||
private final FabricReconciler mFabricReconciler;
|
||||
private final EventDispatcher mEventDispatcher;
|
||||
private FabricBinding mBinding;
|
||||
private long mEventHandlerPointer;
|
||||
|
||||
public FabricUIManager(
|
||||
ReactApplicationContext reactContext,
|
||||
ViewManagerRegistry viewManagerRegistry,
|
||||
JavaScriptContextHolder jsContext) {
|
||||
JavaScriptContextHolder jsContext,
|
||||
EventDispatcher eventDispatcher) {
|
||||
DisplayMetricsHolder.initDisplayMetricsIfNotInitialized(reactContext);
|
||||
mReactApplicationContext = reactContext;
|
||||
mViewManagerRegistry = viewManagerRegistry;
|
||||
|
@ -76,7 +82,12 @@ public class FabricUIManager implements UIManager, JSHandler {
|
|||
new UIViewOperationQueue(
|
||||
reactContext, mNativeViewHierarchyManager, 0);
|
||||
mFabricReconciler = new FabricReconciler(mUIViewOperationQueue);
|
||||
mEventDispatcher = eventDispatcher;
|
||||
mJSContext = jsContext;
|
||||
|
||||
FabricEventEmitter eventEmitter =
|
||||
new FabricEventEmitter(reactContext, this);
|
||||
eventDispatcher.registerEventEmitter(FABRIC, eventEmitter);
|
||||
}
|
||||
|
||||
public void setBinding(FabricBinding binding) {
|
||||
|
@ -355,7 +366,18 @@ public class FabricUIManager implements UIManager, JSHandler {
|
|||
if (mRootShadowNodeRegistry.getNode(tag) == null) {
|
||||
boolean frameDidChange =
|
||||
node.dispatchUpdates(absoluteX, absoluteY, mUIViewOperationQueue, null);
|
||||
// Notify JS about layout event if requested
|
||||
// and if the position or dimensions actually changed
|
||||
// (consistent with iOS and Android Default implementation).
|
||||
if (frameDidChange && node.shouldNotifyOnLayout()) {
|
||||
mUIViewOperationQueue.enqueueOnLayoutEvent(tag,
|
||||
node.getScreenX(),
|
||||
node.getScreenY(),
|
||||
node.getScreenWidth(),
|
||||
node.getScreenHeight());
|
||||
}
|
||||
}
|
||||
|
||||
// Set the reference to the OriginalReactShadowNode to NULL, as the tree is already committed
|
||||
// and we do not need to hold references to the previous tree anymore
|
||||
node.setOriginalReactShadowNode(null);
|
||||
|
|
|
@ -26,6 +26,7 @@ import com.facebook.react.bridge.WritableNativeMap;
|
|||
import com.facebook.react.fabric.FabricUIManager;
|
||||
import com.facebook.react.fabric.Scheduler;
|
||||
import com.facebook.react.fabric.Work;
|
||||
import com.facebook.react.uimanager.IllegalViewOperationException;
|
||||
import com.facebook.react.uimanager.events.RCTEventEmitter;
|
||||
import java.io.Closeable;
|
||||
import java.io.IOException;
|
||||
|
@ -48,9 +49,13 @@ public class FabricEventEmitter implements RCTEventEmitter, Closeable {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void receiveEvent(int targetTag, String eventName, @Nullable WritableMap params) {
|
||||
long eventTarget = mFabricUIManager.createEventTarget(targetTag);
|
||||
mScheduler.scheduleWork(new FabricUIManagerWork(eventTarget, eventName, params));
|
||||
public void receiveEvent(int reactTag, String eventName, @Nullable WritableMap params) {
|
||||
try {
|
||||
long eventTarget = mFabricUIManager.createEventTarget(reactTag);
|
||||
mScheduler.scheduleWork(new FabricUIManagerWork(eventTarget, eventName, params));
|
||||
} catch (IllegalViewOperationException e) {
|
||||
Log.e(TAG, "Unable to emmit event for tag " + reactTag, e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -224,11 +224,11 @@ public class NativeViewHierarchyManager {
|
|||
public long getInstanceHandle(int reactTag) {
|
||||
View view = mTagsToViews.get(reactTag);
|
||||
if (view == null) {
|
||||
throw new IllegalArgumentException("Unable to find view for tag: " + reactTag);
|
||||
throw new IllegalViewOperationException("Unable to find view for tag: " + reactTag);
|
||||
}
|
||||
Long instanceHandle = (Long) view.getTag(R.id.view_tag_instance_handle);
|
||||
if (instanceHandle == null) {
|
||||
throw new IllegalArgumentException("Unable to find instanceHandle for tag: " + reactTag);
|
||||
throw new IllegalViewOperationException("Unable to find instanceHandle for tag: " + reactTag);
|
||||
}
|
||||
return instanceHandle;
|
||||
}
|
||||
|
|
|
@ -96,6 +96,38 @@ public class UIViewOperationQueue {
|
|||
}
|
||||
}
|
||||
|
||||
private final class EmitOnLayoutEventOperation extends ViewOperation {
|
||||
|
||||
private final int mScreenX;
|
||||
private final int mScreenY;
|
||||
private final int mScreenWidth;
|
||||
private final int mScreenHeight;
|
||||
|
||||
public EmitOnLayoutEventOperation(
|
||||
int tag,
|
||||
int screenX,
|
||||
int screenY,
|
||||
int screenWidth,
|
||||
int screenHeight) {
|
||||
super(tag);
|
||||
mScreenX = screenX;
|
||||
mScreenY = screenY;
|
||||
mScreenWidth = screenWidth;
|
||||
mScreenHeight = screenHeight;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute() {
|
||||
mReactApplicationContext.getNativeModule(UIManagerModule.class)
|
||||
.getEventDispatcher()
|
||||
.dispatchEvent(OnLayoutEvent.obtain(
|
||||
mTag,
|
||||
mScreenX,
|
||||
mScreenY,
|
||||
mScreenWidth,
|
||||
mScreenHeight));
|
||||
}
|
||||
}
|
||||
|
||||
private final class UpdateInstanceHandleOperation extends ViewOperation {
|
||||
|
||||
|
@ -706,6 +738,16 @@ public class UIViewOperationQueue {
|
|||
mOperations.add(new UpdatePropertiesOperation(reactTag, props));
|
||||
}
|
||||
|
||||
public void enqueueOnLayoutEvent(
|
||||
int tag,
|
||||
int screenX,
|
||||
int screenY,
|
||||
int screenWidth,
|
||||
int screenHeight) {
|
||||
mOperations.add(new EmitOnLayoutEventOperation(tag, screenX, screenY, screenWidth, screenHeight));
|
||||
}
|
||||
|
||||
|
||||
public void enqueueUpdateLayout(
|
||||
int parentTag,
|
||||
int reactTag,
|
||||
|
|
|
@ -11,6 +11,7 @@ import com.facebook.react.bridge.CatalystInstance;
|
|||
import com.facebook.react.bridge.JavaScriptContextHolder;
|
||||
import com.facebook.react.bridge.ReactApplicationContext;
|
||||
import com.facebook.react.bridge.ReactTestHelper;
|
||||
import com.facebook.react.uimanager.events.EventDispatcher;
|
||||
import com.facebook.react.uimanager.NativeViewHierarchyManager;
|
||||
import com.facebook.react.uimanager.ReactShadowNode;
|
||||
import com.facebook.react.uimanager.ReactShadowNodeImpl;
|
||||
|
@ -46,7 +47,8 @@ public class FabricReconcilerTest {
|
|||
List<ViewManager> viewManagers = new ArrayList<>();
|
||||
ViewManagerRegistry viewManagerRegistry = new ViewManagerRegistry(viewManagers);
|
||||
JavaScriptContextHolder jsContext = mock(JavaScriptContextHolder.class);
|
||||
mFabricUIManager = new FabricUIManager(reactContext, viewManagerRegistry, jsContext);
|
||||
EventDispatcher eventDispatcher = mock(EventDispatcher.class);
|
||||
mFabricUIManager = new FabricUIManager(reactContext, viewManagerRegistry, jsContext, eventDispatcher);
|
||||
mMockUIViewOperationQueue = new MockUIViewOperationQueue(reactContext);
|
||||
mFabricReconciler = new FabricReconciler(mMockUIViewOperationQueue);
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@ import com.facebook.react.bridge.JavaScriptContextHolder;
|
|||
import com.facebook.react.bridge.ReactApplicationContext;
|
||||
import com.facebook.react.bridge.ReactTestHelper;
|
||||
import com.facebook.react.bridge.ReadableNativeMap;
|
||||
import com.facebook.react.uimanager.events.EventDispatcher;
|
||||
import com.facebook.react.uimanager.ReactShadowNode;
|
||||
import com.facebook.react.uimanager.ReactShadowNodeImpl;
|
||||
import com.facebook.react.uimanager.Spacing;
|
||||
|
@ -55,7 +56,8 @@ public class FabricUIManagerTest {
|
|||
new ReactViewManager(), new ReactTextViewManager(), new ReactRawTextManager());
|
||||
ViewManagerRegistry viewManagerRegistry = new ViewManagerRegistry(viewManagers);
|
||||
JavaScriptContextHolder jsContext = mock(JavaScriptContextHolder.class);
|
||||
mFabricUIManager = new FabricUIManager(reactContext, viewManagerRegistry, jsContext);
|
||||
EventDispatcher eventDispatcher = mock(EventDispatcher.class);
|
||||
mFabricUIManager = new FabricUIManager(reactContext, viewManagerRegistry, jsContext, eventDispatcher);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
Loading…
Reference in New Issue