Skip to content

Commit 6aea984

Browse files
mdvaccafacebook-github-bot
authored andcommitted
Add backward compatible support for onLayout event in Fabric
Reviewed By: achen1 Differential Revision: D8231722 fbshipit-source-id: 3d0641a7813e742ca81b98576f9ffc30ee597f30
1 parent 6c989fe commit 6aea984

File tree

8 files changed

+90
-10
lines changed

8 files changed

+90
-10
lines changed

ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactAppTestActivity.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,9 @@
3737
import com.facebook.react.shell.MainReactPackage;
3838
import com.facebook.react.testing.idledetection.ReactBridgeIdleSignaler;
3939
import com.facebook.react.testing.idledetection.ReactIdleDetectionUtil;
40+
import com.facebook.react.uimanager.events.EventDispatcher;
4041
import com.facebook.react.uimanager.UIImplementationProvider;
42+
import com.facebook.react.uimanager.UIManagerModule;
4143
import com.facebook.react.uimanager.ViewManager;
4244
import com.facebook.react.uimanager.ViewManagerRegistry;
4345
import java.util.Arrays;
@@ -265,8 +267,10 @@ public JSIModuleProvider getJSIModuleProvider() {
265267
public FabricUIManager get() {
266268
List<ViewManager> viewManagers =
267269
mReactInstanceManager.getOrCreateViewManagers(reactApplicationContext);
270+
EventDispatcher eventDispatcher =
271+
reactApplicationContext.getNativeModule(UIManagerModule.class).getEventDispatcher();
268272
FabricUIManager fabricUIManager =
269-
new FabricUIManager(reactApplicationContext, new ViewManagerRegistry(viewManagers), jsContext);
273+
new FabricUIManager(reactApplicationContext, new ViewManagerRegistry(viewManagers), jsContext, eventDispatcher);
270274
new FabricJSCBinding().installFabric(jsContext, fabricUIManager);
271275
return fabricUIManager;
272276
}

ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactInstrumentationTest.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@
2525
public abstract class ReactInstrumentationTest extends
2626
ActivityInstrumentationTestCase2<ReactAppTestActivity> implements IdleWaiter {
2727

28+
protected StringRecordingModule mRecordingModule;
29+
2830
public ReactInstrumentationTest() {
2931
super(ReactAppTestActivity.class);
3032
}
@@ -36,6 +38,7 @@ protected void setUp() throws Exception {
3638
Intent intent = new Intent();
3739
intent.putExtra(ReactAppTestActivity.EXTRA_IS_FABRIC_TEST, isFabricTest());
3840
setActivityIntent(intent);
41+
mRecordingModule = new StringRecordingModule();
3942
final ReactAppTestActivity activity = getActivity();
4043
activity.loadBundle(
4144
createReactInstanceSpecForTest(),
@@ -95,7 +98,7 @@ protected <T extends JavaScriptModule> T getJSModule(Class<T> jsInterface) {
9598
* Override this method to provide extra native modules to be loaded before the app starts
9699
*/
97100
protected ReactInstanceSpecForTest createReactInstanceSpecForTest() {
98-
return new ReactInstanceSpecForTest();
101+
return new ReactInstanceSpecForTest().addNativeModule(mRecordingModule);
99102
}
100103

101104
/**

ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import static android.view.View.MeasureSpec.AT_MOST;
1111
import static android.view.View.MeasureSpec.EXACTLY;
1212
import static android.view.View.MeasureSpec.UNSPECIFIED;
13+
import static com.facebook.react.uimanager.common.UIManagerType.FABRIC;
1314

1415
import android.util.Log;
1516
import android.view.View;
@@ -24,9 +25,11 @@
2425
import com.facebook.react.bridge.WritableNativeMap;
2526
import com.facebook.react.common.ReactConstants;
2627
import com.facebook.react.common.annotations.VisibleForTesting;
28+
import com.facebook.react.fabric.events.FabricEventEmitter;
2729
import com.facebook.react.modules.i18nmanager.I18nUtil;
2830
import com.facebook.react.uimanager.DisplayMetricsHolder;
2931
import com.facebook.react.uimanager.NativeViewHierarchyManager;
32+
import com.facebook.react.uimanager.OnLayoutEvent;
3033
import com.facebook.react.uimanager.ReactRootViewTagGenerator;
3134
import com.facebook.react.uimanager.ReactShadowNode;
3235
import com.facebook.react.uimanager.ReactShadowNodeImpl;
@@ -37,6 +40,7 @@
3740
import com.facebook.react.uimanager.ViewManagerRegistry;
3841
import com.facebook.react.uimanager.common.MeasureSpecProvider;
3942
import com.facebook.react.uimanager.common.SizeMonitoringFrameLayout;
43+
import com.facebook.react.uimanager.events.EventDispatcher;
4044
import com.facebook.yoga.YogaDirection;
4145
import java.util.ArrayList;
4246
import java.util.LinkedList;
@@ -61,13 +65,15 @@ public class FabricUIManager implements UIManager, JSHandler {
6165
private final JavaScriptContextHolder mJSContext;
6266
private volatile int mCurrentBatch = 0;
6367
private final FabricReconciler mFabricReconciler;
68+
private final EventDispatcher mEventDispatcher;
6469
private FabricBinding mBinding;
6570
private long mEventHandlerPointer;
6671

6772
public FabricUIManager(
6873
ReactApplicationContext reactContext,
6974
ViewManagerRegistry viewManagerRegistry,
70-
JavaScriptContextHolder jsContext) {
75+
JavaScriptContextHolder jsContext,
76+
EventDispatcher eventDispatcher) {
7177
DisplayMetricsHolder.initDisplayMetricsIfNotInitialized(reactContext);
7278
mReactApplicationContext = reactContext;
7379
mViewManagerRegistry = viewManagerRegistry;
@@ -76,7 +82,12 @@ public FabricUIManager(
7682
new UIViewOperationQueue(
7783
reactContext, mNativeViewHierarchyManager, 0);
7884
mFabricReconciler = new FabricReconciler(mUIViewOperationQueue);
85+
mEventDispatcher = eventDispatcher;
7986
mJSContext = jsContext;
87+
88+
FabricEventEmitter eventEmitter =
89+
new FabricEventEmitter(reactContext, this);
90+
eventDispatcher.registerEventEmitter(FABRIC, eventEmitter);
8091
}
8192

8293
public void setBinding(FabricBinding binding) {
@@ -355,7 +366,18 @@ private void applyUpdatesRecursive(ReactShadowNode node, float absoluteX, float
355366
if (mRootShadowNodeRegistry.getNode(tag) == null) {
356367
boolean frameDidChange =
357368
node.dispatchUpdates(absoluteX, absoluteY, mUIViewOperationQueue, null);
369+
// Notify JS about layout event if requested
370+
// and if the position or dimensions actually changed
371+
// (consistent with iOS and Android Default implementation).
372+
if (frameDidChange && node.shouldNotifyOnLayout()) {
373+
mUIViewOperationQueue.enqueueOnLayoutEvent(tag,
374+
node.getScreenX(),
375+
node.getScreenY(),
376+
node.getScreenWidth(),
377+
node.getScreenHeight());
378+
}
358379
}
380+
359381
// Set the reference to the OriginalReactShadowNode to NULL, as the tree is already committed
360382
// and we do not need to hold references to the previous tree anymore
361383
node.setOriginalReactShadowNode(null);

ReactAndroid/src/main/java/com/facebook/react/fabric/events/FabricEventEmitter.java

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import com.facebook.react.fabric.FabricUIManager;
2727
import com.facebook.react.fabric.Scheduler;
2828
import com.facebook.react.fabric.Work;
29+
import com.facebook.react.uimanager.IllegalViewOperationException;
2930
import com.facebook.react.uimanager.events.RCTEventEmitter;
3031
import java.io.Closeable;
3132
import java.io.IOException;
@@ -48,9 +49,13 @@ public FabricEventEmitter(ReactApplicationContext context, FabricUIManager fabri
4849
}
4950

5051
@Override
51-
public void receiveEvent(int targetTag, String eventName, @Nullable WritableMap params) {
52-
long eventTarget = mFabricUIManager.createEventTarget(targetTag);
53-
mScheduler.scheduleWork(new FabricUIManagerWork(eventTarget, eventName, params));
52+
public void receiveEvent(int reactTag, String eventName, @Nullable WritableMap params) {
53+
try {
54+
long eventTarget = mFabricUIManager.createEventTarget(reactTag);
55+
mScheduler.scheduleWork(new FabricUIManagerWork(eventTarget, eventName, params));
56+
} catch (IllegalViewOperationException e) {
57+
Log.e(TAG, "Unable to emmit event for tag " + reactTag, e);
58+
}
5459
}
5560

5661
@Override

ReactAndroid/src/main/java/com/facebook/react/uimanager/NativeViewHierarchyManager.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -224,11 +224,11 @@ private void updateInstanceHandle(View viewToUpdate, long instanceHandle) {
224224
public long getInstanceHandle(int reactTag) {
225225
View view = mTagsToViews.get(reactTag);
226226
if (view == null) {
227-
throw new IllegalArgumentException("Unable to find view for tag: " + reactTag);
227+
throw new IllegalViewOperationException("Unable to find view for tag: " + reactTag);
228228
}
229229
Long instanceHandle = (Long) view.getTag(R.id.view_tag_instance_handle);
230230
if (instanceHandle == null) {
231-
throw new IllegalArgumentException("Unable to find instanceHandle for tag: " + reactTag);
231+
throw new IllegalViewOperationException("Unable to find instanceHandle for tag: " + reactTag);
232232
}
233233
return instanceHandle;
234234
}

ReactAndroid/src/main/java/com/facebook/react/uimanager/UIViewOperationQueue.java

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,38 @@ public void execute() {
9696
}
9797
}
9898

99+
private final class EmitOnLayoutEventOperation extends ViewOperation {
100+
101+
private final int mScreenX;
102+
private final int mScreenY;
103+
private final int mScreenWidth;
104+
private final int mScreenHeight;
105+
106+
public EmitOnLayoutEventOperation(
107+
int tag,
108+
int screenX,
109+
int screenY,
110+
int screenWidth,
111+
int screenHeight) {
112+
super(tag);
113+
mScreenX = screenX;
114+
mScreenY = screenY;
115+
mScreenWidth = screenWidth;
116+
mScreenHeight = screenHeight;
117+
}
118+
119+
@Override
120+
public void execute() {
121+
mReactApplicationContext.getNativeModule(UIManagerModule.class)
122+
.getEventDispatcher()
123+
.dispatchEvent(OnLayoutEvent.obtain(
124+
mTag,
125+
mScreenX,
126+
mScreenY,
127+
mScreenWidth,
128+
mScreenHeight));
129+
}
130+
}
99131

100132
private final class UpdateInstanceHandleOperation extends ViewOperation {
101133

@@ -706,6 +738,16 @@ public void enqueueUpdateProperties(int reactTag, String className, ReactStylesD
706738
mOperations.add(new UpdatePropertiesOperation(reactTag, props));
707739
}
708740

741+
public void enqueueOnLayoutEvent(
742+
int tag,
743+
int screenX,
744+
int screenY,
745+
int screenWidth,
746+
int screenHeight) {
747+
mOperations.add(new EmitOnLayoutEventOperation(tag, screenX, screenY, screenWidth, screenHeight));
748+
}
749+
750+
709751
public void enqueueUpdateLayout(
710752
int parentTag,
711753
int reactTag,

ReactAndroid/src/test/java/com/facebook/react/fabric/FabricReconcilerTest.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import com.facebook.react.bridge.JavaScriptContextHolder;
1212
import com.facebook.react.bridge.ReactApplicationContext;
1313
import com.facebook.react.bridge.ReactTestHelper;
14+
import com.facebook.react.uimanager.events.EventDispatcher;
1415
import com.facebook.react.uimanager.NativeViewHierarchyManager;
1516
import com.facebook.react.uimanager.ReactShadowNode;
1617
import com.facebook.react.uimanager.ReactShadowNodeImpl;
@@ -46,7 +47,8 @@ public void setUp() {
4647
List<ViewManager> viewManagers = new ArrayList<>();
4748
ViewManagerRegistry viewManagerRegistry = new ViewManagerRegistry(viewManagers);
4849
JavaScriptContextHolder jsContext = mock(JavaScriptContextHolder.class);
49-
mFabricUIManager = new FabricUIManager(reactContext, viewManagerRegistry, jsContext);
50+
EventDispatcher eventDispatcher = mock(EventDispatcher.class);
51+
mFabricUIManager = new FabricUIManager(reactContext, viewManagerRegistry, jsContext, eventDispatcher);
5052
mMockUIViewOperationQueue = new MockUIViewOperationQueue(reactContext);
5153
mFabricReconciler = new FabricReconciler(mMockUIViewOperationQueue);
5254
}

ReactAndroid/src/test/java/com/facebook/react/fabric/FabricUIManagerTest.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
import com.facebook.react.bridge.ReactApplicationContext;
1414
import com.facebook.react.bridge.ReactTestHelper;
1515
import com.facebook.react.bridge.ReadableNativeMap;
16+
import com.facebook.react.uimanager.events.EventDispatcher;
1617
import com.facebook.react.uimanager.ReactShadowNode;
1718
import com.facebook.react.uimanager.ReactShadowNodeImpl;
1819
import com.facebook.react.uimanager.Spacing;
@@ -55,7 +56,8 @@ public void setUp() throws Exception {
5556
new ReactViewManager(), new ReactTextViewManager(), new ReactRawTextManager());
5657
ViewManagerRegistry viewManagerRegistry = new ViewManagerRegistry(viewManagers);
5758
JavaScriptContextHolder jsContext = mock(JavaScriptContextHolder.class);
58-
mFabricUIManager = new FabricUIManager(reactContext, viewManagerRegistry, jsContext);
59+
EventDispatcher eventDispatcher = mock(EventDispatcher.class);
60+
mFabricUIManager = new FabricUIManager(reactContext, viewManagerRegistry, jsContext, eventDispatcher);
5961
}
6062

6163
@Test

0 commit comments

Comments
 (0)