From 5227fb265e0b5d9c78aa0b395a4f39720228bf20 Mon Sep 17 00:00:00 2001 From: Nicola Corti Date: Thu, 8 Aug 2024 02:37:45 -0700 Subject: [PATCH 1/2] Do not destroy views when there is a touch going on for New Architecture Summary: This diff introduces the logic to defer the destruction of ViewState (and EventEmitter) for views that are currently touched on by the user. The idea is to let the UIManager know which view is currently active from the `JSTouchDispatcher` and eventually defer the view deletion till the view is not interacted anymore. The JSTouchDispatcher already retains the information on which tag was the touch originally fired. We'll pass over that information to the UIManager/SurfaceMountingManager so that it can be accounted for when the view has to be deleted. This is causing a couple of bad bugs on Android: Fixes https://github.com/facebook/react-native/issues/45126 Fixes https://github.com/facebook/react-native/issues/44610 Changelog: [Android] [Fixed] - Do not destroy views when there is a touch going on for New Architecture Differential Revision: D60594878 --- .../ReactAndroid/api/ReactAndroid.api | 9 +++ .../com/facebook/react/ReactRootView.java | 2 +- .../com/facebook/react/bridge/UIManager.kt | 18 ++++++ .../react/fabric/FabricUIManager.java | 10 +++ .../mounting/SurfaceMountingManager.java | 42 +++++++++++-- .../react/runtime/ReactSurfaceView.kt | 3 +- .../react/uimanager/JSTouchDispatcher.java | 62 +++++++++++++++---- .../react/uimanager/UIManagerModule.java | 10 +++ .../react/views/modal/ReactModalHostView.kt | 4 +- .../facebook/testutils/fakes/FakeUIManager.kt | 42 ++++++++----- 10 files changed, 165 insertions(+), 37 deletions(-) diff --git a/packages/react-native/ReactAndroid/api/ReactAndroid.api b/packages/react-native/ReactAndroid/api/ReactAndroid.api index 0a3a9bbcc6cb..65b7d4c16e2c 100644 --- a/packages/react-native/ReactAndroid/api/ReactAndroid.api +++ b/packages/react-native/ReactAndroid/api/ReactAndroid.api @@ -1569,6 +1569,7 @@ public abstract interface class com/facebook/react/bridge/UIManager : com/facebo public abstract fun getEventDispatcher ()Ljava/lang/Object; public abstract fun initialize ()V public abstract fun invalidate ()V + public abstract fun markActiveTouchForTag (II)V public abstract fun receiveEvent (IILjava/lang/String;Lcom/facebook/react/bridge/WritableMap;)V public abstract fun receiveEvent (ILjava/lang/String;Lcom/facebook/react/bridge/WritableMap;)V public abstract fun removeUIManagerEventListener (Lcom/facebook/react/bridge/UIManagerListener;)V @@ -1577,6 +1578,7 @@ public abstract interface class com/facebook/react/bridge/UIManager : com/facebo public abstract fun sendAccessibilityEvent (II)V public abstract fun startSurface (Landroid/view/View;Ljava/lang/String;Lcom/facebook/react/bridge/WritableMap;II)I public abstract fun stopSurface (I)V + public abstract fun sweepActiveTouchForTag (II)V public abstract fun synchronouslyUpdateViewOnUIThread (ILcom/facebook/react/bridge/ReadableMap;)V public abstract fun updateRootLayoutSpecs (IIIII)V } @@ -2710,6 +2712,7 @@ public class com/facebook/react/fabric/FabricUIManager : com/facebook/react/brid public fun getThemeData (I[F)Z public fun initialize ()V public fun invalidate ()V + public fun markActiveTouchForTag (II)V public fun onAllAnimationsComplete ()V public fun onAnimationStarted ()V public fun onHostDestroy ()V @@ -2733,6 +2736,7 @@ public class com/facebook/react/fabric/FabricUIManager : com/facebook/react/brid public fun startSurface (Lcom/facebook/react/interfaces/fabric/SurfaceHandler;Landroid/content/Context;Landroid/view/View;)V public fun stopSurface (I)V public fun stopSurface (Lcom/facebook/react/interfaces/fabric/SurfaceHandler;)V + public fun sweepActiveTouchForTag (II)V public fun synchronouslyUpdateViewOnUIThread (ILcom/facebook/react/bridge/ReadableMap;)V public fun updateRootLayoutSpecs (IIIII)V } @@ -2888,6 +2892,7 @@ public class com/facebook/react/fabric/mounting/SurfaceMountingManager { public fun getViewExists (I)Z public fun isRootViewAttached ()Z public fun isStopped ()Z + public fun markActiveTouchForTag (I)V public fun preallocateView (Ljava/lang/String;ILcom/facebook/react/bridge/ReadableMap;Lcom/facebook/react/uimanager/StateWrapper;Z)V public fun printSurfaceState ()V public fun receiveCommand (IILcom/facebook/react/bridge/ReadableArray;)V @@ -2897,6 +2902,7 @@ public class com/facebook/react/fabric/mounting/SurfaceMountingManager { public fun sendAccessibilityEvent (II)V public fun setJSResponder (IIZ)V public fun stopSurface ()V + public fun sweepActiveTouchForTag (I)V public fun updateEventEmitter (ILcom/facebook/react/fabric/events/EventEmitterWrapper;)V public fun updateLayout (IIIIIIII)V public fun updateOverflowInset (IIIII)V @@ -4302,6 +4308,7 @@ public class com/facebook/react/uimanager/JSPointerDispatcher { public class com/facebook/react/uimanager/JSTouchDispatcher { public fun (Landroid/view/ViewGroup;)V public fun handleTouchEvent (Landroid/view/MotionEvent;Lcom/facebook/react/uimanager/events/EventDispatcher;)V + public fun handleTouchEvent (Landroid/view/MotionEvent;Lcom/facebook/react/uimanager/events/EventDispatcher;Lcom/facebook/react/bridge/ReactContext;)V public fun onChildEndedNativeGesture (Landroid/view/MotionEvent;Lcom/facebook/react/uimanager/events/EventDispatcher;)V public fun onChildStartedNativeGesture (Landroid/view/MotionEvent;Lcom/facebook/react/uimanager/events/EventDispatcher;)V } @@ -5284,6 +5291,7 @@ public class com/facebook/react/uimanager/UIManagerModule : com/facebook/react/b public fun invalidate ()V public fun invalidateNodeLayout (I)V public fun manageChildren (ILcom/facebook/react/bridge/ReadableArray;Lcom/facebook/react/bridge/ReadableArray;Lcom/facebook/react/bridge/ReadableArray;Lcom/facebook/react/bridge/ReadableArray;Lcom/facebook/react/bridge/ReadableArray;)V + public fun markActiveTouchForTag (II)V public fun measure (ILcom/facebook/react/bridge/Callback;)V public fun measureInWindow (ILcom/facebook/react/bridge/Callback;)V public fun measureLayout (IILcom/facebook/react/bridge/Callback;Lcom/facebook/react/bridge/Callback;)V @@ -5309,6 +5317,7 @@ public class com/facebook/react/uimanager/UIManagerModule : com/facebook/react/b public fun setViewLocalData (ILjava/lang/Object;)V public fun startSurface (Landroid/view/View;Ljava/lang/String;Lcom/facebook/react/bridge/WritableMap;II)I public fun stopSurface (I)V + public fun sweepActiveTouchForTag (II)V public fun synchronouslyUpdateViewOnUIThread (ILcom/facebook/react/bridge/ReadableMap;)V public fun updateNodeSize (III)V public fun updateRootLayoutSpecs (IIIII)V diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/ReactRootView.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/ReactRootView.java index f08550eebed9..4aa8d031e4e6 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/ReactRootView.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/ReactRootView.java @@ -360,7 +360,7 @@ protected void dispatchJSTouchEvent(MotionEvent event) { EventDispatcher eventDispatcher = UIManagerHelper.getEventDispatcher(getCurrentReactContext(), getUIManagerType()); if (eventDispatcher != null) { - mJSTouchDispatcher.handleTouchEvent(event, eventDispatcher); + mJSTouchDispatcher.handleTouchEvent(event, eventDispatcher, getCurrentReactContext()); } } diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridge/UIManager.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridge/UIManager.kt index b12de9737904..6aab9810556c 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridge/UIManager.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridge/UIManager.kt @@ -157,4 +157,22 @@ public interface UIManager : PerformanceCounter { /** Called before React Native instance is destroyed. */ public fun invalidate() + + /** + * Mark a view as currently active for a touch event. This information could be used by the + * [UIManager] to decide if a view could be safely destroyed or not. + * + * @param surfaceId The surface ID where the view is rendered. + * @param reactTag The react tag for the specific view + */ + public fun markActiveTouchForTag(surfaceId: Int, reactTag: Int) + + /** + * Sweep a view as currently not active for a touch event. This tells the [UIManager] that the + * view is not being interacted by the user and can safely be destroyed. + * + * @param surfaceId The surface ID where the view is rendered. + * @param reactTag The react tag for the specific view + */ + public fun sweepActiveTouchForTag(surfaceId: Int, reactTag: Int) } diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java index db5fa13e85fb..fa79f0df2683 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java @@ -452,6 +452,16 @@ public void invalidate() { } } + @Override + public void markActiveTouchForTag(int surfaceId, int reactTag) { + mMountingManager.getSurfaceManager(surfaceId).markActiveTouchForTag(reactTag); + } + + @Override + public void sweepActiveTouchForTag(int surfaceId, int reactTag) { + mMountingManager.getSurfaceManager(surfaceId).sweepActiveTouchForTag(reactTag); + } + /** * Method added to Fabric for backward compatibility reasons, as users on Paper could call * [addUiBlock] and [prependUiBlock] on UIManagerModule. diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/SurfaceMountingManager.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/SurfaceMountingManager.java index 0c58c4cf2177..d8516050fdc8 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/SurfaceMountingManager.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/SurfaceMountingManager.java @@ -76,6 +76,17 @@ public class SurfaceMountingManager { @ThreadConfined(UI) private final Set mErroneouslyReaddedReactTags = new HashSet<>(); + // This set is used to keep track of views that are currently being interacted with (i.e. + // views that saw a ACTION_DOWN but not a ACTION_UP event yet). This is used to prevent + // views from being removed while they are being interacted with as their event emitter will + // also be removed, and `Pressables` will look "stuck". + @ThreadConfined(UI) + private final Set mViewsWithActiveTouches = new HashSet<>(); + + // This set contains the views that are scheduled to be removed after their touch finishes. + @ThreadConfined(UI) + private final Set mViewsToDeleteAfterTouchFinishes = new HashSet<>(); + // This is null *until* StopSurface is called. private SparseArrayCompat mTagSetForStoppedSurface; @@ -1031,12 +1042,21 @@ public void deleteView(int reactTag) { return; } - // To delete we simply remove the tag from the registry. - // We want to rely on the correct set of MountInstructions being sent to the platform, - // or StopSurface being called, so we do not handle deleting descendents of the View. - mTagToViewState.remove(reactTag); + if (mViewsWithActiveTouches.contains(reactTag)) { + // If the view that went offscreen is still being touched, we can't delete it yet. + // We have to delay the deletion till the touch is completed. + // This is causing bugs like those otherwise: + // - https://github.com/facebook/react-native/issues/44610 + // - https://github.com/facebook/react-native/issues/45126 + mViewsToDeleteAfterTouchFinishes.add(reactTag); + } else { + // To delete we simply remove the tag from the registry. + // We want to rely on the correct set of MountInstructions being sent to the platform, + // or StopSurface being called, so we do not handle deleting descendants of the View. + mTagToViewState.remove(reactTag); - onViewStateDeleted(viewState); + onViewStateDeleted(viewState); + } } @UiThread @@ -1160,6 +1180,18 @@ public void run() { }); } + public void markActiveTouchForTag(int reactTag) { + mViewsWithActiveTouches.add(reactTag); + } + + public void sweepActiveTouchForTag(int reactTag) { + mViewsWithActiveTouches.remove(reactTag); + if (mViewsToDeleteAfterTouchFinishes.contains(reactTag)) { + mViewsToDeleteAfterTouchFinishes.remove(reactTag); + deleteView(reactTag); + } + } + /** * This class holds view state for react tags. Objects of this class are stored into the {@link * #mTagToViewState}, and they should be updated in the same thread. diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/runtime/ReactSurfaceView.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/runtime/ReactSurfaceView.kt index bc979de9c329..d926007ff259 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/runtime/ReactSurfaceView.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/runtime/ReactSurfaceView.kt @@ -139,7 +139,8 @@ public class ReactSurfaceView(context: Context?, private val surface: ReactSurfa override fun dispatchJSTouchEvent(event: MotionEvent) { val eventDispatcher = surface.eventDispatcher if (eventDispatcher != null) { - jsTouchDispatcher.handleTouchEvent(event, eventDispatcher) + jsTouchDispatcher.handleTouchEvent( + event, eventDispatcher, surface.reactHost.currentReactContext) } else { FLog.w( TAG, "Unable to dispatch touch events to JS as the React instance has not been attached") diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/JSTouchDispatcher.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/JSTouchDispatcher.java index 77143c90e30f..fb4537f418a9 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/JSTouchDispatcher.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/JSTouchDispatcher.java @@ -9,10 +9,14 @@ import android.view.MotionEvent; import android.view.ViewGroup; +import androidx.annotation.Nullable; import com.facebook.common.logging.FLog; import com.facebook.infer.annotation.Assertions; import com.facebook.infer.annotation.Nullsafe; +import com.facebook.react.bridge.ReactContext; +import com.facebook.react.bridge.UIManager; import com.facebook.react.common.ReactConstants; +import com.facebook.react.uimanager.common.UIManagerType; import com.facebook.react.uimanager.events.EventDispatcher; import com.facebook.react.uimanager.events.TouchEvent; import com.facebook.react.uimanager.events.TouchEventCoalescingKeyHelper; @@ -30,12 +34,14 @@ public class JSTouchDispatcher { private final float[] mTargetCoordinates = new float[2]; private boolean mChildIsHandlingNativeGesture = false; private long mGestureStartTime = TouchEvent.UNSET; - private final ViewGroup mRootViewGroup; + + private final ViewGroup mViewGroup; + private final TouchEventCoalescingKeyHelper mTouchEventCoalescingKeyHelper = new TouchEventCoalescingKeyHelper(); public JSTouchDispatcher(ViewGroup viewGroup) { - mRootViewGroup = viewGroup; + mViewGroup = viewGroup; } public void onChildStartedNativeGesture( @@ -57,6 +63,10 @@ public void onChildEndedNativeGesture(MotionEvent androidEvent, EventDispatcher mChildIsHandlingNativeGesture = false; } + public void handleTouchEvent(MotionEvent ev, EventDispatcher eventDispatcher) { + handleTouchEvent(ev, eventDispatcher, null); + } + /** * Main catalyst view is responsible for collecting and sending touch events to JS. This method * reacts for an incoming android native touch events ({@link MotionEvent}) and calls into {@link @@ -65,7 +75,8 @@ public void onChildEndedNativeGesture(MotionEvent androidEvent, EventDispatcher * method for figuring out a react view ID in the case of ACTION_DOWN event (when the gesture * starts). */ - public void handleTouchEvent(MotionEvent ev, EventDispatcher eventDispatcher) { + public void handleTouchEvent( + MotionEvent ev, EventDispatcher eventDispatcher, @Nullable ReactContext reactContext) { int action = ev.getAction() & MotionEvent.ACTION_MASK; if (action == MotionEvent.ACTION_DOWN) { if (mTargetTag != -1) { @@ -78,11 +89,13 @@ public void handleTouchEvent(MotionEvent ev, EventDispatcher eventDispatcher) { // this gesture mChildIsHandlingNativeGesture = false; mGestureStartTime = ev.getEventTime(); - mTargetTag = findTargetTagAndSetCoordinates(ev); + int surfaceId = UIManagerHelper.getSurfaceId(mViewGroup); + markActiveTouchForTag(surfaceId, mTargetTag, reactContext); + eventDispatcher.dispatchEvent( TouchEvent.obtain( - UIManagerHelper.getSurfaceId(mRootViewGroup), + UIManagerHelper.getSurfaceId(mViewGroup), mTargetTag, TouchEventType.START, ev, @@ -105,9 +118,10 @@ public void handleTouchEvent(MotionEvent ev, EventDispatcher eventDispatcher) { // End of the gesture. We reset target tag to -1 and expect no further event associated with // this gesture. findTargetTagAndSetCoordinates(ev); + int surfaceId = UIManagerHelper.getSurfaceId(mViewGroup); eventDispatcher.dispatchEvent( TouchEvent.obtain( - UIManagerHelper.getSurfaceId(mRootViewGroup), + surfaceId, mTargetTag, TouchEventType.END, ev, @@ -115,6 +129,7 @@ public void handleTouchEvent(MotionEvent ev, EventDispatcher eventDispatcher) { mTargetCoordinates[0], mTargetCoordinates[1], mTouchEventCoalescingKeyHelper)); + sweepActiveTouchForTag(surfaceId, mTargetTag, reactContext); mTargetTag = -1; mGestureStartTime = TouchEvent.UNSET; } else if (action == MotionEvent.ACTION_MOVE) { @@ -122,7 +137,7 @@ public void handleTouchEvent(MotionEvent ev, EventDispatcher eventDispatcher) { findTargetTagAndSetCoordinates(ev); eventDispatcher.dispatchEvent( TouchEvent.obtain( - UIManagerHelper.getSurfaceId(mRootViewGroup), + UIManagerHelper.getSurfaceId(mViewGroup), mTargetTag, TouchEventType.MOVE, ev, @@ -134,7 +149,7 @@ public void handleTouchEvent(MotionEvent ev, EventDispatcher eventDispatcher) { // New pointer goes down, this can only happen after ACTION_DOWN is sent for the first pointer eventDispatcher.dispatchEvent( TouchEvent.obtain( - UIManagerHelper.getSurfaceId(mRootViewGroup), + UIManagerHelper.getSurfaceId(mViewGroup), mTargetTag, TouchEventType.START, ev, @@ -146,7 +161,7 @@ public void handleTouchEvent(MotionEvent ev, EventDispatcher eventDispatcher) { // Exactly one of the pointers goes up eventDispatcher.dispatchEvent( TouchEvent.obtain( - UIManagerHelper.getSurfaceId(mRootViewGroup), + UIManagerHelper.getSurfaceId(mViewGroup), mTargetTag, TouchEventType.END, ev, @@ -162,6 +177,9 @@ public void handleTouchEvent(MotionEvent ev, EventDispatcher eventDispatcher) { ReactConstants.TAG, "Received an ACTION_CANCEL touch event for which we have no corresponding ACTION_DOWN"); } + int surfaceId = UIManagerHelper.getSurfaceId(mViewGroup); + sweepActiveTouchForTag(surfaceId, mTargetTag, reactContext); + mTargetTag = -1; mGestureStartTime = TouchEvent.UNSET; } else { @@ -171,10 +189,32 @@ public void handleTouchEvent(MotionEvent ev, EventDispatcher eventDispatcher) { } } + private void markActiveTouchForTag( + int surfaceId, int reactTag, @Nullable ReactContext reactContext) { + if (reactContext == null) { + return; + } + UIManager uiManager = UIManagerHelper.getUIManager(reactContext, UIManagerType.FABRIC); + if (uiManager != null) { + uiManager.markActiveTouchForTag(surfaceId, reactTag); + } + } + + private void sweepActiveTouchForTag( + int surfaceId, int reactTag, @Nullable ReactContext reactContext) { + if (reactContext == null) { + return; + } + UIManager uiManager = UIManagerHelper.getUIManager(reactContext, UIManagerType.FABRIC); + if (uiManager != null) { + uiManager.sweepActiveTouchForTag(surfaceId, reactTag); + } + } + private int findTargetTagAndSetCoordinates(MotionEvent ev) { // This method updates `mTargetCoordinates` with coordinates for the motion event. return TouchTargetHelper.findTargetTagAndCoordinatesForTouch( - ev.getX(), ev.getY(), mRootViewGroup, mTargetCoordinates, null); + ev.getX(), ev.getY(), mViewGroup, mTargetCoordinates, null); } private void dispatchCancelEvent(MotionEvent androidEvent, EventDispatcher eventDispatcher) { @@ -195,7 +235,7 @@ private void dispatchCancelEvent(MotionEvent androidEvent, EventDispatcher event Assertions.assertNotNull(eventDispatcher) .dispatchEvent( TouchEvent.obtain( - UIManagerHelper.getSurfaceId(mRootViewGroup), + UIManagerHelper.getSurfaceId(mViewGroup), mTargetTag, TouchEventType.CANCEL, androidEvent, diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModule.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModule.java index 09862f765d9d..ea72dc0ca175 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModule.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModule.java @@ -207,6 +207,16 @@ public void invalidate() { ViewManagerPropertyUpdater.clear(); } + @Override + public void markActiveTouchForTag(int surfaceId, int reactTag) { + // Not implemented for Paper. + } + + @Override + public void sweepActiveTouchForTag(int surfaceId, int reactTag) { + // Not implemented for Paper. + } + /** * This method is intended to reuse the {@link ViewManagerRegistry} with FabricUIManager. Do not * use this method as this will be removed in the near future. diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/modal/ReactModalHostView.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/modal/ReactModalHostView.kt index f6e0d82fc01a..3a5841b1c7bc 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/modal/ReactModalHostView.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/modal/ReactModalHostView.kt @@ -483,7 +483,7 @@ public class ReactModalHostView(context: ThemedReactContext) : override fun onInterceptTouchEvent(event: MotionEvent): Boolean { eventDispatcher?.let { eventDispatcher -> - jSTouchDispatcher.handleTouchEvent(event, eventDispatcher) + jSTouchDispatcher.handleTouchEvent(event, eventDispatcher, reactContext) jSPointerDispatcher?.handleMotionEvent(event, eventDispatcher, true) } return super.onInterceptTouchEvent(event) @@ -492,7 +492,7 @@ public class ReactModalHostView(context: ThemedReactContext) : @SuppressLint("ClickableViewAccessibility") override fun onTouchEvent(event: MotionEvent): Boolean { eventDispatcher?.let { eventDispatcher -> - jSTouchDispatcher.handleTouchEvent(event, eventDispatcher) + jSTouchDispatcher.handleTouchEvent(event, eventDispatcher, reactContext) jSPointerDispatcher?.handleMotionEvent(event, eventDispatcher, false) } super.onTouchEvent(event) diff --git a/packages/react-native/ReactAndroid/src/test/java/com/facebook/testutils/fakes/FakeUIManager.kt b/packages/react-native/ReactAndroid/src/test/java/com/facebook/testutils/fakes/FakeUIManager.kt index c51c01483290..55f287820a58 100644 --- a/packages/react-native/ReactAndroid/src/test/java/com/facebook/testutils/fakes/FakeUIManager.kt +++ b/packages/react-native/ReactAndroid/src/test/java/com/facebook/testutils/fakes/FakeUIManager.kt @@ -25,12 +25,12 @@ class FakeUIManager : UIManager, UIBlockViewResolver { var resolvedViewCount = 0 override fun profileNextBatch() { - TODO("Not yet implemented") + error("Not yet implemented") } @Deprecated("") override fun addRootView(rootView: T, initialProps: WritableMap?): Int { - TODO("Not yet implemented") + error("Not yet implemented") } override fun startSurface( @@ -40,11 +40,11 @@ class FakeUIManager : UIManager, UIBlockViewResolver { widthMeasureSpec: Int, heightMeasureSpec: Int ): Int { - TODO("Not yet implemented") + error("Not yet implemented") } override fun stopSurface(surfaceId: Int) { - TODO("Not yet implemented") + error("Not yet implemented") } override fun updateRootLayoutSpecs( @@ -54,35 +54,35 @@ class FakeUIManager : UIManager, UIBlockViewResolver { offsetX: Int, offsetY: Int ) { - TODO("Not yet implemented") + error("Not yet implemented") } override fun dispatchCommand(reactTag: Int, commandId: Int, commandArgs: ReadableArray?) { - TODO("Not yet implemented") + error("Not yet implemented") } override fun dispatchCommand(reactTag: Int, commandId: String, commandArgs: ReadableArray?) { - TODO("Not yet implemented") + error("Not yet implemented") } override fun getEventDispatcher(): T { - TODO("Not yet implemented") + error("Not yet implemented") } override fun synchronouslyUpdateViewOnUIThread(reactTag: Int, props: ReadableMap?) { - TODO("Not yet implemented") + error("Not yet implemented") } override fun sendAccessibilityEvent(reactTag: Int, eventType: Int) { - TODO("Not yet implemented") + error("Not yet implemented") } override fun addUIManagerEventListener(listener: UIManagerListener?) { - TODO("Not yet implemented") + error("Not yet implemented") } override fun removeUIManagerEventListener(listener: UIManagerListener?) { - TODO("Not yet implemented") + error("Not yet implemented") } override fun resolveView(reactTag: Int): View? { @@ -92,24 +92,32 @@ class FakeUIManager : UIManager, UIBlockViewResolver { @Deprecated("") override fun receiveEvent(reactTag: Int, eventName: String, event: WritableMap?) { - TODO("Not yet implemented") + error("Not yet implemented") } override fun receiveEvent(surfaceId: Int, reactTag: Int, eventName: String, event: WritableMap?) { - TODO("Not yet implemented") + error("Not yet implemented") } @Deprecated("") override fun resolveCustomDirectEventName(eventName: String): String? { - TODO("Not yet implemented") + error("Not yet implemented") } override fun initialize() { - TODO("Not yet implemented") + error("Not yet implemented") } override fun invalidate() { - TODO("Not yet implemented") + error("Not yet implemented") + } + + override fun markActiveTouchForTag(surfaceId: Int, reactTag: Int) { + error("Not yet implemented") + } + + override fun sweepActiveTouchForTag(surfaceId: Int, reactTag: Int) { + error("Not yet implemented") } override val performanceCounters: Map? From 7e1f4897342fb2596246c9310c448727982ce023 Mon Sep 17 00:00:00 2001 From: Nicola Corti Date: Thu, 8 Aug 2024 02:44:42 -0700 Subject: [PATCH 2/2] Introduce the enableEventEmitterRetentionDuringGesturesOnAndroid to gate the Pressable fix (#45930) Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/45930 This introduces the `enableEventEmitterRetentionDuringGesturesOnAndroid` that allows us to gate the fix for bug #45126 and #44610. Changelog: [Internal] [Changed] - Introduce the enableEventEmitterRetentionDuringGesturesOnAndroid to gate the Pressable fix Reviewed By: mdvacca Differential Revision: D60908117 --- .../DefaultNewArchitectureEntryPoint.kt | 5 ++ .../mounting/SurfaceMountingManager.java | 9 +- .../featureflags/ReactNativeFeatureFlags.kt | 8 +- .../ReactNativeFeatureFlagsCxxAccessor.kt | 12 ++- .../ReactNativeFeatureFlagsCxxInterop.kt | 4 +- .../ReactNativeFeatureFlagsDefaults.kt | 4 +- .../ReactNativeFeatureFlagsLocalAccessor.kt | 13 ++- .../ReactNativeFeatureFlagsProvider.kt | 4 +- .../react/uimanager/JSTouchDispatcher.java | 7 ++ .../JReactNativeFeatureFlagsCxxInterop.cpp | 16 +++- .../JReactNativeFeatureFlagsCxxInterop.h | 5 +- .../featureflags/ReactNativeFeatureFlags.cpp | 6 +- .../featureflags/ReactNativeFeatureFlags.h | 7 +- .../ReactNativeFeatureFlagsAccessor.cpp | 86 +++++++++++-------- .../ReactNativeFeatureFlagsAccessor.h | 6 +- .../ReactNativeFeatureFlagsDefaults.h | 6 +- .../ReactNativeFeatureFlagsProvider.h | 3 +- .../NativeReactNativeFeatureFlags.cpp | 7 +- .../NativeReactNativeFeatureFlags.h | 4 +- .../ReactNativeFeatureFlags.config.js | 5 ++ .../featureflags/ReactNativeFeatureFlags.js | 7 +- .../specs/NativeReactNativeFeatureFlags.js | 3 +- 22 files changed, 174 insertions(+), 53 deletions(-) diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/defaults/DefaultNewArchitectureEntryPoint.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/defaults/DefaultNewArchitectureEntryPoint.kt index d7bf878a38b0..38b3be0c8839 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/defaults/DefaultNewArchitectureEntryPoint.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/defaults/DefaultNewArchitectureEntryPoint.kt @@ -46,6 +46,11 @@ public object DefaultNewArchitectureEntryPoint { ReactNativeFeatureFlags.override( object : ReactNativeNewArchitectureFeatureFlagsDefaults(newArchitectureEnabled = true) { override fun useFabricInterop(): Boolean = fabricEnabled + + // We turn this feature flag to true for OSS to fix #44610 and #45126 and other + // similar bugs related to pressable. + override fun enableEventEmitterRetentionDuringGesturesOnAndroid(): Boolean = + fabricEnabled }) } diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/SurfaceMountingManager.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/SurfaceMountingManager.java index d8516050fdc8..feef4f1eb035 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/SurfaceMountingManager.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/SurfaceMountingManager.java @@ -1042,7 +1042,8 @@ public void deleteView(int reactTag) { return; } - if (mViewsWithActiveTouches.contains(reactTag)) { + if (ReactNativeFeatureFlags.enableEventEmitterRetentionDuringGesturesOnAndroid() + && mViewsWithActiveTouches.contains(reactTag)) { // If the view that went offscreen is still being touched, we can't delete it yet. // We have to delay the deletion till the touch is completed. // This is causing bugs like those otherwise: @@ -1181,10 +1182,16 @@ public void run() { } public void markActiveTouchForTag(int reactTag) { + if (!ReactNativeFeatureFlags.enableEventEmitterRetentionDuringGesturesOnAndroid()) { + return; + } mViewsWithActiveTouches.add(reactTag); } public void sweepActiveTouchForTag(int reactTag) { + if (!ReactNativeFeatureFlags.enableEventEmitterRetentionDuringGesturesOnAndroid()) { + return; + } mViewsWithActiveTouches.remove(reactTag); if (mViewsToDeleteAfterTouchFinishes.contains(reactTag)) { mViewsToDeleteAfterTouchFinishes.remove(reactTag); diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlags.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlags.kt index cf54437762cf..275f6fbe871e 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlags.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlags.kt @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<<11bd299e21bf2eb1c320e657885826e4>> + * @generated SignedSource<<275859c437f60e7733da2b238c911152>> */ /** @@ -88,6 +88,12 @@ public object ReactNativeFeatureFlags { @JvmStatic public fun enableEagerRootViewAttachment(): Boolean = accessor.enableEagerRootViewAttachment() + /** + * Enables the retention of EventEmitterWrapper on Android till the touch gesture is over to fix a bug on pressable (#44610) + */ + @JvmStatic + public fun enableEventEmitterRetentionDuringGesturesOnAndroid(): Boolean = accessor.enableEventEmitterRetentionDuringGesturesOnAndroid() + /** * This feature flag enables logs for Fabric. */ diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsCxxAccessor.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsCxxAccessor.kt index e0cfeb5f0adf..6c32b6fddcad 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsCxxAccessor.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsCxxAccessor.kt @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<> + * @generated SignedSource<> */ /** @@ -30,6 +30,7 @@ public class ReactNativeFeatureFlagsCxxAccessor : ReactNativeFeatureFlagsAccesso private var enableBackgroundStyleApplicatorCache: Boolean? = null private var enableCleanTextInputYogaNodeCache: Boolean? = null private var enableEagerRootViewAttachmentCache: Boolean? = null + private var enableEventEmitterRetentionDuringGesturesOnAndroidCache: Boolean? = null private var enableFabricLogsCache: Boolean? = null private var enableFabricRendererExclusivelyCache: Boolean? = null private var enableGranularShadowTreeStateReconciliationCache: Boolean? = null @@ -154,6 +155,15 @@ public class ReactNativeFeatureFlagsCxxAccessor : ReactNativeFeatureFlagsAccesso return cached } + override fun enableEventEmitterRetentionDuringGesturesOnAndroid(): Boolean { + var cached = enableEventEmitterRetentionDuringGesturesOnAndroidCache + if (cached == null) { + cached = ReactNativeFeatureFlagsCxxInterop.enableEventEmitterRetentionDuringGesturesOnAndroid() + enableEventEmitterRetentionDuringGesturesOnAndroidCache = cached + } + return cached + } + override fun enableFabricLogs(): Boolean { var cached = enableFabricLogsCache if (cached == null) { diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsCxxInterop.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsCxxInterop.kt index 3b15ce274633..51ff0117ac27 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsCxxInterop.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsCxxInterop.kt @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<> + * @generated SignedSource<<1d79b037e6e8cf2e7306b7f5b3798b9a>> */ /** @@ -48,6 +48,8 @@ public object ReactNativeFeatureFlagsCxxInterop { @DoNotStrip @JvmStatic public external fun enableEagerRootViewAttachment(): Boolean + @DoNotStrip @JvmStatic public external fun enableEventEmitterRetentionDuringGesturesOnAndroid(): Boolean + @DoNotStrip @JvmStatic public external fun enableFabricLogs(): Boolean @DoNotStrip @JvmStatic public external fun enableFabricRendererExclusively(): Boolean diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsDefaults.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsDefaults.kt index 16514aa88abc..96948995e2d0 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsDefaults.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsDefaults.kt @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<<06c99ad6853216864f14c96fdc9704dd>> + * @generated SignedSource<> */ /** @@ -43,6 +43,8 @@ public open class ReactNativeFeatureFlagsDefaults : ReactNativeFeatureFlagsProvi override fun enableEagerRootViewAttachment(): Boolean = false + override fun enableEventEmitterRetentionDuringGesturesOnAndroid(): Boolean = false + override fun enableFabricLogs(): Boolean = false override fun enableFabricRendererExclusively(): Boolean = false diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsLocalAccessor.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsLocalAccessor.kt index 02a2f9ed372b..903f978fd9f2 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsLocalAccessor.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsLocalAccessor.kt @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<> + * @generated SignedSource<<408d66cdad8b708c06ca844cd6524ba4>> */ /** @@ -34,6 +34,7 @@ public class ReactNativeFeatureFlagsLocalAccessor : ReactNativeFeatureFlagsAcces private var enableBackgroundStyleApplicatorCache: Boolean? = null private var enableCleanTextInputYogaNodeCache: Boolean? = null private var enableEagerRootViewAttachmentCache: Boolean? = null + private var enableEventEmitterRetentionDuringGesturesOnAndroidCache: Boolean? = null private var enableFabricLogsCache: Boolean? = null private var enableFabricRendererExclusivelyCache: Boolean? = null private var enableGranularShadowTreeStateReconciliationCache: Boolean? = null @@ -168,6 +169,16 @@ public class ReactNativeFeatureFlagsLocalAccessor : ReactNativeFeatureFlagsAcces return cached } + override fun enableEventEmitterRetentionDuringGesturesOnAndroid(): Boolean { + var cached = enableEventEmitterRetentionDuringGesturesOnAndroidCache + if (cached == null) { + cached = currentProvider.enableEventEmitterRetentionDuringGesturesOnAndroid() + accessedFeatureFlags.add("enableEventEmitterRetentionDuringGesturesOnAndroid") + enableEventEmitterRetentionDuringGesturesOnAndroidCache = cached + } + return cached + } + override fun enableFabricLogs(): Boolean { var cached = enableFabricLogsCache if (cached == null) { diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsProvider.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsProvider.kt index 8d6c9dc44683..e1db6abce717 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsProvider.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsProvider.kt @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<<6c32d13e793895356e70e01c2fa784b6>> + * @generated SignedSource<<040b9cb9cec727e2eb31769712980528>> */ /** @@ -43,6 +43,8 @@ public interface ReactNativeFeatureFlagsProvider { @DoNotStrip public fun enableEagerRootViewAttachment(): Boolean + @DoNotStrip public fun enableEventEmitterRetentionDuringGesturesOnAndroid(): Boolean + @DoNotStrip public fun enableFabricLogs(): Boolean @DoNotStrip public fun enableFabricRendererExclusively(): Boolean diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/JSTouchDispatcher.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/JSTouchDispatcher.java index fb4537f418a9..d763bcb4f48b 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/JSTouchDispatcher.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/JSTouchDispatcher.java @@ -16,6 +16,7 @@ import com.facebook.react.bridge.ReactContext; import com.facebook.react.bridge.UIManager; import com.facebook.react.common.ReactConstants; +import com.facebook.react.internal.featureflags.ReactNativeFeatureFlags; import com.facebook.react.uimanager.common.UIManagerType; import com.facebook.react.uimanager.events.EventDispatcher; import com.facebook.react.uimanager.events.TouchEvent; @@ -191,6 +192,9 @@ public void handleTouchEvent( private void markActiveTouchForTag( int surfaceId, int reactTag, @Nullable ReactContext reactContext) { + if (!ReactNativeFeatureFlags.enableEventEmitterRetentionDuringGesturesOnAndroid()) { + return; + } if (reactContext == null) { return; } @@ -202,6 +206,9 @@ private void markActiveTouchForTag( private void sweepActiveTouchForTag( int surfaceId, int reactTag, @Nullable ReactContext reactContext) { + if (!ReactNativeFeatureFlags.enableEventEmitterRetentionDuringGesturesOnAndroid()) { + return; + } if (reactContext == null) { return; } diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/featureflags/JReactNativeFeatureFlagsCxxInterop.cpp b/packages/react-native/ReactAndroid/src/main/jni/react/featureflags/JReactNativeFeatureFlagsCxxInterop.cpp index 49120d82a171..71924a1f99f7 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/featureflags/JReactNativeFeatureFlagsCxxInterop.cpp +++ b/packages/react-native/ReactAndroid/src/main/jni/react/featureflags/JReactNativeFeatureFlagsCxxInterop.cpp @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<<12c6250b601db5f8db15dc1bed57405c>> + * @generated SignedSource<> */ /** @@ -99,6 +99,12 @@ class ReactNativeFeatureFlagsProviderHolder return method(javaProvider_); } + bool enableEventEmitterRetentionDuringGesturesOnAndroid() override { + static const auto method = + getReactNativeFeatureFlagsProviderJavaClass()->getMethod("enableEventEmitterRetentionDuringGesturesOnAndroid"); + return method(javaProvider_); + } + bool enableFabricLogs() override { static const auto method = getReactNativeFeatureFlagsProviderJavaClass()->getMethod("enableFabricLogs"); @@ -351,6 +357,11 @@ bool JReactNativeFeatureFlagsCxxInterop::enableEagerRootViewAttachment( return ReactNativeFeatureFlags::enableEagerRootViewAttachment(); } +bool JReactNativeFeatureFlagsCxxInterop::enableEventEmitterRetentionDuringGesturesOnAndroid( + facebook::jni::alias_ref /*unused*/) { + return ReactNativeFeatureFlags::enableEventEmitterRetentionDuringGesturesOnAndroid(); +} + bool JReactNativeFeatureFlagsCxxInterop::enableFabricLogs( facebook::jni::alias_ref /*unused*/) { return ReactNativeFeatureFlags::enableFabricLogs(); @@ -563,6 +574,9 @@ void JReactNativeFeatureFlagsCxxInterop::registerNatives() { makeNativeMethod( "enableEagerRootViewAttachment", JReactNativeFeatureFlagsCxxInterop::enableEagerRootViewAttachment), + makeNativeMethod( + "enableEventEmitterRetentionDuringGesturesOnAndroid", + JReactNativeFeatureFlagsCxxInterop::enableEventEmitterRetentionDuringGesturesOnAndroid), makeNativeMethod( "enableFabricLogs", JReactNativeFeatureFlagsCxxInterop::enableFabricLogs), diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/featureflags/JReactNativeFeatureFlagsCxxInterop.h b/packages/react-native/ReactAndroid/src/main/jni/react/featureflags/JReactNativeFeatureFlagsCxxInterop.h index bb7d763462db..b7274bcde5c3 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/featureflags/JReactNativeFeatureFlagsCxxInterop.h +++ b/packages/react-native/ReactAndroid/src/main/jni/react/featureflags/JReactNativeFeatureFlagsCxxInterop.h @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<<5399269d162bd4823a7ec36198c0604f>> + * @generated SignedSource<> */ /** @@ -60,6 +60,9 @@ class JReactNativeFeatureFlagsCxxInterop static bool enableEagerRootViewAttachment( facebook::jni::alias_ref); + static bool enableEventEmitterRetentionDuringGesturesOnAndroid( + facebook::jni::alias_ref); + static bool enableFabricLogs( facebook::jni::alias_ref); diff --git a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlags.cpp b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlags.cpp index f49e406f182a..549658d6f844 100644 --- a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlags.cpp +++ b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlags.cpp @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<> + * @generated SignedSource<> */ /** @@ -61,6 +61,10 @@ bool ReactNativeFeatureFlags::enableEagerRootViewAttachment() { return getAccessor().enableEagerRootViewAttachment(); } +bool ReactNativeFeatureFlags::enableEventEmitterRetentionDuringGesturesOnAndroid() { + return getAccessor().enableEventEmitterRetentionDuringGesturesOnAndroid(); +} + bool ReactNativeFeatureFlags::enableFabricLogs() { return getAccessor().enableFabricLogs(); } diff --git a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlags.h b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlags.h index d8473b36178e..656fe5736b5d 100644 --- a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlags.h +++ b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlags.h @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<<93b1717fb2e45f00fb068a4ffa248afe>> + * @generated SignedSource<<45ae072fb6a0b1ec404b3dc8adc13186>> */ /** @@ -87,6 +87,11 @@ class ReactNativeFeatureFlags { */ RN_EXPORT static bool enableEagerRootViewAttachment(); + /** + * Enables the retention of EventEmitterWrapper on Android till the touch gesture is over to fix a bug on pressable (#44610) + */ + RN_EXPORT static bool enableEventEmitterRetentionDuringGesturesOnAndroid(); + /** * This feature flag enables logs for Fabric. */ diff --git a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.cpp b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.cpp index 0c13880ebf5e..b4f8cf56b2b9 100644 --- a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.cpp +++ b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.cpp @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<> + * @generated SignedSource<<9e7498efd93e3c23b74219b7b30ec851>> */ /** @@ -209,6 +209,24 @@ bool ReactNativeFeatureFlagsAccessor::enableEagerRootViewAttachment() { return flagValue.value(); } +bool ReactNativeFeatureFlagsAccessor::enableEventEmitterRetentionDuringGesturesOnAndroid() { + auto flagValue = enableEventEmitterRetentionDuringGesturesOnAndroid_.load(); + + if (!flagValue.has_value()) { + // This block is not exclusive but it is not necessary. + // If multiple threads try to initialize the feature flag, we would only + // be accessing the provider multiple times but the end state of this + // instance and the returned flag value would be the same. + + markFlagAsAccessed(10, "enableEventEmitterRetentionDuringGesturesOnAndroid"); + + flagValue = currentProvider_->enableEventEmitterRetentionDuringGesturesOnAndroid(); + enableEventEmitterRetentionDuringGesturesOnAndroid_ = flagValue; + } + + return flagValue.value(); +} + bool ReactNativeFeatureFlagsAccessor::enableFabricLogs() { auto flagValue = enableFabricLogs_.load(); @@ -218,7 +236,7 @@ bool ReactNativeFeatureFlagsAccessor::enableFabricLogs() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(10, "enableFabricLogs"); + markFlagAsAccessed(11, "enableFabricLogs"); flagValue = currentProvider_->enableFabricLogs(); enableFabricLogs_ = flagValue; @@ -236,7 +254,7 @@ bool ReactNativeFeatureFlagsAccessor::enableFabricRendererExclusively() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(11, "enableFabricRendererExclusively"); + markFlagAsAccessed(12, "enableFabricRendererExclusively"); flagValue = currentProvider_->enableFabricRendererExclusively(); enableFabricRendererExclusively_ = flagValue; @@ -254,7 +272,7 @@ bool ReactNativeFeatureFlagsAccessor::enableGranularShadowTreeStateReconciliatio // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(12, "enableGranularShadowTreeStateReconciliation"); + markFlagAsAccessed(13, "enableGranularShadowTreeStateReconciliation"); flagValue = currentProvider_->enableGranularShadowTreeStateReconciliation(); enableGranularShadowTreeStateReconciliation_ = flagValue; @@ -272,7 +290,7 @@ bool ReactNativeFeatureFlagsAccessor::enableLongTaskAPI() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(13, "enableLongTaskAPI"); + markFlagAsAccessed(14, "enableLongTaskAPI"); flagValue = currentProvider_->enableLongTaskAPI(); enableLongTaskAPI_ = flagValue; @@ -290,7 +308,7 @@ bool ReactNativeFeatureFlagsAccessor::enableMicrotasks() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(14, "enableMicrotasks"); + markFlagAsAccessed(15, "enableMicrotasks"); flagValue = currentProvider_->enableMicrotasks(); enableMicrotasks_ = flagValue; @@ -308,7 +326,7 @@ bool ReactNativeFeatureFlagsAccessor::enablePropsUpdateReconciliationAndroid() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(15, "enablePropsUpdateReconciliationAndroid"); + markFlagAsAccessed(16, "enablePropsUpdateReconciliationAndroid"); flagValue = currentProvider_->enablePropsUpdateReconciliationAndroid(); enablePropsUpdateReconciliationAndroid_ = flagValue; @@ -326,7 +344,7 @@ bool ReactNativeFeatureFlagsAccessor::enableReportEventPaintTime() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(16, "enableReportEventPaintTime"); + markFlagAsAccessed(17, "enableReportEventPaintTime"); flagValue = currentProvider_->enableReportEventPaintTime(); enableReportEventPaintTime_ = flagValue; @@ -344,7 +362,7 @@ bool ReactNativeFeatureFlagsAccessor::enableSynchronousStateUpdates() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(17, "enableSynchronousStateUpdates"); + markFlagAsAccessed(18, "enableSynchronousStateUpdates"); flagValue = currentProvider_->enableSynchronousStateUpdates(); enableSynchronousStateUpdates_ = flagValue; @@ -362,7 +380,7 @@ bool ReactNativeFeatureFlagsAccessor::enableUIConsistency() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(18, "enableUIConsistency"); + markFlagAsAccessed(19, "enableUIConsistency"); flagValue = currentProvider_->enableUIConsistency(); enableUIConsistency_ = flagValue; @@ -380,7 +398,7 @@ bool ReactNativeFeatureFlagsAccessor::enableViewRecycling() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(19, "enableViewRecycling"); + markFlagAsAccessed(20, "enableViewRecycling"); flagValue = currentProvider_->enableViewRecycling(); enableViewRecycling_ = flagValue; @@ -398,7 +416,7 @@ bool ReactNativeFeatureFlagsAccessor::excludeYogaFromRawProps() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(20, "excludeYogaFromRawProps"); + markFlagAsAccessed(21, "excludeYogaFromRawProps"); flagValue = currentProvider_->excludeYogaFromRawProps(); excludeYogaFromRawProps_ = flagValue; @@ -416,7 +434,7 @@ bool ReactNativeFeatureFlagsAccessor::fetchImagesInViewPreallocation() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(21, "fetchImagesInViewPreallocation"); + markFlagAsAccessed(22, "fetchImagesInViewPreallocation"); flagValue = currentProvider_->fetchImagesInViewPreallocation(); fetchImagesInViewPreallocation_ = flagValue; @@ -434,7 +452,7 @@ bool ReactNativeFeatureFlagsAccessor::fixIncorrectScrollViewStateUpdateOnAndroid // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(22, "fixIncorrectScrollViewStateUpdateOnAndroid"); + markFlagAsAccessed(23, "fixIncorrectScrollViewStateUpdateOnAndroid"); flagValue = currentProvider_->fixIncorrectScrollViewStateUpdateOnAndroid(); fixIncorrectScrollViewStateUpdateOnAndroid_ = flagValue; @@ -452,7 +470,7 @@ bool ReactNativeFeatureFlagsAccessor::fixMappingOfEventPrioritiesBetweenFabricAn // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(23, "fixMappingOfEventPrioritiesBetweenFabricAndReact"); + markFlagAsAccessed(24, "fixMappingOfEventPrioritiesBetweenFabricAndReact"); flagValue = currentProvider_->fixMappingOfEventPrioritiesBetweenFabricAndReact(); fixMappingOfEventPrioritiesBetweenFabricAndReact_ = flagValue; @@ -470,7 +488,7 @@ bool ReactNativeFeatureFlagsAccessor::fixMissedFabricStateUpdatesOnAndroid() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(24, "fixMissedFabricStateUpdatesOnAndroid"); + markFlagAsAccessed(25, "fixMissedFabricStateUpdatesOnAndroid"); flagValue = currentProvider_->fixMissedFabricStateUpdatesOnAndroid(); fixMissedFabricStateUpdatesOnAndroid_ = flagValue; @@ -488,7 +506,7 @@ bool ReactNativeFeatureFlagsAccessor::forceBatchingMountItemsOnAndroid() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(25, "forceBatchingMountItemsOnAndroid"); + markFlagAsAccessed(26, "forceBatchingMountItemsOnAndroid"); flagValue = currentProvider_->forceBatchingMountItemsOnAndroid(); forceBatchingMountItemsOnAndroid_ = flagValue; @@ -506,7 +524,7 @@ bool ReactNativeFeatureFlagsAccessor::fuseboxEnabledDebug() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(26, "fuseboxEnabledDebug"); + markFlagAsAccessed(27, "fuseboxEnabledDebug"); flagValue = currentProvider_->fuseboxEnabledDebug(); fuseboxEnabledDebug_ = flagValue; @@ -524,7 +542,7 @@ bool ReactNativeFeatureFlagsAccessor::fuseboxEnabledRelease() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(27, "fuseboxEnabledRelease"); + markFlagAsAccessed(28, "fuseboxEnabledRelease"); flagValue = currentProvider_->fuseboxEnabledRelease(); fuseboxEnabledRelease_ = flagValue; @@ -542,7 +560,7 @@ bool ReactNativeFeatureFlagsAccessor::initEagerTurboModulesOnNativeModulesQueueA // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(28, "initEagerTurboModulesOnNativeModulesQueueAndroid"); + markFlagAsAccessed(29, "initEagerTurboModulesOnNativeModulesQueueAndroid"); flagValue = currentProvider_->initEagerTurboModulesOnNativeModulesQueueAndroid(); initEagerTurboModulesOnNativeModulesQueueAndroid_ = flagValue; @@ -560,7 +578,7 @@ bool ReactNativeFeatureFlagsAccessor::lazyAnimationCallbacks() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(29, "lazyAnimationCallbacks"); + markFlagAsAccessed(30, "lazyAnimationCallbacks"); flagValue = currentProvider_->lazyAnimationCallbacks(); lazyAnimationCallbacks_ = flagValue; @@ -578,7 +596,7 @@ bool ReactNativeFeatureFlagsAccessor::loadVectorDrawablesOnImages() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(30, "loadVectorDrawablesOnImages"); + markFlagAsAccessed(31, "loadVectorDrawablesOnImages"); flagValue = currentProvider_->loadVectorDrawablesOnImages(); loadVectorDrawablesOnImages_ = flagValue; @@ -596,7 +614,7 @@ bool ReactNativeFeatureFlagsAccessor::setAndroidLayoutDirection() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(31, "setAndroidLayoutDirection"); + markFlagAsAccessed(32, "setAndroidLayoutDirection"); flagValue = currentProvider_->setAndroidLayoutDirection(); setAndroidLayoutDirection_ = flagValue; @@ -614,7 +632,7 @@ bool ReactNativeFeatureFlagsAccessor::traceTurboModulePromiseRejectionsOnAndroid // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(32, "traceTurboModulePromiseRejectionsOnAndroid"); + markFlagAsAccessed(33, "traceTurboModulePromiseRejectionsOnAndroid"); flagValue = currentProvider_->traceTurboModulePromiseRejectionsOnAndroid(); traceTurboModulePromiseRejectionsOnAndroid_ = flagValue; @@ -632,7 +650,7 @@ bool ReactNativeFeatureFlagsAccessor::useFabricInterop() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(33, "useFabricInterop"); + markFlagAsAccessed(34, "useFabricInterop"); flagValue = currentProvider_->useFabricInterop(); useFabricInterop_ = flagValue; @@ -650,7 +668,7 @@ bool ReactNativeFeatureFlagsAccessor::useImmediateExecutorInAndroidBridgeless() // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(34, "useImmediateExecutorInAndroidBridgeless"); + markFlagAsAccessed(35, "useImmediateExecutorInAndroidBridgeless"); flagValue = currentProvider_->useImmediateExecutorInAndroidBridgeless(); useImmediateExecutorInAndroidBridgeless_ = flagValue; @@ -668,7 +686,7 @@ bool ReactNativeFeatureFlagsAccessor::useModernRuntimeScheduler() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(35, "useModernRuntimeScheduler"); + markFlagAsAccessed(36, "useModernRuntimeScheduler"); flagValue = currentProvider_->useModernRuntimeScheduler(); useModernRuntimeScheduler_ = flagValue; @@ -686,7 +704,7 @@ bool ReactNativeFeatureFlagsAccessor::useNativeViewConfigsInBridgelessMode() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(36, "useNativeViewConfigsInBridgelessMode"); + markFlagAsAccessed(37, "useNativeViewConfigsInBridgelessMode"); flagValue = currentProvider_->useNativeViewConfigsInBridgelessMode(); useNativeViewConfigsInBridgelessMode_ = flagValue; @@ -704,7 +722,7 @@ bool ReactNativeFeatureFlagsAccessor::useNewReactImageViewBackgroundDrawing() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(37, "useNewReactImageViewBackgroundDrawing"); + markFlagAsAccessed(38, "useNewReactImageViewBackgroundDrawing"); flagValue = currentProvider_->useNewReactImageViewBackgroundDrawing(); useNewReactImageViewBackgroundDrawing_ = flagValue; @@ -722,7 +740,7 @@ bool ReactNativeFeatureFlagsAccessor::useOptimisedViewPreallocationOnAndroid() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(38, "useOptimisedViewPreallocationOnAndroid"); + markFlagAsAccessed(39, "useOptimisedViewPreallocationOnAndroid"); flagValue = currentProvider_->useOptimisedViewPreallocationOnAndroid(); useOptimisedViewPreallocationOnAndroid_ = flagValue; @@ -740,7 +758,7 @@ bool ReactNativeFeatureFlagsAccessor::useRuntimeShadowNodeReferenceUpdate() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(39, "useRuntimeShadowNodeReferenceUpdate"); + markFlagAsAccessed(40, "useRuntimeShadowNodeReferenceUpdate"); flagValue = currentProvider_->useRuntimeShadowNodeReferenceUpdate(); useRuntimeShadowNodeReferenceUpdate_ = flagValue; @@ -758,7 +776,7 @@ bool ReactNativeFeatureFlagsAccessor::useRuntimeShadowNodeReferenceUpdateOnLayou // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(40, "useRuntimeShadowNodeReferenceUpdateOnLayout"); + markFlagAsAccessed(41, "useRuntimeShadowNodeReferenceUpdateOnLayout"); flagValue = currentProvider_->useRuntimeShadowNodeReferenceUpdateOnLayout(); useRuntimeShadowNodeReferenceUpdateOnLayout_ = flagValue; @@ -776,7 +794,7 @@ bool ReactNativeFeatureFlagsAccessor::useStateAlignmentMechanism() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(41, "useStateAlignmentMechanism"); + markFlagAsAccessed(42, "useStateAlignmentMechanism"); flagValue = currentProvider_->useStateAlignmentMechanism(); useStateAlignmentMechanism_ = flagValue; @@ -794,7 +812,7 @@ bool ReactNativeFeatureFlagsAccessor::useTurboModuleInterop() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(42, "useTurboModuleInterop"); + markFlagAsAccessed(43, "useTurboModuleInterop"); flagValue = currentProvider_->useTurboModuleInterop(); useTurboModuleInterop_ = flagValue; diff --git a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.h b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.h index 99c85da10448..7471b7d91fe0 100644 --- a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.h +++ b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.h @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<<42259cb82f9ac5b3c0918339b45e6a2a>> + * @generated SignedSource<> */ /** @@ -41,6 +41,7 @@ class ReactNativeFeatureFlagsAccessor { bool enableBackgroundStyleApplicator(); bool enableCleanTextInputYogaNode(); bool enableEagerRootViewAttachment(); + bool enableEventEmitterRetentionDuringGesturesOnAndroid(); bool enableFabricLogs(); bool enableFabricRendererExclusively(); bool enableGranularShadowTreeStateReconciliation(); @@ -84,7 +85,7 @@ class ReactNativeFeatureFlagsAccessor { std::unique_ptr currentProvider_; bool wasOverridden_; - std::array, 43> accessedFeatureFlags_; + std::array, 44> accessedFeatureFlags_; std::atomic> commonTestFlag_; std::atomic> allowRecursiveCommitsWithSynchronousMountOnAndroid_; @@ -96,6 +97,7 @@ class ReactNativeFeatureFlagsAccessor { std::atomic> enableBackgroundStyleApplicator_; std::atomic> enableCleanTextInputYogaNode_; std::atomic> enableEagerRootViewAttachment_; + std::atomic> enableEventEmitterRetentionDuringGesturesOnAndroid_; std::atomic> enableFabricLogs_; std::atomic> enableFabricRendererExclusively_; std::atomic> enableGranularShadowTreeStateReconciliation_; diff --git a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDefaults.h b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDefaults.h index e557ea0baff7..34dc9784a07f 100644 --- a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDefaults.h +++ b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDefaults.h @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<<6624485d7a7712c8243e4a00621fa10d>> + * @generated SignedSource<<5984a783c431c11b00c2dd8321432235>> */ /** @@ -67,6 +67,10 @@ class ReactNativeFeatureFlagsDefaults : public ReactNativeFeatureFlagsProvider { return false; } + bool enableEventEmitterRetentionDuringGesturesOnAndroid() override { + return false; + } + bool enableFabricLogs() override { return false; } diff --git a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsProvider.h b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsProvider.h index d5d57251de0a..1e7392fdba31 100644 --- a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsProvider.h +++ b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsProvider.h @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<<28c8387a6ed837bcfbe75da8dae74e63>> + * @generated SignedSource<<362ab4dfd19d6f3189b3c3e5aafd009a>> */ /** @@ -35,6 +35,7 @@ class ReactNativeFeatureFlagsProvider { virtual bool enableBackgroundStyleApplicator() = 0; virtual bool enableCleanTextInputYogaNode() = 0; virtual bool enableEagerRootViewAttachment() = 0; + virtual bool enableEventEmitterRetentionDuringGesturesOnAndroid() = 0; virtual bool enableFabricLogs() = 0; virtual bool enableFabricRendererExclusively() = 0; virtual bool enableGranularShadowTreeStateReconciliation() = 0; diff --git a/packages/react-native/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.cpp b/packages/react-native/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.cpp index 54e14c2cef0a..56b406deca47 100644 --- a/packages/react-native/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.cpp +++ b/packages/react-native/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.cpp @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<> + * @generated SignedSource<> */ /** @@ -87,6 +87,11 @@ bool NativeReactNativeFeatureFlags::enableEagerRootViewAttachment( return ReactNativeFeatureFlags::enableEagerRootViewAttachment(); } +bool NativeReactNativeFeatureFlags::enableEventEmitterRetentionDuringGesturesOnAndroid( + jsi::Runtime& /*runtime*/) { + return ReactNativeFeatureFlags::enableEventEmitterRetentionDuringGesturesOnAndroid(); +} + bool NativeReactNativeFeatureFlags::enableFabricLogs( jsi::Runtime& /*runtime*/) { return ReactNativeFeatureFlags::enableFabricLogs(); diff --git a/packages/react-native/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.h b/packages/react-native/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.h index fc97c4b479a4..4bc9ec789057 100644 --- a/packages/react-native/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.h +++ b/packages/react-native/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.h @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<> + * @generated SignedSource<<6b0ad22b5e8302c1d4b0dae4d1f2eb19>> */ /** @@ -55,6 +55,8 @@ class NativeReactNativeFeatureFlags bool enableEagerRootViewAttachment(jsi::Runtime& runtime); + bool enableEventEmitterRetentionDuringGesturesOnAndroid(jsi::Runtime& runtime); + bool enableFabricLogs(jsi::Runtime& runtime); bool enableFabricRendererExclusively(jsi::Runtime& runtime); diff --git a/packages/react-native/scripts/featureflags/ReactNativeFeatureFlags.config.js b/packages/react-native/scripts/featureflags/ReactNativeFeatureFlags.config.js index 7dfe3df73739..a85eb9e1dacd 100644 --- a/packages/react-native/scripts/featureflags/ReactNativeFeatureFlags.config.js +++ b/packages/react-native/scripts/featureflags/ReactNativeFeatureFlags.config.js @@ -83,6 +83,11 @@ const definitions: FeatureFlagDefinitions = { description: 'Feature flag to configure eager attachment of the root view/initialisation of the JS code.', }, + enableEventEmitterRetentionDuringGesturesOnAndroid: { + defaultValue: false, + description: + 'Enables the retention of EventEmitterWrapper on Android till the touch gesture is over to fix a bug on pressable (#44610)', + }, enableFabricLogs: { defaultValue: false, description: 'This feature flag enables logs for Fabric.', diff --git a/packages/react-native/src/private/featureflags/ReactNativeFeatureFlags.js b/packages/react-native/src/private/featureflags/ReactNativeFeatureFlags.js index e0947d444e39..37ac42ca7202 100644 --- a/packages/react-native/src/private/featureflags/ReactNativeFeatureFlags.js +++ b/packages/react-native/src/private/featureflags/ReactNativeFeatureFlags.js @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<<6896ec018143f40b7d08487fb10239d7>> + * @generated SignedSource<<453a0231b2d396d59727425f008c65b8>> * @flow strict-local */ @@ -54,6 +54,7 @@ export type ReactNativeFeatureFlags = { enableBackgroundStyleApplicator: Getter, enableCleanTextInputYogaNode: Getter, enableEagerRootViewAttachment: Getter, + enableEventEmitterRetentionDuringGesturesOnAndroid: Getter, enableFabricLogs: Getter, enableFabricRendererExclusively: Getter, enableGranularShadowTreeStateReconciliation: Getter, @@ -189,6 +190,10 @@ export const enableCleanTextInputYogaNode: Getter = createNativeFlagGet * Feature flag to configure eager attachment of the root view/initialisation of the JS code. */ export const enableEagerRootViewAttachment: Getter = createNativeFlagGetter('enableEagerRootViewAttachment', false); +/** + * Enables the retention of EventEmitterWrapper on Android till the touch gesture is over to fix a bug on pressable (#44610) + */ +export const enableEventEmitterRetentionDuringGesturesOnAndroid: Getter = createNativeFlagGetter('enableEventEmitterRetentionDuringGesturesOnAndroid', false); /** * This feature flag enables logs for Fabric. */ diff --git a/packages/react-native/src/private/featureflags/specs/NativeReactNativeFeatureFlags.js b/packages/react-native/src/private/featureflags/specs/NativeReactNativeFeatureFlags.js index dfc17488309e..97b556181a94 100644 --- a/packages/react-native/src/private/featureflags/specs/NativeReactNativeFeatureFlags.js +++ b/packages/react-native/src/private/featureflags/specs/NativeReactNativeFeatureFlags.js @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<<8e7f7c0b5eccf4db77ab4b65a4aae313>> + * @generated SignedSource<> * @flow strict-local */ @@ -33,6 +33,7 @@ export interface Spec extends TurboModule { +enableBackgroundStyleApplicator?: () => boolean; +enableCleanTextInputYogaNode?: () => boolean; +enableEagerRootViewAttachment?: () => boolean; + +enableEventEmitterRetentionDuringGesturesOnAndroid?: () => boolean; +enableFabricLogs?: () => boolean; +enableFabricRendererExclusively?: () => boolean; +enableGranularShadowTreeStateReconciliation?: () => boolean;