Skip to content

Commit 64ae12e

Browse files
Luna Weifacebook-github-bot
authored andcommitted
PointerEvents: Refactor JSPointerDispatcher to share logic for UP/DOWN for secondary pointers
Summary: Changelog: [Internal] - Refactor JSPointerDispatcher to group secondary actions (pointer_up, pointer_down) to use same logic and emit non-direct events This diff re-arranges some code and re-uses some logic for different MotionEvent types. Specifically, before our code for handling a motionEvent looked like ``` func onMotionEvent(event) { if (event is HOVER_MOVE) { handleHoverEvent(event) } if (event is ACTION_DOWN) { // logic for dispatching down, enter, over } if (event is ACTION_POINTER_DOWN) { // this represents any secondary pointer going down // logic for dispatching down } if (event is ACTION_MOVE) { // logic for dispatching touch move } if (event is ACTION_UP) { // logic for dispatching up, out, leave } if (event is ACTION_POINTER_UP) { // this represents any secondary pointer going up // logic for dispatching up } .... } ``` now, we've refactored it to be like: ``` func onMotionEvent(event) { if (event is HOVER_MOVE) { // Still keep this as separate because it does some special things. Will refactor in follow-up diff handleHoverEvent(event) } switch() { case ACTION_DOWN or ACTION_POINTER_DOWN: // do same logic break; case ACTION_UP or ACTION_POINTER_UP: // do same logic break; case ACTION_MOVE: // do same logic, we will want to converge this logic with HOVER_MOVE, todo in a follow-up break; ... } .... } ``` This refactor adds the functionality of `enter, over, out, leave` to secondary pointer events in which they weren't fired before. Reviewed By: vincentriemer Differential Revision: D39142820 fbshipit-source-id: 8b89db6dc22f24583f8c14dbb8392d4dc8ff6e4d
1 parent c52df02 commit 64ae12e

File tree

1 file changed

+145
-165
lines changed

1 file changed

+145
-165
lines changed

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

Lines changed: 145 additions & 165 deletions
Original file line numberDiff line numberDiff line change
@@ -74,224 +74,204 @@ public void onChildEndedNativeGesture() {
7474
mChildHandlingNativeGesture = -1;
7575
}
7676

77-
public void handleMotionEvent(MotionEvent motionEvent, EventDispatcher eventDispatcher) {
78-
int action = motionEvent.getActionMasked();
79-
80-
// Ignore hover enter/exit because we determine this ourselves
81-
if (action == MotionEvent.ACTION_HOVER_EXIT || action == MotionEvent.ACTION_HOVER_ENTER) {
82-
return;
77+
private void onUp(
78+
int activeTargetTag,
79+
List<ViewTarget> hitPath,
80+
int surfaceId,
81+
MotionEvent motionEvent,
82+
EventDispatcher eventDispatcher) {
83+
if (motionEvent.getActionMasked() == MotionEvent.ACTION_UP) {
84+
// End of a "down" coalescing key
85+
mTouchEventCoalescingKeyHelper.removeCoalescingKey(mDownStartTime);
86+
mDownStartTime = TouchEvent.UNSET;
87+
} else {
88+
mTouchEventCoalescingKeyHelper.incrementCoalescingKey(mDownStartTime);
8389
}
8490

8591
boolean supportsHover = PointerEventHelper.supportsHover(motionEvent);
86-
int surfaceId = UIManagerHelper.getSurfaceId(mRootViewGroup);
87-
88-
// Only relevant for POINTER_UP/POINTER_DOWN actions, otherwise 0
89-
int actionIndex = motionEvent.getActionIndex();
90-
91-
List<ViewTarget> hitPath =
92-
TouchTargetHelper.findTargetPathAndCoordinatesForTouch(
93-
motionEvent.getX(actionIndex),
94-
motionEvent.getY(actionIndex),
95-
mRootViewGroup,
96-
mTargetCoordinates);
97-
98-
if (hitPath.isEmpty()) {
99-
return;
100-
}
101-
102-
TouchTargetHelper.ViewTarget activeViewTarget = hitPath.get(0);
103-
int activeTargetTag = activeViewTarget.getViewId();
104-
105-
if (action == MotionEvent.ACTION_HOVER_MOVE) {
106-
handleHoverEvent(motionEvent, eventDispatcher, surfaceId, hitPath);
107-
return;
92+
boolean listeningForUp = isAnyoneListeningForBubblingEvent(hitPath, EVENT.UP, EVENT.UP_CAPTURE);
93+
if (listeningForUp) {
94+
eventDispatcher.dispatchEvent(
95+
PointerEvent.obtain(
96+
PointerEventHelper.POINTER_UP,
97+
surfaceId,
98+
activeTargetTag,
99+
motionEvent,
100+
mTargetCoordinates,
101+
mPrimaryPointerId));
108102
}
109103

110-
// First down pointer
111-
if (action == MotionEvent.ACTION_DOWN) {
112-
mPrimaryPointerId = motionEvent.getPointerId(actionIndex);
113-
114-
// Start a "down" coalescing key
115-
mDownStartTime = motionEvent.getEventTime();
116-
mTouchEventCoalescingKeyHelper.addCoalescingKey(mDownStartTime);
117-
118-
if (!supportsHover) {
119-
// Indirect OVER event dispatches before ENTER
120-
boolean listeningForOver =
121-
isAnyoneListeningForBubblingEvent(hitPath, EVENT.OVER, EVENT.OVER_CAPTURE);
122-
if (listeningForOver) {
123-
eventDispatcher.dispatchEvent(
124-
PointerEvent.obtain(
125-
PointerEventHelper.POINTER_OVER,
126-
surfaceId,
127-
activeTargetTag,
128-
motionEvent,
129-
mTargetCoordinates,
130-
mPrimaryPointerId));
131-
}
132-
133-
List<ViewTarget> enterViewTargets =
134-
filterByShouldDispatch(hitPath, EVENT.ENTER, EVENT.ENTER_CAPTURE, false);
135-
136-
// Dispatch root -> target, we need to reverse order of enterViewTargets
137-
Collections.reverse(enterViewTargets);
138-
dispatchEventForViewTargets(
139-
PointerEventHelper.POINTER_ENTER,
140-
enterViewTargets,
141-
eventDispatcher,
142-
surfaceId,
143-
motionEvent);
144-
}
145-
146-
boolean listeningForDown =
147-
isAnyoneListeningForBubblingEvent(hitPath, EVENT.DOWN, EVENT.DOWN_CAPTURE);
148-
if (listeningForDown) {
104+
if (!supportsHover) {
105+
boolean listeningForOut =
106+
isAnyoneListeningForBubblingEvent(hitPath, EVENT.OUT, EVENT.OUT_CAPTURE);
107+
if (listeningForOut) {
149108
eventDispatcher.dispatchEvent(
150109
PointerEvent.obtain(
151-
PointerEventHelper.POINTER_DOWN,
110+
PointerEventHelper.POINTER_OUT,
152111
surfaceId,
153112
activeTargetTag,
154113
motionEvent,
155114
mTargetCoordinates,
156115
mPrimaryPointerId));
157116
}
158117

159-
return;
118+
List<ViewTarget> leaveViewTargets =
119+
filterByShouldDispatch(hitPath, EVENT.LEAVE, EVENT.LEAVE_CAPTURE, false);
120+
121+
// target -> root
122+
dispatchEventForViewTargets(
123+
PointerEventHelper.POINTER_LEAVE,
124+
leaveViewTargets,
125+
eventDispatcher,
126+
surfaceId,
127+
motionEvent);
160128
}
161129

162-
// If the touch was intercepted by a child, we've already sent a cancel event to JS for this
163-
// gesture, so we shouldn't send any more pointer events related to it.
164-
if (mChildHandlingNativeGesture != -1) {
165-
return;
130+
if (motionEvent.getActionMasked() == MotionEvent.ACTION_UP) {
131+
mPrimaryPointerId = UNSET_POINTER_ID;
166132
}
133+
return;
134+
}
167135

168-
// New pointer goes down, this can only happen after ACTION_DOWN is sent for the first pointer
169-
if (action == MotionEvent.ACTION_POINTER_DOWN) {
170-
mTouchEventCoalescingKeyHelper.incrementCoalescingKey(mDownStartTime);
136+
private void onDown(
137+
int activeTargetTag,
138+
List<ViewTarget> hitPath,
139+
int surfaceId,
140+
MotionEvent motionEvent,
141+
EventDispatcher eventDispatcher) {
171142

172-
// TODO(luwe) We need to fire indirect over,enter events for secondary pointers
143+
if (motionEvent.getActionMasked() == MotionEvent.ACTION_DOWN) {
144+
mPrimaryPointerId = motionEvent.getPointerId(0);
145+
mDownStartTime = motionEvent.getEventTime();
146+
mTouchEventCoalescingKeyHelper.addCoalescingKey(mDownStartTime);
147+
} else {
148+
mTouchEventCoalescingKeyHelper.incrementCoalescingKey(mDownStartTime);
149+
}
173150

174-
boolean listeningForDown =
175-
isAnyoneListeningForBubblingEvent(hitPath, EVENT.DOWN, EVENT.DOWN_CAPTURE);
176-
if (listeningForDown) {
151+
boolean supportsHover = PointerEventHelper.supportsHover(motionEvent);
152+
if (!supportsHover) {
153+
// Indirect OVER event dispatches before ENTER
154+
boolean listeningForOver =
155+
isAnyoneListeningForBubblingEvent(hitPath, EVENT.OVER, EVENT.OVER_CAPTURE);
156+
if (listeningForOver) {
177157
eventDispatcher.dispatchEvent(
178158
PointerEvent.obtain(
179-
PointerEventHelper.POINTER_DOWN,
159+
PointerEventHelper.POINTER_OVER,
180160
surfaceId,
181161
activeTargetTag,
182162
motionEvent,
183163
mTargetCoordinates,
184164
mPrimaryPointerId));
185165
}
186166

187-
return;
167+
List<ViewTarget> enterViewTargets =
168+
filterByShouldDispatch(hitPath, EVENT.ENTER, EVENT.ENTER_CAPTURE, false);
169+
170+
// Dispatch root -> target, we need to reverse order of enterViewTargets
171+
Collections.reverse(enterViewTargets);
172+
dispatchEventForViewTargets(
173+
PointerEventHelper.POINTER_ENTER,
174+
enterViewTargets,
175+
eventDispatcher,
176+
surfaceId,
177+
motionEvent);
188178
}
189179

190-
if (action == MotionEvent.ACTION_MOVE) {
191-
int coalescingKey = mTouchEventCoalescingKeyHelper.getCoalescingKey(mDownStartTime);
180+
boolean listeningForDown =
181+
isAnyoneListeningForBubblingEvent(hitPath, EVENT.DOWN, EVENT.DOWN_CAPTURE);
182+
if (listeningForDown) {
183+
eventDispatcher.dispatchEvent(
184+
PointerEvent.obtain(
185+
PointerEventHelper.POINTER_DOWN,
186+
surfaceId,
187+
activeTargetTag,
188+
motionEvent,
189+
mTargetCoordinates,
190+
mPrimaryPointerId));
191+
}
192+
}
192193

193-
boolean listeningForMove =
194-
isAnyoneListeningForBubblingEvent(hitPath, EVENT.MOVE, EVENT.MOVE_CAPTURE);
195-
if (listeningForMove) {
196-
eventDispatcher.dispatchEvent(
197-
PointerEvent.obtain(
198-
PointerEventHelper.POINTER_MOVE,
199-
surfaceId,
200-
activeTargetTag,
201-
motionEvent,
202-
mTargetCoordinates,
203-
coalescingKey,
204-
mPrimaryPointerId));
205-
}
194+
public void handleMotionEvent(MotionEvent motionEvent, EventDispatcher eventDispatcher) {
195+
int action = motionEvent.getActionMasked();
206196

197+
// Ignore hover enter/exit because we determine this ourselves
198+
if (action == MotionEvent.ACTION_HOVER_EXIT || action == MotionEvent.ACTION_HOVER_ENTER) {
207199
return;
208200
}
209201

210-
// Exactly one of the pointers goes up, not the last one
211-
if (action == MotionEvent.ACTION_POINTER_UP) {
212-
mTouchEventCoalescingKeyHelper.incrementCoalescingKey(mDownStartTime);
202+
boolean supportsHover = PointerEventHelper.supportsHover(motionEvent);
203+
int surfaceId = UIManagerHelper.getSurfaceId(mRootViewGroup);
213204

214-
// TODO(luwe) We need to fire indirect out,leave events for secondary pointers
205+
// Only relevant for POINTER_UP/POINTER_DOWN actions, otherwise 0
206+
int actionIndex = motionEvent.getActionIndex();
215207

216-
boolean listeningForUp =
217-
isAnyoneListeningForBubblingEvent(hitPath, EVENT.UP, EVENT.UP_CAPTURE);
218-
if (listeningForUp) {
219-
eventDispatcher.dispatchEvent(
220-
PointerEvent.obtain(
221-
PointerEventHelper.POINTER_UP,
222-
surfaceId,
223-
activeTargetTag,
224-
motionEvent,
225-
mTargetCoordinates,
226-
mPrimaryPointerId));
227-
}
208+
List<ViewTarget> hitPath =
209+
TouchTargetHelper.findTargetPathAndCoordinatesForTouch(
210+
motionEvent.getX(actionIndex),
211+
motionEvent.getY(actionIndex),
212+
mRootViewGroup,
213+
mTargetCoordinates);
228214

215+
if (hitPath.isEmpty()) {
229216
return;
230217
}
231218

232-
// Last pointer comes up
233-
if (action == MotionEvent.ACTION_UP) {
219+
TouchTargetHelper.ViewTarget activeViewTarget = hitPath.get(0);
220+
int activeTargetTag = activeViewTarget.getViewId();
234221

235-
// End of a "down" coalescing key
236-
mTouchEventCoalescingKeyHelper.removeCoalescingKey(mDownStartTime);
237-
mDownStartTime = TouchEvent.UNSET;
222+
if (action == MotionEvent.ACTION_HOVER_MOVE) {
223+
onMove(motionEvent, eventDispatcher, surfaceId, hitPath);
224+
return;
225+
}
238226

239-
boolean listeningForUp =
240-
isAnyoneListeningForBubblingEvent(hitPath, EVENT.UP, EVENT.UP_CAPTURE);
241-
if (listeningForUp) {
242-
eventDispatcher.dispatchEvent(
243-
PointerEvent.obtain(
244-
PointerEventHelper.POINTER_UP,
245-
surfaceId,
246-
activeTargetTag,
247-
motionEvent,
248-
mTargetCoordinates,
249-
mPrimaryPointerId));
250-
}
227+
// TODO(luwe) - Update this to properly handle native gesture handling for non-hover move events
228+
// If the touch was intercepted by a child, we've already sent a cancel event to JS for this
229+
// gesture, so we shouldn't send any more pointer events related to it.
230+
if (mChildHandlingNativeGesture != -1) {
231+
return;
232+
}
251233

252-
if (!supportsHover) {
253-
boolean listeningForOut =
254-
isAnyoneListeningForBubblingEvent(hitPath, EVENT.OUT, EVENT.OUT_CAPTURE);
255-
if (listeningForOut) {
234+
switch (action) {
235+
case MotionEvent.ACTION_DOWN:
236+
case MotionEvent.ACTION_POINTER_DOWN:
237+
onDown(activeTargetTag, hitPath, surfaceId, motionEvent, eventDispatcher);
238+
break;
239+
case MotionEvent.ACTION_MOVE:
240+
// TODO(luwe) - converge this with ACTION_HOVER_MOVE
241+
int coalescingKey = mTouchEventCoalescingKeyHelper.getCoalescingKey(mDownStartTime);
242+
243+
boolean listeningForMove =
244+
isAnyoneListeningForBubblingEvent(hitPath, EVENT.MOVE, EVENT.MOVE_CAPTURE);
245+
if (listeningForMove) {
256246
eventDispatcher.dispatchEvent(
257247
PointerEvent.obtain(
258-
PointerEventHelper.POINTER_OUT,
248+
PointerEventHelper.POINTER_MOVE,
259249
surfaceId,
260250
activeTargetTag,
261251
motionEvent,
262252
mTargetCoordinates,
253+
coalescingKey,
263254
mPrimaryPointerId));
264255
}
265-
266-
List<ViewTarget> leaveViewTargets =
267-
filterByShouldDispatch(hitPath, EVENT.LEAVE, EVENT.LEAVE_CAPTURE, false);
268-
269-
// target -> root
270-
dispatchEventForViewTargets(
271-
PointerEventHelper.POINTER_LEAVE,
272-
leaveViewTargets,
273-
eventDispatcher,
274-
surfaceId,
275-
motionEvent);
276-
}
277-
278-
mPrimaryPointerId = UNSET_POINTER_ID;
279-
return;
256+
break;
257+
case MotionEvent.ACTION_UP:
258+
case MotionEvent.ACTION_POINTER_UP:
259+
onUp(activeTargetTag, hitPath, surfaceId, motionEvent, eventDispatcher);
260+
break;
261+
case MotionEvent.ACTION_CANCEL:
262+
dispatchCancelEvent(hitPath, motionEvent, eventDispatcher);
263+
break;
264+
default:
265+
FLog.w(
266+
ReactConstants.TAG,
267+
"Warning : Motion Event was ignored. Action="
268+
+ action
269+
+ " Target="
270+
+ activeTargetTag
271+
+ " Supports Hover="
272+
+ supportsHover);
273+
return;
280274
}
281-
282-
if (action == MotionEvent.ACTION_CANCEL) {
283-
dispatchCancelEvent(hitPath, motionEvent, eventDispatcher);
284-
return;
285-
}
286-
287-
FLog.w(
288-
ReactConstants.TAG,
289-
"Warning : Motion Event was ignored. Action="
290-
+ action
291-
+ " Target="
292-
+ activeTargetTag
293-
+ " Supports Hover="
294-
+ supportsHover);
295275
}
296276

297277
private static boolean isAnyoneListeningForBubblingEvent(
@@ -356,7 +336,7 @@ private void dispatchEventForViewTargets(
356336
}
357337

358338
// called on hover_move motion events only
359-
private void handleHoverEvent(
339+
private void onMove(
360340
MotionEvent motionEvent,
361341
EventDispatcher eventDispatcher,
362342
int surfaceId,

0 commit comments

Comments
 (0)