Binding for js events

Reviewed By: fkgozali

Differential Revision: D8181616

fbshipit-source-id: 5937c83f22ac09e3041fcb0f8d4e9e3026b2b397
This commit is contained in:
David Vacca 2018-05-30 21:49:20 -07:00 committed by Facebook Github Bot
parent 23fbd312aa
commit 0f10e03dd8
10 changed files with 92 additions and 44 deletions

View File

@ -261,7 +261,7 @@ public class ReactAppTestActivity extends FragmentActivity
List<ViewManager> 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;
}

View File

@ -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
);
}

View File

@ -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);
}
}

View File

@ -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);
}

View File

@ -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);
}
}
}

View File

@ -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);
}
}

View File

@ -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) {

View File

@ -115,7 +115,7 @@ public class EventDispatcher implements LifecycleEventListener,
for (EventDispatcherListener listener : mListeners) {
listener.onEventDispatch(event);
}
synchronized (mEventsStagingLock) {
mEventStaging.add(event);
Systrace.startAsyncFlow(

View File

@ -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<ViewManager> 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);
}

View File

@ -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.<ViewManager>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