Skip to content

Commit

Permalink
PointerEvents: Store last hitPath, eventCoordinates for different poi…
Browse files Browse the repository at this point in the history
…nters

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
  • Loading branch information
Luna Wei authored and facebook-github-bot committed Sep 1, 2022
1 parent c89f5fd commit c34659a
Showing 1 changed file with 74 additions and 51 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@
import com.facebook.react.uimanager.events.TouchEventCoalescingKeyHelper;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
* JSPointerDispatcher handles dispatching pointer events to JS from RootViews. If you implement
Expand All @@ -37,9 +39,8 @@ public class JSPointerDispatcher {

private final TouchEventCoalescingKeyHelper mTouchEventCoalescingKeyHelper =
new TouchEventCoalescingKeyHelper();
private List<ViewTarget> mLastHitPath = Collections.emptyList();
private final float[] mLastEventCoordinates = new float[2];
private final float[] mTargetCoordinates = new float[2];
private final Map<Integer, List<ViewTarget>> mLastHitPathByPointerId = new HashMap<>();
private final Map<Integer, float[]> mLastEventCoodinatesByPointerId = new HashMap<>();

private int mChildHandlingNativeGesture = -1;
private int mPrimaryPointerId = UNSET_POINTER_ID;
Expand All @@ -62,10 +63,11 @@ public void onChildStartedNativeGesture(
return;
}

float[] targetCoordinates = new float[2];
List<ViewTarget> hitPath =
TouchTargetHelper.findTargetPathAndCoordinatesForTouch(
motionEvent.getX(), motionEvent.getY(), mRootViewGroup, mTargetCoordinates);
dispatchCancelEvent(hitPath, motionEvent, eventDispatcher);
motionEvent.getX(), motionEvent.getY(), mRootViewGroup, targetCoordinates);
dispatchCancelEvent(hitPath, motionEvent, eventDispatcher, targetCoordinates);
mChildHandlingNativeGesture = childView.getId();
}

Expand All @@ -79,7 +81,8 @@ private void onUp(
List<ViewTarget> hitPath,
int surfaceId,
MotionEvent motionEvent,
EventDispatcher eventDispatcher) {
EventDispatcher eventDispatcher,
float[] targetCoordinates) {
if (motionEvent.getActionMasked() == MotionEvent.ACTION_UP) {
// End of a "down" coalescing key
mTouchEventCoalescingKeyHelper.removeCoalescingKey(mDownStartTime);
Expand All @@ -97,7 +100,7 @@ private void onUp(
surfaceId,
activeTargetTag,
motionEvent,
mTargetCoordinates,
targetCoordinates,
mPrimaryPointerId));
}

Expand All @@ -111,7 +114,7 @@ private void onUp(
surfaceId,
activeTargetTag,
motionEvent,
mTargetCoordinates,
targetCoordinates,
mPrimaryPointerId));
}

Expand All @@ -124,21 +127,26 @@ private void onUp(
leaveViewTargets,
eventDispatcher,
surfaceId,
motionEvent);
motionEvent,
targetCoordinates);

int activePointerId = motionEvent.getPointerId(motionEvent.getActionIndex());
mLastHitPathByPointerId.remove(activePointerId);
mLastEventCoodinatesByPointerId.remove(activePointerId);
}

if (motionEvent.getActionMasked() == MotionEvent.ACTION_UP) {
mPrimaryPointerId = UNSET_POINTER_ID;
}
return;
}

private void onDown(
int activeTargetTag,
List<ViewTarget> hitPath,
int surfaceId,
MotionEvent motionEvent,
EventDispatcher eventDispatcher) {
EventDispatcher eventDispatcher,
float[] targetCoordinates) {

if (motionEvent.getActionMasked() == MotionEvent.ACTION_DOWN) {
mPrimaryPointerId = motionEvent.getPointerId(0);
Expand All @@ -160,7 +168,7 @@ private void onDown(
surfaceId,
activeTargetTag,
motionEvent,
mTargetCoordinates,
targetCoordinates,
mPrimaryPointerId));
}

Expand All @@ -174,7 +182,8 @@ private void onDown(
enterViewTargets,
eventDispatcher,
surfaceId,
motionEvent);
motionEvent,
targetCoordinates);
}

boolean listeningForDown =
Expand All @@ -186,7 +195,7 @@ private void onDown(
surfaceId,
activeTargetTag,
motionEvent,
mTargetCoordinates,
targetCoordinates,
mPrimaryPointerId));
}
}
Expand All @@ -199,18 +208,18 @@ public void handleMotionEvent(MotionEvent motionEvent, EventDispatcher eventDisp
return;
}

boolean supportsHover = PointerEventHelper.supportsHover(motionEvent);
int surfaceId = UIManagerHelper.getSurfaceId(mRootViewGroup);

// Only relevant for POINTER_UP/POINTER_DOWN actions, otherwise 0
int actionIndex = motionEvent.getActionIndex();

float[] targetCoordinates = new float[2];
List<ViewTarget> hitPath =
TouchTargetHelper.findTargetPathAndCoordinatesForTouch(
motionEvent.getX(actionIndex),
motionEvent.getY(actionIndex),
mRootViewGroup,
mTargetCoordinates);
targetCoordinates);

if (hitPath.isEmpty()) {
return;
Expand All @@ -220,7 +229,7 @@ public void handleMotionEvent(MotionEvent motionEvent, EventDispatcher eventDisp
int activeTargetTag = activeViewTarget.getViewId();

if (action == MotionEvent.ACTION_HOVER_MOVE) {
onMove(motionEvent, eventDispatcher, surfaceId, hitPath);
onMove(motionEvent, eventDispatcher, surfaceId, hitPath, targetCoordinates);
return;
}

Expand All @@ -234,7 +243,8 @@ public void handleMotionEvent(MotionEvent motionEvent, EventDispatcher eventDisp
switch (action) {
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_POINTER_DOWN:
onDown(activeTargetTag, hitPath, surfaceId, motionEvent, eventDispatcher);
onDown(
activeTargetTag, hitPath, surfaceId, motionEvent, eventDispatcher, targetCoordinates);
break;
case MotionEvent.ACTION_MOVE:
// TODO(luwe) - converge this with ACTION_HOVER_MOVE
Expand All @@ -249,27 +259,22 @@ public void handleMotionEvent(MotionEvent motionEvent, EventDispatcher eventDisp
surfaceId,
activeTargetTag,
motionEvent,
mTargetCoordinates,
targetCoordinates,
coalescingKey,
mPrimaryPointerId));
}
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_POINTER_UP:
onUp(activeTargetTag, hitPath, surfaceId, motionEvent, eventDispatcher);
onUp(activeTargetTag, hitPath, surfaceId, motionEvent, eventDispatcher, targetCoordinates);
break;
case MotionEvent.ACTION_CANCEL:
dispatchCancelEvent(hitPath, motionEvent, eventDispatcher);
dispatchCancelEvent(hitPath, motionEvent, eventDispatcher, targetCoordinates);
break;
default:
FLog.w(
ReactConstants.TAG,
"Warning : Motion Event was ignored. Action="
+ action
+ " Target="
+ activeTargetTag
+ " Supports Hover="
+ supportsHover);
"Warning : Motion Event was ignored. Action=" + action + " Target=" + activeTargetTag);
return;
}
}
Expand Down Expand Up @@ -325,13 +330,14 @@ private void dispatchEventForViewTargets(
List<ViewTarget> viewTargets,
EventDispatcher dispatcher,
int surfaceId,
MotionEvent motionEvent) {
MotionEvent motionEvent,
float[] targetCoordinates) {

for (ViewTarget viewTarget : viewTargets) {
int viewId = viewTarget.getViewId();
dispatcher.dispatchEvent(
PointerEvent.obtain(
eventName, surfaceId, viewId, motionEvent, mTargetCoordinates, mPrimaryPointerId));
eventName, surfaceId, viewId, motionEvent, targetCoordinates, mPrimaryPointerId));
}
}

Expand All @@ -340,19 +346,31 @@ private void onMove(
MotionEvent motionEvent,
EventDispatcher eventDispatcher,
int surfaceId,
List<ViewTarget> hitPath) {
List<ViewTarget> hitPath,
float[] targetCoordinates) {

int action = motionEvent.getActionMasked();
if (action != MotionEvent.ACTION_HOVER_MOVE) {
return;
}

int actionIndex = motionEvent.getActionIndex();
int activePointerId = motionEvent.getPointerId(actionIndex);
float x = motionEvent.getX();
float y = motionEvent.getY();
List<ViewTarget> lastHitPath =
mLastHitPathByPointerId.containsKey(activePointerId)
? mLastHitPathByPointerId.get(activePointerId)
: Collections.emptyList();

float[] lastEventCoordinates =
mLastEventCoodinatesByPointerId.containsKey(activePointerId)
? mLastEventCoodinatesByPointerId.get(activePointerId)
: new float[] {0, 0};

boolean qualifiedMove =
(Math.abs(mLastEventCoordinates[0] - x) > ONMOVE_EPSILON
|| Math.abs(mLastEventCoordinates[1] - y) > ONMOVE_EPSILON);
(Math.abs(lastEventCoordinates[0] - x) > ONMOVE_EPSILON
|| Math.abs(lastEventCoordinates[1] - y) > ONMOVE_EPSILON);

// Early exit
if (!qualifiedMove) {
Expand Down Expand Up @@ -384,15 +402,15 @@ private void onMove(
}

// hitState is list ordered from inner child -> parent tag
// Traverse hitState back-to-front to find the first divergence with mLastHitState
// Traverse hitState back-to-front to find the first divergence with lastHitPath
// FIXME: this may generate incorrect events when view collapsing changes the hierarchy
boolean nonDivergentListeningToEnter = false;
boolean nonDivergentListeningToLeave = false;
int firstDivergentIndexFromBack = 0;
while (firstDivergentIndexFromBack < Math.min(hitPath.size(), mLastHitPath.size())
while (firstDivergentIndexFromBack < Math.min(hitPath.size(), lastHitPath.size())
&& hitPath
.get(hitPath.size() - 1 - firstDivergentIndexFromBack)
.equals(mLastHitPath.get(mLastHitPath.size() - 1 - firstDivergentIndexFromBack))) {
.equals(lastHitPath.get(lastHitPath.size() - 1 - firstDivergentIndexFromBack))) {

// Track if any non-diverging views are listening to enter/leave
View nonDivergentViewTargetView =
Expand All @@ -410,32 +428,32 @@ private void onMove(
}

boolean hasDiverged =
firstDivergentIndexFromBack < Math.max(hitPath.size(), mLastHitPath.size());
firstDivergentIndexFromBack < Math.max(hitPath.size(), lastHitPath.size());

if (hasDiverged) {
// If something has changed in either enter/exit, let's start a new coalescing key
mTouchEventCoalescingKeyHelper.incrementCoalescingKey(mHoverInteractionKey);

// Out, Leave events
if (mLastHitPath.size() > 0) {
int lastTargetTag = mLastHitPath.get(0).getViewId();
if (lastHitPath.size() > 0) {
int lastTargetTag = lastHitPath.get(0).getViewId();
boolean listeningForOut =
isAnyoneListeningForBubblingEvent(mLastHitPath, EVENT.OUT, EVENT.OUT_CAPTURE);
isAnyoneListeningForBubblingEvent(lastHitPath, EVENT.OUT, EVENT.OUT_CAPTURE);
if (listeningForOut) {
eventDispatcher.dispatchEvent(
PointerEvent.obtain(
PointerEventHelper.POINTER_OUT,
surfaceId,
lastTargetTag,
motionEvent,
mTargetCoordinates,
targetCoordinates,
mPrimaryPointerId));
}

// target -> root
List<ViewTarget> leaveViewTargets =
filterByShouldDispatch(
mLastHitPath.subList(0, mLastHitPath.size() - firstDivergentIndexFromBack),
lastHitPath.subList(0, lastHitPath.size() - firstDivergentIndexFromBack),
EVENT.LEAVE,
EVENT.LEAVE_CAPTURE,
nonDivergentListeningToLeave);
Expand All @@ -446,7 +464,8 @@ private void onMove(
leaveViewTargets,
eventDispatcher,
surfaceId,
motionEvent);
motionEvent,
targetCoordinates);
}
}

Expand All @@ -459,7 +478,7 @@ private void onMove(
surfaceId,
targetTag,
motionEvent,
mTargetCoordinates,
targetCoordinates,
mPrimaryPointerId));
}

Expand All @@ -479,7 +498,8 @@ private void onMove(
enterViewTargets,
eventDispatcher,
surfaceId,
motionEvent);
motionEvent,
targetCoordinates);
}
}

Expand All @@ -493,18 +513,20 @@ private void onMove(
surfaceId,
targetTag,
motionEvent,
mTargetCoordinates,
targetCoordinates,
coalescingKey,
mPrimaryPointerId));
}

mLastHitPath = hitPath;
mLastEventCoordinates[0] = x;
mLastEventCoordinates[1] = y;
mLastHitPathByPointerId.put(activePointerId, hitPath);
mLastEventCoodinatesByPointerId.put(activePointerId, new float[] {x, y});
}

private void dispatchCancelEvent(
List<ViewTarget> hitPath, MotionEvent motionEvent, EventDispatcher eventDispatcher) {
List<ViewTarget> hitPath,
MotionEvent motionEvent,
EventDispatcher eventDispatcher,
float[] targetCoordinates) {
// This means the gesture has already ended, via some other CANCEL or UP event. This is not
// expected to happen very often as it would mean some child View has decided to intercept the
// touch stream and start a native gesture only upon receiving the UP/CANCEL event.
Expand All @@ -526,7 +548,7 @@ private void dispatchCancelEvent(
surfaceId,
targetTag,
motionEvent,
mTargetCoordinates,
targetCoordinates,
mPrimaryPointerId));
}

Expand All @@ -539,7 +561,8 @@ private void dispatchCancelEvent(
leaveViewTargets,
eventDispatcher,
surfaceId,
motionEvent);
motionEvent,
targetCoordinates);

mTouchEventCoalescingKeyHelper.removeCoalescingKey(mDownStartTime);
mDownStartTime = TouchEvent.UNSET;
Expand Down

0 comments on commit c34659a

Please sign in to comment.