From fa0c9002d6b7e898a1d7804cede59425f29492f1 Mon Sep 17 00:00:00 2001 From: Genki Kondo Date: Fri, 31 Mar 2023 12:01:24 -0700 Subject: [PATCH] Calculate entered/exited views during handling of all MotionEvents (#36666) Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/36666 Modify JSPointerDispatcher to dispatch out/over/leave/enter events on handing of any MotionEvent. This functionality is in parity with [how touch events are handled in iOS](https://www.internalfb.com/code/fbsource/[cdfd2520a4d43b3a46104ecbf437bb792460e3f7]/xplat/js/react-native-github/packages/react-native/React/Fabric/RCTSurfacePointerHandler.mm?lines=780). handleMotionEvent updates the last hit path upon any MotionEvent, so we want to make sure that we handle any out/over/leave/enter dispatches in this method. This diff just extracts the dispatching of out/over/leave/enter from onMove() to handleMotionEvent(). Changelog: [Internal] - Calculate entered/exited views on all touch/move events Reviewed By: javache, mdvacca Differential Revision: D44426524 fbshipit-source-id: 5225c54c2c995440ac766c6fbc99c08f05c70a92 --- .../react/uimanager/JSPointerDispatcher.java | 27 ++++++++++++------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/JSPointerDispatcher.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/JSPointerDispatcher.java index 0dd991f1aaf392..c2125fa3eed78a 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/JSPointerDispatcher.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/JSPointerDispatcher.java @@ -158,10 +158,6 @@ private void onDown( motionEvent, enterViewTargets, eventDispatcher); - } else { - // There are cases when the pointer may have moved in the same frame as the down event. - // Dispatch the move event before the down event. - onMove(activeTargetTag, eventState, motionEvent, eventDispatcher); } boolean listeningForDown = @@ -255,6 +251,8 @@ public void handleMotionEvent( activeTargetTag = activeHitPath.get(0).getViewId(); } + handleHitStateDivergence(activeTargetTag, eventState, motionEvent, eventDispatcher); + // Dispatch pointer events from the MotionEvents. When we want to ignore an event, we need to // exit early so we don't record anything about this MotionEvent. switch (action) { @@ -362,7 +360,7 @@ private static List filterByShouldDispatch( return dispatchableViewTargets; } - private void dispatchEventForViewTargets( + private static void dispatchEventForViewTargets( String eventName, PointerEventState eventState, MotionEvent motionEvent, @@ -375,20 +373,20 @@ private void dispatchEventForViewTargets( } } - private boolean qualifiedMove(float[] eventCoordinates, float[] lastEventCoordinates) { + private static boolean qualifiedMove(float[] eventCoordinates, float[] lastEventCoordinates) { return (Math.abs(lastEventCoordinates[0] - eventCoordinates[0]) > ONMOVE_EPSILON || Math.abs(lastEventCoordinates[1] - eventCoordinates[1]) > ONMOVE_EPSILON); } - private void onMove( + // Determines which views are being entered and exited based on comparison between the previous + // hit path and the current hit path, and dispatches out/over/leave/enter events. + private void handleHitStateDivergence( int targetTag, PointerEventState eventState, MotionEvent motionEvent, EventDispatcher eventDispatcher) { - int activePointerId = eventState.getActivePointerId(); List activeHitPath = eventState.getHitPathByPointerId().get(activePointerId); - List lastHitPath = mLastHitPathByPointerId != null && mLastHitPathByPointerId.containsKey(activePointerId) ? mLastHitPathByPointerId.get(activePointerId) @@ -483,6 +481,15 @@ private void onMove( eventDispatcher); } } + } + + private void onMove( + int targetTag, + PointerEventState eventState, + MotionEvent motionEvent, + EventDispatcher eventDispatcher) { + int activePointerId = eventState.getActivePointerId(); + List activeHitPath = eventState.getHitPathByPointerId().get(activePointerId); boolean listeningToMove = isAnyoneListeningForBubblingEvent(activeHitPath, EVENT.MOVE, EVENT.MOVE_CAPTURE); @@ -551,7 +558,7 @@ private void dispatchCancelEvent( } } - private void debugPrintHitPath(List hitPath) { + private static void debugPrintHitPath(List hitPath) { StringBuilder builder = new StringBuilder("hitPath: "); for (ViewTarget viewTarget : hitPath) { builder.append(String.format("%d, ", viewTarget.getViewId()));