Skip to content

Commit c34659a

Browse files
Luna Weifacebook-github-bot
authored andcommitted
PointerEvents: Store last hitPath, eventCoordinates for different pointers
Summary: Changelog: [Internal] - Key cached values between different MotionEvents by pointerId. Currently the implementation uses one cached list and array to store the last hitPath and event coordinates. We use these to determine if we've entered or left any views. With more pointers, we need to be tracking these values for each pointer. As well, clean up usage of `mLastTargetCoordinates`. This doesn't need to be a global as its an array that's updated by reference in `findTargetPathAndCoordinatesForTouch` Reviewed By: vincentriemer Differential Revision: D39152528 fbshipit-source-id: 28c18629bf974f41950401c7726a4757ad43ac28
1 parent c89f5fd commit c34659a

File tree

1 file changed

+74
-51
lines changed

1 file changed

+74
-51
lines changed

ReactAndroid/src/main/java/com/facebook/react/uimanager/JSPointerDispatcher.java

Lines changed: 74 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,9 @@
2222
import com.facebook.react.uimanager.events.TouchEventCoalescingKeyHelper;
2323
import java.util.ArrayList;
2424
import java.util.Collections;
25+
import java.util.HashMap;
2526
import 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

Comments
 (0)