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 307caf3c0..e7e6d95e3 100644 --- a/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactAppTestActivity.java +++ b/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactAppTestActivity.java @@ -7,11 +7,12 @@ package com.facebook.react.testing; +import static com.facebook.react.bridge.UiThreadUtil.runOnUiThread; + import android.content.Intent; import android.graphics.Bitmap; import android.os.Bundle; import android.support.v4.app.FragmentActivity; -import android.util.Log; import android.view.View; import android.view.ViewTreeObserver; import android.widget.FrameLayout; @@ -38,7 +39,7 @@ import com.facebook.react.testing.idledetection.ReactIdleDetectionUtil; import com.facebook.react.uimanager.UIImplementationProvider; import com.facebook.react.uimanager.ViewManager; import com.facebook.react.uimanager.ViewManagerRegistry; -import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; @@ -244,35 +245,28 @@ public class ReactAppTestActivity extends FragmentActivity .setBridgeIdleDebugListener(mBridgeIdleSignaler) .setInitialLifecycleState(mLifecycleState) .setJSIModulesProvider( - new JSIModulesProvider() { - @Override - public List getJSIModules( - final ReactApplicationContext reactApplicationContext, - final JavaScriptContextHolder jsContext) { + new JSIModulesProvider() { + @Override + public List getJSIModules( + final ReactApplicationContext reactApplicationContext, + final JavaScriptContextHolder jsContext) { + return Arrays.asList(new JSIModuleHolder() { + @Override + public Class getJSIModuleClass() { + return UIManager.class; + } - List modules = new ArrayList<>(); - modules.add( - new JSIModuleHolder() { - - @Override - public Class getJSIModuleClass() { - return UIManager.class; - } - - @Override - public FabricUIManager getJSIModule() { - List viewManagers = - getReactInstanceManager().getOrCreateViewManagers(reactApplicationContext); - FabricUIManager fabricUIManager = - new FabricUIManager( - reactApplicationContext, new ViewManagerRegistry(viewManagers)); - new FabricJSCBinding().installFabric(jsContext, fabricUIManager); - return fabricUIManager; - } - }); - - return modules; - }}) + @Override + public FabricUIManager getJSIModule() { + List viewManagers = + mReactInstanceManager.getOrCreateViewManagers(reactApplicationContext); + FabricUIManager fabricUIManager = + new FabricUIManager(reactApplicationContext, new ViewManagerRegistry(viewManagers)); + new FabricJSCBinding().installFabric(jsContext, fabricUIManager); + return fabricUIManager; + } + }); + }}) .setUIImplementationProvider(uiImplementationProvider); final CountDownLatch latch = new CountDownLatch(1); diff --git a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java index 45d678232..7363d1dda 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java @@ -82,6 +82,7 @@ import com.facebook.react.uimanager.DisplayMetricsHolder; import com.facebook.react.uimanager.UIImplementationProvider; import com.facebook.react.uimanager.UIManagerHelper; import com.facebook.react.uimanager.ViewManager; +import com.facebook.react.uimanager.events.EventDispatcher; import com.facebook.react.views.imagehelper.ResourceDrawableIdHelper; import com.facebook.soloader.SoLoader; import com.facebook.systrace.Systrace; @@ -1077,6 +1078,8 @@ public class ReactInstanceManager { ReactMarker.logMarker(CREATE_REACT_CONTEXT_START, jsExecutor.getName()); final ReactApplicationContext reactContext = new ReactApplicationContext(mApplicationContext); + reactContext.setEventDispatcher(new EventDispatcher(reactContext)); + NativeModuleCallExceptionHandler exceptionHandler = mNativeModuleCallExceptionHandler != null ? mNativeModuleCallExceptionHandler : mDevSupportManager; diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/EventDispatcher.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/EventDispatcher.java new file mode 100644 index 000000000..e596a4782 --- /dev/null +++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/EventDispatcher.java @@ -0,0 +1,13 @@ +/** + * Copyright (c) 2014-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ +package com.facebook.react.bridge; + +/** + * Marker interface for EventDispatcher. + */ +public interface EventDispatcher { +} diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/ReactContext.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/ReactContext.java index 713f5a7fd..cae4c7f5f 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/bridge/ReactContext.java +++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/ReactContext.java @@ -39,6 +39,7 @@ public class ReactContext extends ContextWrapper { private LifecycleState mLifecycleState = LifecycleState.BEFORE_CREATE; + private @Nullable EventDispatcher mEventDispatcher; private @Nullable CatalystInstance mCatalystInstance; private @Nullable LayoutInflater mInflater; private @Nullable MessageQueueThread mUiMessageQueueThread; @@ -349,4 +350,12 @@ public class ReactContext extends ContextWrapper { public JavaScriptContextHolder getJavaScriptContextHolder() { return mCatalystInstance.getJavaScriptContextHolder(); } + + public T getEventDispatcher() { + return (T) mEventDispatcher; + } + + public void setEventDispatcher(EventDispatcher eventDispatcher) { + mEventDispatcher = eventDispatcher; + } } diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/Scheduler.java b/ReactAndroid/src/main/java/com/facebook/react/fabric/Scheduler.java index 0f401f57e..87f7ce6db 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/Scheduler.java +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/Scheduler.java @@ -22,6 +22,7 @@ public class Scheduler { public void scheduleWork(Work work) { // TODO T26717866 this method needs to be implemented. The current implementation is just for // testing purpose. + work.run(); } diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModule.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModule.java index 3937f13de..5a7c7d1ce 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModule.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModule.java @@ -9,12 +9,11 @@ package com.facebook.react.uimanager; import static com.facebook.react.bridge.ReactMarkerConstants.CREATE_UI_MANAGER_MODULE_CONSTANTS_END; import static com.facebook.react.bridge.ReactMarkerConstants.CREATE_UI_MANAGER_MODULE_CONSTANTS_START; - import static com.facebook.react.uimanager.common.UIManagerType.DEFAULT; import android.content.ComponentCallbacks2; -import android.content.res.Configuration; import android.content.Context; +import android.content.res.Configuration; import android.media.AudioManager; import com.facebook.common.logging.FLog; import com.facebook.debug.holder.PrinterHolder; @@ -42,6 +41,7 @@ import com.facebook.react.uimanager.common.SizeMonitoringFrameLayout; import com.facebook.react.uimanager.common.ViewUtil; import com.facebook.react.uimanager.debug.NotThreadSafeViewHierarchyUpdateDebugListener; import com.facebook.react.uimanager.events.EventDispatcher; +import com.facebook.react.uimanager.events.RCTEventEmitter; import com.facebook.systrace.Systrace; import com.facebook.systrace.SystraceMessage; import java.util.ArrayList; @@ -129,7 +129,7 @@ public class UIManagerModule extends ReactContextBaseJavaModule implements int minTimeLeftInFrameForNonBatchedOperationMs) { super(reactContext); DisplayMetricsHolder.initDisplayMetricsIfNotInitialized(reactContext); - mEventDispatcher = new EventDispatcher(reactContext); + mEventDispatcher = reactContext.getEventDispatcher(); mModuleConstants = createConstants(viewManagerResolver); mCustomDirectEvents = UIManagerModuleConstants.getDirectEventTypeConstants(); mUIImplementation = @@ -149,7 +149,7 @@ public class UIManagerModule extends ReactContextBaseJavaModule implements int minTimeLeftInFrameForNonBatchedOperationMs) { super(reactContext); DisplayMetricsHolder.initDisplayMetricsIfNotInitialized(reactContext); - mEventDispatcher = new EventDispatcher(reactContext); + mEventDispatcher = reactContext.getEventDispatcher(); mCustomDirectEvents = MapBuilder.newHashMap(); mModuleConstants = createConstants(viewManagersList, null, mCustomDirectEvents); mUIImplementation = @@ -182,10 +182,14 @@ public class UIManagerModule extends ReactContextBaseJavaModule implements @Override public void initialize() { getReactApplicationContext().registerComponentCallbacks(mMemoryTrimCallback); + mEventDispatcher.registerEventEmitter( + DEFAULT, + getReactApplicationContext().getJSModule(RCTEventEmitter.class)); } @Override public void onHostResume() { + mUIImplementation.onHostResume(); } 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 7feddf17b..c613f8685 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 @@ -7,16 +7,7 @@ package com.facebook.react.uimanager.events; -import javax.annotation.Nullable; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Comparator; -import java.util.Map; -import java.util.concurrent.atomic.AtomicInteger; - import android.util.LongSparseArray; - import com.facebook.infer.annotation.Assertions; import com.facebook.react.bridge.LifecycleEventListener; import com.facebook.react.bridge.ReactApplicationContext; @@ -26,6 +17,12 @@ import com.facebook.react.modules.core.ChoreographerCompat; import com.facebook.react.modules.core.ReactChoreographer; import com.facebook.react.uimanager.common.UIManagerType; import com.facebook.systrace.Systrace; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Comparator; +import java.util.Map; +import java.util.concurrent.atomic.AtomicInteger; +import javax.annotation.Nullable; /** * Class responsible for dispatching UI events to JS. The main purpose of this class is to act as an @@ -59,7 +56,8 @@ import com.facebook.systrace.Systrace; * EVENT_TYPE_ID_MASK = 0x0000ffff00000000 * COALESCING_KEY_MASK = 0xffff000000000000 */ -public class EventDispatcher implements LifecycleEventListener { +public class EventDispatcher implements LifecycleEventListener, + com.facebook.react.bridge.EventDispatcher { private static final Comparator EVENT_COMPARATOR = new Comparator() { @Override @@ -99,7 +97,7 @@ public class EventDispatcher implements LifecycleEventListener { private Event[] mEventsToDispatch = new Event[16]; private int mEventsToDispatchSize = 0; - private volatile @Nullable RCTEventEmitter mRCTEventEmitter; + private volatile @Nullable ReactEventEmitter mRCTEventEmitter = new ReactEventEmitter(); private short mNextEventTypeId = 0; private volatile boolean mHasDispatchScheduled = false; @@ -153,9 +151,6 @@ public class EventDispatcher implements LifecycleEventListener { @Override public void onHostResume() { - if (mRCTEventEmitter == null) { - mRCTEventEmitter = mReactContext.getJSModule(RCTEventEmitter.class); - } mCurrentFrameCallback.maybePostFromNonUI(); } @@ -255,6 +250,10 @@ public class EventDispatcher implements LifecycleEventListener { (((long) coalescingKey) & 0xffff) << 48; } + public void registerEventEmitter(@UIManagerType int uiManagerType, RCTEventEmitter eventEmitter) { + mRCTEventEmitter.register(uiManagerType, eventEmitter); + } + private class ScheduleDispatchFrameCallback extends ChoreographerCompat.FrameCallback { private volatile boolean mIsPosted = false; private boolean mShouldStop = false; diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/events/RCTEventEmitter.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/events/RCTEventEmitter.java index b96418605..a46d0b3ea 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/events/RCTEventEmitter.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/events/RCTEventEmitter.java @@ -14,8 +14,8 @@ import com.facebook.react.bridge.WritableArray; import com.facebook.react.bridge.WritableMap; public interface RCTEventEmitter extends JavaScriptModule { - public void receiveEvent(int targetTag, String eventName, @Nullable WritableMap event); - public void receiveTouches( + void receiveEvent(int targetTag, String eventName, @Nullable WritableMap event); + void receiveTouches( String eventName, WritableArray touches, WritableArray changedIndices); diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/events/ReactEventEmitter.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/events/ReactEventEmitter.java new file mode 100644 index 000000000..713ce32db --- /dev/null +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/events/ReactEventEmitter.java @@ -0,0 +1,53 @@ +/** + * Copyright (c) 2014-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +package com.facebook.react.uimanager.events; + +import static com.facebook.react.uimanager.events.TouchesHelper.TARGET_KEY; + +import android.util.SparseArray; +import com.facebook.infer.annotation.Assertions; +import com.facebook.react.bridge.WritableArray; +import com.facebook.react.bridge.WritableMap; +import com.facebook.react.uimanager.common.UIManagerType; +import com.facebook.react.uimanager.common.ViewUtil; +import javax.annotation.Nullable; + +public class ReactEventEmitter implements RCTEventEmitter { + + private final SparseArray mEventEmitters = new SparseArray<>(); + + public ReactEventEmitter() { + } + + public void register(@UIManagerType int uiManagerType, RCTEventEmitter eventEmitter) { + mEventEmitters.put(uiManagerType, eventEmitter); + } + + @Override + public void receiveEvent(int targetReactTag, String eventName, @Nullable WritableMap event) { + getEventEmitter(targetReactTag).receiveEvent(targetReactTag, eventName, event); + } + + @Override + public void receiveTouches( + String eventName, + WritableArray touches, + WritableArray changedIndices) { + + Assertions.assertCondition(touches.size() > 0); + + int targetReactTag = touches.getMap(0).getInt(TARGET_KEY); + getEventEmitter(targetReactTag).receiveTouches(eventName, touches, changedIndices); + } + + private RCTEventEmitter getEventEmitter(int reactTag) { + int type = ViewUtil.getUIManagerType(reactTag); + return mEventEmitters.get(type); + } + +}