2222import com .facebook .react .uimanager .events .TouchEventCoalescingKeyHelper ;
2323import java .util .ArrayList ;
2424import java .util .Collections ;
25+ import java .util .HashMap ;
2526import java .util .List ;
27+ import java .util .Map ;
2628
2729/**
2830 * JSPointerDispatcher handles dispatching pointer events to JS from RootViews. If you implement
@@ -37,9 +39,8 @@ public class JSPointerDispatcher {
3739
3840 private final TouchEventCoalescingKeyHelper mTouchEventCoalescingKeyHelper =
3941 new TouchEventCoalescingKeyHelper ();
40- private List <ViewTarget > mLastHitPath = Collections .emptyList ();
41- private final float [] mLastEventCoordinates = new float [2 ];
42- private final float [] mTargetCoordinates = new float [2 ];
42+ private final Map <Integer , List <ViewTarget >> mLastHitPathByPointerId = new HashMap <>();
43+ private final Map <Integer , float []> mLastEventCoodinatesByPointerId = new HashMap <>();
4344
4445 private int mChildHandlingNativeGesture = -1 ;
4546 private int mPrimaryPointerId = UNSET_POINTER_ID ;
@@ -62,10 +63,11 @@ public void onChildStartedNativeGesture(
6263 return ;
6364 }
6465
66+ float [] targetCoordinates = new float [2 ];
6567 List <ViewTarget > hitPath =
6668 TouchTargetHelper .findTargetPathAndCoordinatesForTouch (
67- motionEvent .getX (), motionEvent .getY (), mRootViewGroup , mTargetCoordinates );
68- dispatchCancelEvent (hitPath , motionEvent , eventDispatcher );
69+ motionEvent .getX (), motionEvent .getY (), mRootViewGroup , targetCoordinates );
70+ dispatchCancelEvent (hitPath , motionEvent , eventDispatcher , targetCoordinates );
6971 mChildHandlingNativeGesture = childView .getId ();
7072 }
7173
@@ -79,7 +81,8 @@ private void onUp(
7981 List <ViewTarget > hitPath ,
8082 int surfaceId ,
8183 MotionEvent motionEvent ,
82- EventDispatcher eventDispatcher ) {
84+ EventDispatcher eventDispatcher ,
85+ float [] targetCoordinates ) {
8386 if (motionEvent .getActionMasked () == MotionEvent .ACTION_UP ) {
8487 // End of a "down" coalescing key
8588 mTouchEventCoalescingKeyHelper .removeCoalescingKey (mDownStartTime );
@@ -97,7 +100,7 @@ private void onUp(
97100 surfaceId ,
98101 activeTargetTag ,
99102 motionEvent ,
100- mTargetCoordinates ,
103+ targetCoordinates ,
101104 mPrimaryPointerId ));
102105 }
103106
@@ -111,7 +114,7 @@ private void onUp(
111114 surfaceId ,
112115 activeTargetTag ,
113116 motionEvent ,
114- mTargetCoordinates ,
117+ targetCoordinates ,
115118 mPrimaryPointerId ));
116119 }
117120
@@ -124,21 +127,26 @@ private void onUp(
124127 leaveViewTargets ,
125128 eventDispatcher ,
126129 surfaceId ,
127- motionEvent );
130+ motionEvent ,
131+ targetCoordinates );
132+
133+ int activePointerId = motionEvent .getPointerId (motionEvent .getActionIndex ());
134+ mLastHitPathByPointerId .remove (activePointerId );
135+ mLastEventCoodinatesByPointerId .remove (activePointerId );
128136 }
129137
130138 if (motionEvent .getActionMasked () == MotionEvent .ACTION_UP ) {
131139 mPrimaryPointerId = UNSET_POINTER_ID ;
132140 }
133- return ;
134141 }
135142
136143 private void onDown (
137144 int activeTargetTag ,
138145 List <ViewTarget > hitPath ,
139146 int surfaceId ,
140147 MotionEvent motionEvent ,
141- EventDispatcher eventDispatcher ) {
148+ EventDispatcher eventDispatcher ,
149+ float [] targetCoordinates ) {
142150
143151 if (motionEvent .getActionMasked () == MotionEvent .ACTION_DOWN ) {
144152 mPrimaryPointerId = motionEvent .getPointerId (0 );
@@ -160,7 +168,7 @@ private void onDown(
160168 surfaceId ,
161169 activeTargetTag ,
162170 motionEvent ,
163- mTargetCoordinates ,
171+ targetCoordinates ,
164172 mPrimaryPointerId ));
165173 }
166174
@@ -174,7 +182,8 @@ private void onDown(
174182 enterViewTargets ,
175183 eventDispatcher ,
176184 surfaceId ,
177- motionEvent );
185+ motionEvent ,
186+ targetCoordinates );
178187 }
179188
180189 boolean listeningForDown =
@@ -186,7 +195,7 @@ private void onDown(
186195 surfaceId ,
187196 activeTargetTag ,
188197 motionEvent ,
189- mTargetCoordinates ,
198+ targetCoordinates ,
190199 mPrimaryPointerId ));
191200 }
192201 }
@@ -199,18 +208,18 @@ public void handleMotionEvent(MotionEvent motionEvent, EventDispatcher eventDisp
199208 return ;
200209 }
201210
202- boolean supportsHover = PointerEventHelper .supportsHover (motionEvent );
203211 int surfaceId = UIManagerHelper .getSurfaceId (mRootViewGroup );
204212
205213 // Only relevant for POINTER_UP/POINTER_DOWN actions, otherwise 0
206214 int actionIndex = motionEvent .getActionIndex ();
207215
216+ float [] targetCoordinates = new float [2 ];
208217 List <ViewTarget > hitPath =
209218 TouchTargetHelper .findTargetPathAndCoordinatesForTouch (
210219 motionEvent .getX (actionIndex ),
211220 motionEvent .getY (actionIndex ),
212221 mRootViewGroup ,
213- mTargetCoordinates );
222+ targetCoordinates );
214223
215224 if (hitPath .isEmpty ()) {
216225 return ;
@@ -220,7 +229,7 @@ public void handleMotionEvent(MotionEvent motionEvent, EventDispatcher eventDisp
220229 int activeTargetTag = activeViewTarget .getViewId ();
221230
222231 if (action == MotionEvent .ACTION_HOVER_MOVE ) {
223- onMove (motionEvent , eventDispatcher , surfaceId , hitPath );
232+ onMove (motionEvent , eventDispatcher , surfaceId , hitPath , targetCoordinates );
224233 return ;
225234 }
226235
@@ -234,7 +243,8 @@ public void handleMotionEvent(MotionEvent motionEvent, EventDispatcher eventDisp
234243 switch (action ) {
235244 case MotionEvent .ACTION_DOWN :
236245 case MotionEvent .ACTION_POINTER_DOWN :
237- onDown (activeTargetTag , hitPath , surfaceId , motionEvent , eventDispatcher );
246+ onDown (
247+ activeTargetTag , hitPath , surfaceId , motionEvent , eventDispatcher , targetCoordinates );
238248 break ;
239249 case MotionEvent .ACTION_MOVE :
240250 // TODO(luwe) - converge this with ACTION_HOVER_MOVE
@@ -249,27 +259,22 @@ public void handleMotionEvent(MotionEvent motionEvent, EventDispatcher eventDisp
249259 surfaceId ,
250260 activeTargetTag ,
251261 motionEvent ,
252- mTargetCoordinates ,
262+ targetCoordinates ,
253263 coalescingKey ,
254264 mPrimaryPointerId ));
255265 }
256266 break ;
257267 case MotionEvent .ACTION_UP :
258268 case MotionEvent .ACTION_POINTER_UP :
259- onUp (activeTargetTag , hitPath , surfaceId , motionEvent , eventDispatcher );
269+ onUp (activeTargetTag , hitPath , surfaceId , motionEvent , eventDispatcher , targetCoordinates );
260270 break ;
261271 case MotionEvent .ACTION_CANCEL :
262- dispatchCancelEvent (hitPath , motionEvent , eventDispatcher );
272+ dispatchCancelEvent (hitPath , motionEvent , eventDispatcher , targetCoordinates );
263273 break ;
264274 default :
265275 FLog .w (
266276 ReactConstants .TAG ,
267- "Warning : Motion Event was ignored. Action="
268- + action
269- + " Target="
270- + activeTargetTag
271- + " Supports Hover="
272- + supportsHover );
277+ "Warning : Motion Event was ignored. Action=" + action + " Target=" + activeTargetTag );
273278 return ;
274279 }
275280 }
@@ -325,13 +330,14 @@ private void dispatchEventForViewTargets(
325330 List <ViewTarget > viewTargets ,
326331 EventDispatcher dispatcher ,
327332 int surfaceId ,
328- MotionEvent motionEvent ) {
333+ MotionEvent motionEvent ,
334+ float [] targetCoordinates ) {
329335
330336 for (ViewTarget viewTarget : viewTargets ) {
331337 int viewId = viewTarget .getViewId ();
332338 dispatcher .dispatchEvent (
333339 PointerEvent .obtain (
334- eventName , surfaceId , viewId , motionEvent , mTargetCoordinates , mPrimaryPointerId ));
340+ eventName , surfaceId , viewId , motionEvent , targetCoordinates , mPrimaryPointerId ));
335341 }
336342 }
337343
@@ -340,19 +346,31 @@ private void onMove(
340346 MotionEvent motionEvent ,
341347 EventDispatcher eventDispatcher ,
342348 int surfaceId ,
343- List <ViewTarget > hitPath ) {
349+ List <ViewTarget > hitPath ,
350+ float [] targetCoordinates ) {
344351
345352 int action = motionEvent .getActionMasked ();
346353 if (action != MotionEvent .ACTION_HOVER_MOVE ) {
347354 return ;
348355 }
349356
357+ int actionIndex = motionEvent .getActionIndex ();
358+ int activePointerId = motionEvent .getPointerId (actionIndex );
350359 float x = motionEvent .getX ();
351360 float y = motionEvent .getY ();
361+ List <ViewTarget > lastHitPath =
362+ mLastHitPathByPointerId .containsKey (activePointerId )
363+ ? mLastHitPathByPointerId .get (activePointerId )
364+ : Collections .emptyList ();
365+
366+ float [] lastEventCoordinates =
367+ mLastEventCoodinatesByPointerId .containsKey (activePointerId )
368+ ? mLastEventCoodinatesByPointerId .get (activePointerId )
369+ : new float [] {0 , 0 };
352370
353371 boolean qualifiedMove =
354- (Math .abs (mLastEventCoordinates [0 ] - x ) > ONMOVE_EPSILON
355- || Math .abs (mLastEventCoordinates [1 ] - y ) > ONMOVE_EPSILON );
372+ (Math .abs (lastEventCoordinates [0 ] - x ) > ONMOVE_EPSILON
373+ || Math .abs (lastEventCoordinates [1 ] - y ) > ONMOVE_EPSILON );
356374
357375 // Early exit
358376 if (!qualifiedMove ) {
@@ -384,15 +402,15 @@ private void onMove(
384402 }
385403
386404 // hitState is list ordered from inner child -> parent tag
387- // Traverse hitState back-to-front to find the first divergence with mLastHitState
405+ // Traverse hitState back-to-front to find the first divergence with lastHitPath
388406 // FIXME: this may generate incorrect events when view collapsing changes the hierarchy
389407 boolean nonDivergentListeningToEnter = false ;
390408 boolean nonDivergentListeningToLeave = false ;
391409 int firstDivergentIndexFromBack = 0 ;
392- while (firstDivergentIndexFromBack < Math .min (hitPath .size (), mLastHitPath .size ())
410+ while (firstDivergentIndexFromBack < Math .min (hitPath .size (), lastHitPath .size ())
393411 && hitPath
394412 .get (hitPath .size () - 1 - firstDivergentIndexFromBack )
395- .equals (mLastHitPath .get (mLastHitPath .size () - 1 - firstDivergentIndexFromBack ))) {
413+ .equals (lastHitPath .get (lastHitPath .size () - 1 - firstDivergentIndexFromBack ))) {
396414
397415 // Track if any non-diverging views are listening to enter/leave
398416 View nonDivergentViewTargetView =
@@ -410,32 +428,32 @@ private void onMove(
410428 }
411429
412430 boolean hasDiverged =
413- firstDivergentIndexFromBack < Math .max (hitPath .size (), mLastHitPath .size ());
431+ firstDivergentIndexFromBack < Math .max (hitPath .size (), lastHitPath .size ());
414432
415433 if (hasDiverged ) {
416434 // If something has changed in either enter/exit, let's start a new coalescing key
417435 mTouchEventCoalescingKeyHelper .incrementCoalescingKey (mHoverInteractionKey );
418436
419437 // Out, Leave events
420- if (mLastHitPath .size () > 0 ) {
421- int lastTargetTag = mLastHitPath .get (0 ).getViewId ();
438+ if (lastHitPath .size () > 0 ) {
439+ int lastTargetTag = lastHitPath .get (0 ).getViewId ();
422440 boolean listeningForOut =
423- isAnyoneListeningForBubblingEvent (mLastHitPath , EVENT .OUT , EVENT .OUT_CAPTURE );
441+ isAnyoneListeningForBubblingEvent (lastHitPath , EVENT .OUT , EVENT .OUT_CAPTURE );
424442 if (listeningForOut ) {
425443 eventDispatcher .dispatchEvent (
426444 PointerEvent .obtain (
427445 PointerEventHelper .POINTER_OUT ,
428446 surfaceId ,
429447 lastTargetTag ,
430448 motionEvent ,
431- mTargetCoordinates ,
449+ targetCoordinates ,
432450 mPrimaryPointerId ));
433451 }
434452
435453 // target -> root
436454 List <ViewTarget > leaveViewTargets =
437455 filterByShouldDispatch (
438- mLastHitPath .subList (0 , mLastHitPath .size () - firstDivergentIndexFromBack ),
456+ lastHitPath .subList (0 , lastHitPath .size () - firstDivergentIndexFromBack ),
439457 EVENT .LEAVE ,
440458 EVENT .LEAVE_CAPTURE ,
441459 nonDivergentListeningToLeave );
@@ -446,7 +464,8 @@ private void onMove(
446464 leaveViewTargets ,
447465 eventDispatcher ,
448466 surfaceId ,
449- motionEvent );
467+ motionEvent ,
468+ targetCoordinates );
450469 }
451470 }
452471
@@ -459,7 +478,7 @@ private void onMove(
459478 surfaceId ,
460479 targetTag ,
461480 motionEvent ,
462- mTargetCoordinates ,
481+ targetCoordinates ,
463482 mPrimaryPointerId ));
464483 }
465484
@@ -479,7 +498,8 @@ private void onMove(
479498 enterViewTargets ,
480499 eventDispatcher ,
481500 surfaceId ,
482- motionEvent );
501+ motionEvent ,
502+ targetCoordinates );
483503 }
484504 }
485505
@@ -493,18 +513,20 @@ private void onMove(
493513 surfaceId ,
494514 targetTag ,
495515 motionEvent ,
496- mTargetCoordinates ,
516+ targetCoordinates ,
497517 coalescingKey ,
498518 mPrimaryPointerId ));
499519 }
500520
501- mLastHitPath = hitPath ;
502- mLastEventCoordinates [0 ] = x ;
503- mLastEventCoordinates [1 ] = y ;
521+ mLastHitPathByPointerId .put (activePointerId , hitPath );
522+ mLastEventCoodinatesByPointerId .put (activePointerId , new float [] {x , y });
504523 }
505524
506525 private void dispatchCancelEvent (
507- List <ViewTarget > hitPath , MotionEvent motionEvent , EventDispatcher eventDispatcher ) {
526+ List <ViewTarget > hitPath ,
527+ MotionEvent motionEvent ,
528+ EventDispatcher eventDispatcher ,
529+ float [] targetCoordinates ) {
508530 // This means the gesture has already ended, via some other CANCEL or UP event. This is not
509531 // expected to happen very often as it would mean some child View has decided to intercept the
510532 // touch stream and start a native gesture only upon receiving the UP/CANCEL event.
@@ -526,7 +548,7 @@ private void dispatchCancelEvent(
526548 surfaceId ,
527549 targetTag ,
528550 motionEvent ,
529- mTargetCoordinates ,
551+ targetCoordinates ,
530552 mPrimaryPointerId ));
531553 }
532554
@@ -539,7 +561,8 @@ private void dispatchCancelEvent(
539561 leaveViewTargets ,
540562 eventDispatcher ,
541563 surfaceId ,
542- motionEvent );
564+ motionEvent ,
565+ targetCoordinates );
543566
544567 mTouchEventCoalescingKeyHelper .removeCoalescingKey (mDownStartTime );
545568 mDownStartTime = TouchEvent .UNSET ;
0 commit comments