diff --git a/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactAppTestActivity.java b/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactAppTestActivity.java index e7e6d95e3..ddaae9d17 100644 --- a/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactAppTestActivity.java +++ b/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactAppTestActivity.java @@ -261,7 +261,7 @@ public class ReactAppTestActivity extends FragmentActivity List viewManagers = mReactInstanceManager.getOrCreateViewManagers(reactApplicationContext); FabricUIManager fabricUIManager = - new FabricUIManager(reactApplicationContext, new ViewManagerRegistry(viewManagers)); + new FabricUIManager(reactApplicationContext, new ViewManagerRegistry(viewManagers), jsContext); new FabricJSCBinding().installFabric(jsContext, fabricUIManager); return fabricUIManager; } diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricBinding.java b/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricBinding.java index 97535f0a0..0636c17c2 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricBinding.java +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricBinding.java @@ -8,9 +8,24 @@ package com.facebook.react.fabric; import com.facebook.react.bridge.JavaScriptContextHolder; +import com.facebook.react.bridge.NativeMap; public interface FabricBinding { void installFabric(JavaScriptContextHolder jsContext, FabricUIManager fabricModule); + long createEventTarget(long jsContextNativePointer, long instanceHandlePointer); + + void releaseEventTarget(long jsContextNativePointer, long eventTargetPointer); + + void releaseEventHandler(long jsContextNativePointer, long eventHandlerPointer); + + void dispatchEventToTarget( + long jsContextNativePointer, + long eventHandlerPointer, + long eventTargetPointer, + String type, + NativeMap payload + ); + } 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 6b7bfff47..10a187108 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java @@ -14,15 +14,15 @@ import static android.view.View.MeasureSpec.UNSPECIFIED; import android.util.Log; import android.view.View; import com.facebook.infer.annotation.Assertions; -import com.facebook.react.bridge.GuardedRunnable; import com.facebook.react.bridge.JavaScriptContextHolder; import com.facebook.react.bridge.ReactApplicationContext; import com.facebook.react.bridge.ReadableArray; import com.facebook.react.bridge.ReadableMap; import com.facebook.react.bridge.ReadableNativeMap; import com.facebook.react.bridge.UIManager; -import com.facebook.react.common.ReactConstants; 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.modules.i18nmanager.I18nUtil; import com.facebook.react.uimanager.DisplayMetricsHolder; @@ -39,10 +39,8 @@ import com.facebook.react.uimanager.common.MeasureSpecProvider; import com.facebook.react.uimanager.common.SizeMonitoringFrameLayout; import com.facebook.yoga.YogaDirection; import java.util.ArrayList; -import java.util.HashSet; import java.util.LinkedList; import java.util.List; -import java.util.Set; import javax.annotation.Nullable; /** @@ -60,14 +58,16 @@ public class FabricUIManager implements UIManager, JSHandler { private final ViewManagerRegistry mViewManagerRegistry; private final UIViewOperationQueue mUIViewOperationQueue; private final NativeViewHierarchyManager mNativeViewHierarchyManager; + private final JavaScriptContextHolder mJSContext; private volatile int mCurrentBatch = 0; private final FabricReconciler mFabricReconciler; - // TODO: Initialize new Binding (waiting for C++ implemenation to be landed) private FabricBinding mBinding; - private JavaScriptContextHolder mContext; + private long mEventHandlerPointer; public FabricUIManager( - ReactApplicationContext reactContext, ViewManagerRegistry viewManagerRegistry) { + ReactApplicationContext reactContext, + ViewManagerRegistry viewManagerRegistry, + JavaScriptContextHolder jsContext) { DisplayMetricsHolder.initDisplayMetricsIfNotInitialized(reactContext); mReactApplicationContext = reactContext; mViewManagerRegistry = viewManagerRegistry; @@ -76,10 +76,11 @@ public class FabricUIManager implements UIManager, JSHandler { new UIViewOperationQueue( reactContext, mNativeViewHierarchyManager, 0); mFabricReconciler = new FabricReconciler(mUIViewOperationQueue); + mJSContext = jsContext; } - public void registerEventHandler(long eventHandlerPointer) { - // TODO: Release this event handler at some point. + public void setBinding(FabricBinding binding) { + mBinding = binding; } /** Creates a new {@link ReactShadowNode} */ @@ -480,20 +481,39 @@ public class FabricUIManager implements UIManager, JSHandler { } } - @Override - public void invoke(int instanceHandle, String name, WritableMap params) { - Log.e(TAG, "Invoking '" + name + "' on instanceHandle: '" + instanceHandle + "' from FabricUIManager."); - // -> call to C++ - } - - public long createEventTarget(int reactTag) throws IllegalStateException { + @Nullable + public long createEventTarget(int reactTag) { long instanceHandle = mNativeViewHierarchyManager.getInstanceHandle(reactTag); - if (instanceHandle == 0) { - throw new IllegalStateException("View with reactTag " + reactTag + " does not exist."); + long context = mJSContext.get(); + long eventTarget = mBinding.createEventTarget(context, instanceHandle); + if (DEBUG) { + Log.e( + TAG, + "Created EventTarget: " + eventTarget + " for tag: " + reactTag + " with instanceHandle: " + instanceHandle); } - - // TODO: uncomment after diff including Binding is landed - // return mBinding.createEventTarget(mContext.get(), instanceHandle); - return 0; + return eventTarget; } + + public void registerEventHandler(long eventHandlerPointer) { + mEventHandlerPointer = eventHandlerPointer; + } + + public void releaseEventTarget(long eventTargetPointer) { + mBinding.releaseEventTarget(mJSContext.get(), eventTargetPointer); + } + + public void releaseEventHandler(long eventHandlerPointer) { + mBinding.releaseEventHandler(mJSContext.get(), eventHandlerPointer); + } + + @Override + public void invoke(long eventTarget, String name, WritableMap params) { + if (DEBUG) { + Log.e( + TAG, + "Dispatching event for target: " + eventTarget); + } + mBinding.dispatchEventToTarget(mJSContext.get(), mEventHandlerPointer, eventTarget, name, (WritableNativeMap) params); + } + } diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/JSHandler.java b/ReactAndroid/src/main/java/com/facebook/react/fabric/JSHandler.java index 42b11c46d..471c016a6 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/JSHandler.java +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/JSHandler.java @@ -10,6 +10,6 @@ import com.facebook.react.bridge.WritableMap; public interface JSHandler { - void invoke(int instanceHandle, String name, WritableMap params); + void invoke(long instanceHandle, String name, WritableMap params); } diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/events/FabricEventEmitter.java b/ReactAndroid/src/main/java/com/facebook/react/fabric/events/FabricEventEmitter.java index 59c701e67..6ec640bf3 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/events/FabricEventEmitter.java +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/events/FabricEventEmitter.java @@ -49,9 +49,8 @@ public class FabricEventEmitter implements RCTEventEmitter, Closeable { @Override public void receiveEvent(int targetTag, String eventName, @Nullable WritableMap params) { - //TODO get instanceHandle associated with targetTag. - int instanceHandle = targetTag; - mScheduler.scheduleWork(new FabricUIManagerWork(instanceHandle, eventName, params) ); + long eventTarget = mFabricUIManager.createEventTarget(targetTag); + mScheduler.scheduleWork(new FabricUIManagerWork(eventTarget, eventName, params)); } @Override @@ -60,19 +59,26 @@ public class FabricEventEmitter implements RCTEventEmitter, Closeable { } private class FabricUIManagerWork implements Work { - private final int mInstanceHandle; + private final long mEventTarget; private final String mEventName; private final WritableMap mParams; - public FabricUIManagerWork(int instanceHandle, String eventName, @Nullable WritableMap params) { - mInstanceHandle = instanceHandle; + public FabricUIManagerWork(long eventTarget, String eventName, @Nullable WritableMap params) { + mEventTarget = eventTarget; mEventName = eventName; mParams = params; } @Override public void run() { - mFabricUIManager.invoke(mInstanceHandle, mEventName, mParams); + try { + mFabricUIManager.invoke(mEventTarget, mEventName, mParams); + } catch (Throwable t) { + Log.e(TAG, "Error sending event " + mEventName, t); + //TODO: manage exception properly + } finally{ + mFabricUIManager.releaseEventTarget(mEventTarget); + } } } diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/jsc/FabricJSCBinding.java b/ReactAndroid/src/main/java/com/facebook/react/fabric/jsc/FabricJSCBinding.java index 190a1aefc..38bbbfe63 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/jsc/FabricJSCBinding.java +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/jsc/FabricJSCBinding.java @@ -28,13 +28,17 @@ public class FabricJSCBinding implements FabricBinding { private static native HybridData initHybrid(); - private native long createEventTarget(long jsContextNativePointer, long instanceHandlePointer); + @Override + public native long createEventTarget(long jsContextNativePointer, long instanceHandlePointer); - private native void releaseEventTarget(long jsContextNativePointer, long eventTargetPointer); + @Override + public native void releaseEventTarget(long jsContextNativePointer, long eventTargetPointer); - private native void releaseEventHandler(long jsContextNativePointer, long eventHandlerPointer); + @Override + public native void releaseEventHandler(long jsContextNativePointer, long eventHandlerPointer); - private native void dispatchEventToTarget( + @Override + public native void dispatchEventToTarget( long jsContextNativePointer, long eventHandlerPointer, long eventTargetPointer, @@ -50,6 +54,7 @@ public class FabricJSCBinding implements FabricBinding { @Override public void installFabric(JavaScriptContextHolder jsContext, FabricUIManager fabricModule) { + fabricModule.setBinding(this); installFabric(jsContext.get(), fabricModule); } } diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/NativeViewHierarchyManager.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/NativeViewHierarchyManager.java index d5a204719..4cb9a92dc 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/NativeViewHierarchyManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/NativeViewHierarchyManager.java @@ -222,17 +222,15 @@ public class NativeViewHierarchyManager { @Nullable @TargetApi(Build.VERSION_CODES.DONUT) public long getInstanceHandle(int reactTag) { - UiThreadUtil.assertOnUiThread(); - View view = mTagsToViews.get(reactTag); if (view == null) { throw new IllegalArgumentException("Unable to find view for tag: " + reactTag); } - Long tag = (Long) view.getTag(R.id.view_tag_instance_handle); - if (tag == null) { + Long instanceHandle = (Long) view.getTag(R.id.view_tag_instance_handle); + if (instanceHandle == null) { throw new IllegalArgumentException("Unable to find instanceHandle for tag: " + reactTag); } - return tag; + return instanceHandle; } private void updateLayout(View viewToUpdate, int x, int y, int width, int height) { diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/events/EventDispatcher.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/events/EventDispatcher.java index ad15ce0a8..c9bc7af5d 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/events/EventDispatcher.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/events/EventDispatcher.java @@ -115,7 +115,7 @@ public class EventDispatcher implements LifecycleEventListener, for (EventDispatcherListener listener : mListeners) { listener.onEventDispatch(event); } - + synchronized (mEventsStagingLock) { mEventStaging.add(event); Systrace.startAsyncFlow( diff --git a/ReactAndroid/src/test/java/com/facebook/react/fabric/FabricReconcilerTest.java b/ReactAndroid/src/test/java/com/facebook/react/fabric/FabricReconcilerTest.java index bf4d69dff..d5f210408 100644 --- a/ReactAndroid/src/test/java/com/facebook/react/fabric/FabricReconcilerTest.java +++ b/ReactAndroid/src/test/java/com/facebook/react/fabric/FabricReconcilerTest.java @@ -5,6 +5,7 @@ import static org.fest.assertions.api.Assertions.assertThat; import static org.mockito.Mockito.mock; 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.NativeViewHierarchyManager; @@ -41,7 +42,8 @@ public class FabricReconcilerTest { reactContext.initializeWithInstance(catalystInstance); List viewManagers = new ArrayList<>(); ViewManagerRegistry viewManagerRegistry = new ViewManagerRegistry(viewManagers); - mFabricUIManager = new FabricUIManager(reactContext, viewManagerRegistry); + JavaScriptContextHolder jsContext = mock(JavaScriptContextHolder.class); + mFabricUIManager = new FabricUIManager(reactContext, viewManagerRegistry, jsContext); mMockUIViewOperationQueue = new MockUIViewOperationQueue(reactContext); mFabricReconciler = new FabricReconciler(mMockUIViewOperationQueue); } diff --git a/ReactAndroid/src/test/java/com/facebook/react/fabric/FabricUIManagerTest.java b/ReactAndroid/src/test/java/com/facebook/react/fabric/FabricUIManagerTest.java index 1b651817e..8d70d85f6 100644 --- a/ReactAndroid/src/test/java/com/facebook/react/fabric/FabricUIManagerTest.java +++ b/ReactAndroid/src/test/java/com/facebook/react/fabric/FabricUIManagerTest.java @@ -3,8 +3,10 @@ package com.facebook.react.fabric; import static org.fest.assertions.api.Assertions.assertThat; import static com.facebook.react.bridge.InstanceHandleHelper.randomInstanceHandle; +import static org.mockito.Mockito.mock; import com.facebook.react.ReactRootView; +import com.facebook.react.bridge.JavaScriptContextHolder; import com.facebook.react.bridge.ReactApplicationContext; import com.facebook.react.bridge.ReactTestHelper; import com.facebook.react.bridge.ReadableNativeMap; @@ -49,8 +51,8 @@ public class FabricUIManagerTest { Arrays.asList( new ReactViewManager(), new ReactTextViewManager(), new ReactRawTextManager()); ViewManagerRegistry viewManagerRegistry = new ViewManagerRegistry(viewManagers); - - mFabricUIManager = new FabricUIManager(reactContext, viewManagerRegistry); + JavaScriptContextHolder jsContext = mock(JavaScriptContextHolder.class); + mFabricUIManager = new FabricUIManager(reactContext, viewManagerRegistry, jsContext); } @Test