From c98981b19a1c18c2f75da27a5e091f9ae006d418 Mon Sep 17 00:00:00 2001 From: Ruslan Shestopalyuk Date: Fri, 3 Jan 2025 13:41:50 -0800 Subject: [PATCH] ReactEventEmitter -> Kotlin (#48464) Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/48464 # Changelog: [Internal] - As in the title. Reviewed By: christophpurrer Differential Revision: D67791375 --- .../ReactAndroid/api/ReactAndroid.api | 7 + .../uimanager/events/ReactEventEmitter.java | 165 ------------------ .../uimanager/events/ReactEventEmitter.kt | 136 +++++++++++++++ .../react/uimanager/events/TouchesHelper.kt | 2 +- 4 files changed, 144 insertions(+), 166 deletions(-) delete mode 100644 packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/events/ReactEventEmitter.java create mode 100644 packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/events/ReactEventEmitter.kt diff --git a/packages/react-native/ReactAndroid/api/ReactAndroid.api b/packages/react-native/ReactAndroid/api/ReactAndroid.api index 07a77e1e9189ea..86287d2524a1ec 100644 --- a/packages/react-native/ReactAndroid/api/ReactAndroid.api +++ b/packages/react-native/ReactAndroid/api/ReactAndroid.api @@ -5780,6 +5780,13 @@ public final class com/facebook/react/uimanager/events/TouchEventType$Companion public final fun getJSEventName (Lcom/facebook/react/uimanager/events/TouchEventType;)Ljava/lang/String; } +public final class com/facebook/react/uimanager/events/TouchesHelper { + public static final field INSTANCE Lcom/facebook/react/uimanager/events/TouchesHelper; + public static final field TARGET_KEY Ljava/lang/String; + public static final fun sendTouchEvent (Lcom/facebook/react/uimanager/events/RCTModernEventEmitter;Lcom/facebook/react/uimanager/events/TouchEvent;)V + public static final fun sendTouchesLegacy (Lcom/facebook/react/uimanager/events/RCTEventEmitter;Lcom/facebook/react/uimanager/events/TouchEvent;)V +} + public final class com/facebook/react/uimanager/layoutanimation/InterpolatorType : java/lang/Enum { public static final field Companion Lcom/facebook/react/uimanager/layoutanimation/InterpolatorType$Companion; public static final field EASE_IN Lcom/facebook/react/uimanager/layoutanimation/InterpolatorType; diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/events/ReactEventEmitter.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/events/ReactEventEmitter.java deleted file mode 100644 index 0b44b10c66b8de..00000000000000 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/events/ReactEventEmitter.java +++ /dev/null @@ -1,165 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * 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 androidx.annotation.Nullable; -import com.facebook.infer.annotation.Assertions; -import com.facebook.react.bridge.ReactApplicationContext; -import com.facebook.react.bridge.ReactNoCrashSoftException; -import com.facebook.react.bridge.ReactSoftExceptionLogger; -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; - -class ReactEventEmitter implements RCTModernEventEmitter { - - private static final String TAG = "ReactEventEmitter"; - - /** Corresponds to {@link com.facebook.react.fabric.events.FabricEventEmitter} */ - @Nullable private RCTModernEventEmitter mFabricEventEmitter = null; - - /** Corresponds to (Paper) EventEmitter, which is a JS interface */ - @Nullable private RCTEventEmitter mDefaultEventEmitter = null; - - private final ReactApplicationContext mReactContext; - - public ReactEventEmitter(ReactApplicationContext reactContext) { - mReactContext = reactContext; - } - - public void register(@UIManagerType int uiManagerType, RCTModernEventEmitter eventEmitter) { - assert uiManagerType == UIManagerType.FABRIC; - mFabricEventEmitter = eventEmitter; - } - - public void register(@UIManagerType int uiManagerType, RCTEventEmitter eventEmitter) { - assert uiManagerType == UIManagerType.DEFAULT; - mDefaultEventEmitter = eventEmitter; - } - - public void unregister(@UIManagerType int uiManagerType) { - if (uiManagerType == UIManagerType.DEFAULT) { - mDefaultEventEmitter = null; - } else { - mFabricEventEmitter = null; - } - } - - @Override - public void receiveEvent(int targetReactTag, String eventName, @Nullable WritableMap event) { - receiveEvent(-1, targetReactTag, eventName, event); - } - - @Override - public void receiveEvent( - int surfaceId, int targetTag, String eventName, @Nullable WritableMap event) { - // We assume this event can't be coalesced. `customCoalesceKey` has no meaning in Fabric. - receiveEvent(surfaceId, targetTag, eventName, false, 0, event, EventCategoryDef.UNSPECIFIED); - } - - @Override - public void receiveTouches( - String eventName, WritableArray touches, WritableArray changedIndices) { - /* - * This method should be unused by default processing pipeline, but leaving it here to make sure - * that any custom code using it in legacy renderer is compatible - */ - Assertions.assertCondition(touches.size() > 0); - - int reactTag = touches.getMap(0).getInt(TARGET_KEY); - @UIManagerType int uiManagerType = ViewUtil.getUIManagerType(reactTag); - if (uiManagerType == UIManagerType.DEFAULT && getDefaultEventEmitter() != null) { - mDefaultEventEmitter.receiveTouches(eventName, touches, changedIndices); - } - } - - @Override - public void receiveTouches(TouchEvent event) { - int reactTag = event.getViewTag(); - @UIManagerType - int uiManagerType = ViewUtil.getUIManagerType(event.getViewTag(), event.getSurfaceId()); - if (uiManagerType == UIManagerType.FABRIC && mFabricEventEmitter != null) { - TouchesHelper.sendTouchEvent(mFabricEventEmitter, event); - } else if (uiManagerType == UIManagerType.DEFAULT && getDefaultEventEmitter() != null) { - TouchesHelper.sendTouchesLegacy(mDefaultEventEmitter, event); - } else { - ReactSoftExceptionLogger.logSoftException( - TAG, - new ReactNoCrashSoftException( - "Cannot find EventEmitter for receivedTouches: ReactTag[" - + reactTag - + "] UIManagerType[" - + uiManagerType - + "] EventName[" - + event.getEventName() - + "]")); - } - } - - /** - * Get default/Paper event emitter. Callers should have verified that this is not an event for a - * View managed by Fabric - */ - @Nullable - private RCTEventEmitter getDefaultEventEmitter() { - if (mDefaultEventEmitter == null) { - if (mReactContext.hasActiveReactInstance()) { - mDefaultEventEmitter = mReactContext.getJSModule(RCTEventEmitter.class); - } else { - ReactSoftExceptionLogger.logSoftException( - TAG, - new ReactNoCrashSoftException( - "Cannot get RCTEventEmitter from Context, no active Catalyst instance!")); - } - } - return mDefaultEventEmitter; - } - - @Override - public void receiveEvent( - int surfaceId, - int targetReactTag, - String eventName, - boolean canCoalesceEvent, - int customCoalesceKey, - @Nullable WritableMap event, - @EventCategoryDef int category) { - @UIManagerType int uiManagerType = ViewUtil.getUIManagerType(targetReactTag, surfaceId); - if (uiManagerType == UIManagerType.FABRIC && mFabricEventEmitter != null) { - mFabricEventEmitter.receiveEvent( - surfaceId, - targetReactTag, - eventName, - canCoalesceEvent, - customCoalesceKey, - event, - category); - } else if (uiManagerType == UIManagerType.DEFAULT) { - RCTEventEmitter defaultEmitter = getDefaultEventEmitter(); - if (defaultEmitter != null) { - defaultEmitter.receiveEvent(targetReactTag, eventName, event); - } - } else { - ReactSoftExceptionLogger.logSoftException( - TAG, - new ReactNoCrashSoftException( - "Cannot find EventEmitter for receiveEvent: SurfaceId[" - + surfaceId - + "] ReactTag[" - + targetReactTag - + "] UIManagerType[" - + uiManagerType - + "] EventName[" - + eventName - + "]")); - } - } -} diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/events/ReactEventEmitter.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/events/ReactEventEmitter.kt new file mode 100644 index 00000000000000..53ad8d04d3d74b --- /dev/null +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/events/ReactEventEmitter.kt @@ -0,0 +1,136 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +// RCTEventEmitter usage throughout: +@file:Suppress("DEPRECATION") + +package com.facebook.react.uimanager.events + +import com.facebook.react.bridge.ReactApplicationContext +import com.facebook.react.bridge.ReactNoCrashSoftException +import com.facebook.react.bridge.ReactSoftExceptionLogger.logSoftException +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.getUIManagerType + +internal class ReactEventEmitter(private val reactContext: ReactApplicationContext) : + RCTModernEventEmitter { + /** Corresponds to [com.facebook.react.fabric.events.FabricEventEmitter] */ + private var fabricEventEmitter: RCTModernEventEmitter? = null + + /** Corresponds to (Paper) EventEmitter, which is a JS interface */ + private var defaultEventEmitter: RCTEventEmitter? = null + + fun register(@UIManagerType uiManagerType: Int, eventEmitter: RCTModernEventEmitter?) { + check(uiManagerType == UIManagerType.FABRIC) + fabricEventEmitter = eventEmitter + } + + fun register(@UIManagerType uiManagerType: Int, eventEmitter: RCTEventEmitter?) { + check(uiManagerType == UIManagerType.DEFAULT) + defaultEventEmitter = eventEmitter + } + + fun unregister(@UIManagerType uiManagerType: Int) { + if (uiManagerType == UIManagerType.DEFAULT) { + defaultEventEmitter = null + } else { + fabricEventEmitter = null + } + } + + @Deprecated("Please use RCTModernEventEmitter") + override fun receiveEvent(targetReactTag: Int, eventName: String, event: WritableMap?) { + receiveEvent(-1, targetReactTag, eventName, event) + } + + override fun receiveEvent( + surfaceId: Int, + targetTag: Int, + eventName: String, + event: WritableMap? + ) { + // We assume this event can't be coalesced. `customCoalesceKey` has no meaning in Fabric. + receiveEvent(surfaceId, targetTag, eventName, false, 0, event, EventCategoryDef.UNSPECIFIED) + } + + @Deprecated("Please use RCTModernEventEmitter") + override fun receiveTouches( + eventName: String, + touches: WritableArray, + changedIndices: WritableArray + ) { + /* + * This method should be unused by default processing pipeline, but leaving it here to make sure + * that any custom code using it in legacy renderer is compatible + */ + check(touches.size() > 0) + + val reactTag = touches.getMap(0)?.getInt(TouchesHelper.TARGET_KEY) ?: 0 + @UIManagerType val uiManagerType = getUIManagerType(reactTag) + if (uiManagerType == UIManagerType.DEFAULT) { + ensureDefaultEventEmitter()?.receiveTouches(eventName, touches, changedIndices) + } + } + + @Deprecated("Please use RCTModernEventEmitter") + override fun receiveTouches(event: TouchEvent) { + @UIManagerType val uiManagerType = getUIManagerType(event.viewTag, event.surfaceId) + if (uiManagerType == UIManagerType.FABRIC) { + fabricEventEmitter?.let { TouchesHelper.sendTouchEvent(it, event) } + } else if (uiManagerType == UIManagerType.DEFAULT) { + ensureDefaultEventEmitter()?.let { TouchesHelper.sendTouchesLegacy(it, event) } + } + } + + /** + * Get default/Paper event emitter. Callers should have verified that this is not an event for a + * View managed by Fabric + */ + private fun ensureDefaultEventEmitter(): RCTEventEmitter? { + if (defaultEventEmitter == null) { + if (reactContext.hasActiveReactInstance()) { + defaultEventEmitter = reactContext.getJSModule(RCTEventEmitter::class.java) + } else { + logSoftException( + TAG, + ReactNoCrashSoftException( + "Cannot get RCTEventEmitter from Context, no active Catalyst instance!")) + } + } + return defaultEventEmitter + } + + override fun receiveEvent( + surfaceId: Int, + targetReactTag: Int, + eventName: String, + canCoalesceEvent: Boolean, + customCoalesceKey: Int, + event: WritableMap?, + @EventCategoryDef category: Int + ) { + @UIManagerType val uiManagerType = getUIManagerType(targetReactTag, surfaceId) + if (uiManagerType == UIManagerType.FABRIC) { + fabricEventEmitter?.receiveEvent( + surfaceId, + targetReactTag, + eventName, + canCoalesceEvent, + customCoalesceKey, + event, + category) + } else if (uiManagerType == UIManagerType.DEFAULT) { + ensureDefaultEventEmitter()?.receiveEvent(targetReactTag, eventName, event) + } + } + + companion object { + private const val TAG = "ReactEventEmitter" + } +} diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/events/TouchesHelper.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/events/TouchesHelper.kt index 77f694d08ff79e..a51a181e3267d0 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/events/TouchesHelper.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/events/TouchesHelper.kt @@ -15,7 +15,7 @@ import com.facebook.react.uimanager.events.TouchEventType.Companion.getJSEventNa import com.facebook.systrace.Systrace /** Class responsible for generating catalyst touch events based on android [MotionEvent]. */ -internal object TouchesHelper { +public object TouchesHelper { @JvmField @Deprecated("Not used in New Architecture") public val TARGET_KEY: String = "target" private const val TARGET_SURFACE_KEY = "targetSurface"