@@ -111,7 +111,13 @@ public void handleMotionEvent(MotionEvent motionEvent, EventDispatcher eventDisp
111
111
112
112
if (!supportsHover ) {
113
113
dispatchNonBubblingEventForPathWhenListened (
114
- EVENT .ENTER , EVENT .ENTER_CAPTURE , hitPath , eventDispatcher , surfaceId , motionEvent );
114
+ EVENT .ENTER ,
115
+ EVENT .ENTER_CAPTURE ,
116
+ hitPath ,
117
+ eventDispatcher ,
118
+ surfaceId ,
119
+ motionEvent ,
120
+ false );
115
121
}
116
122
117
123
boolean listeningForDown =
@@ -196,7 +202,13 @@ public void handleMotionEvent(MotionEvent motionEvent, EventDispatcher eventDisp
196
202
197
203
if (!supportsHover ) {
198
204
dispatchNonBubblingEventForPathWhenListened (
199
- EVENT .LEAVE , EVENT .LEAVE_CAPTURE , hitPath , eventDispatcher , surfaceId , motionEvent );
205
+ EVENT .LEAVE ,
206
+ EVENT .LEAVE_CAPTURE ,
207
+ hitPath ,
208
+ eventDispatcher ,
209
+ surfaceId ,
210
+ motionEvent ,
211
+ false );
200
212
}
201
213
return ;
202
214
}
@@ -227,22 +239,28 @@ private static boolean isAnyoneListeningForBubblingEvent(
227
239
return false ;
228
240
}
229
241
230
- /*
231
- Dispatch event only if ancestor is listening to relevant event.
232
- This should only be relevant for ENTER/LEAVE events.
233
- @param hitPath - ordered from inner target to root
242
+ /**
243
+ * Dispatch event only if ancestor is listening to relevant capture event. This should only be
244
+ * relevant for ENTER/LEAVE events that need to be dispatched along every relevant view in the hit
245
+ * path.
246
+ *
247
+ * @param pointerEventType - Should only be ENTER/LEAVE events
248
+ * @param hitPath - ViewTargets ordered from target -> root
249
+ * @param dispatcher
250
+ * @param surfaceId
251
+ * @param motionEvent
252
+ * @param forceDispatch - Ignore if ancestor is listening and force the event to be dispatched
234
253
*/
235
-
236
- /** Dispatch non-bubbling event along the hit path only when relevant listeners */
237
254
private static void dispatchNonBubblingEventForPathWhenListened (
238
255
EVENT event ,
239
256
EVENT captureEvent ,
240
257
List <ViewTarget > hitPath ,
241
258
EventDispatcher dispatcher ,
242
259
int surfaceId ,
243
- MotionEvent motionEvent ) {
260
+ MotionEvent motionEvent ,
261
+ boolean forceDispatch ) {
244
262
245
- boolean ancestorListening = false ;
263
+ boolean ancestorListening = forceDispatch ;
246
264
String eventName = PointerEventHelper .getDispatchableEventName (event );
247
265
if (eventName == null ) {
248
266
return ;
@@ -312,54 +330,72 @@ private void handleHoverEvent(
312
330
// hitState is list ordered from inner child -> parent tag
313
331
// Traverse hitState back-to-front to find the first divergence with mLastHitState
314
332
// FIXME: this may generate incorrect events when view collapsing changes the hierarchy
315
- int firstDivergentIndex = 0 ;
316
- while (firstDivergentIndex < Math .min (hitPath .size (), mLastHitPath .size ())
333
+ boolean nonDivergentListeningToEnter = false ;
334
+ boolean nonDivergentListeningToLeave = false ;
335
+ int firstDivergentIndexFromBack = 0 ;
336
+ while (firstDivergentIndexFromBack < Math .min (hitPath .size (), mLastHitPath .size ())
317
337
&& hitPath
318
- .get (hitPath .size () - 1 - firstDivergentIndex )
319
- .equals (mLastHitPath .get (mLastHitPath .size () - 1 - firstDivergentIndex ))) {
320
- firstDivergentIndex ++;
338
+ .get (hitPath .size () - 1 - firstDivergentIndexFromBack )
339
+ .equals (mLastHitPath .get (mLastHitPath .size () - 1 - firstDivergentIndexFromBack ))) {
340
+
341
+ // Track if any non-diverging views are listening to enter/leave
342
+ View nonDivergentViewTargetView =
343
+ hitPath .get (hitPath .size () - 1 - firstDivergentIndexFromBack ).getView ();
344
+ if (!nonDivergentListeningToEnter
345
+ && PointerEventHelper .isListening (nonDivergentViewTargetView , EVENT .ENTER_CAPTURE )) {
346
+ nonDivergentListeningToEnter = true ;
347
+ }
348
+ if (!nonDivergentListeningToLeave
349
+ && PointerEventHelper .isListening (nonDivergentViewTargetView , EVENT .LEAVE_CAPTURE )) {
350
+ nonDivergentListeningToLeave = true ;
351
+ }
352
+
353
+ firstDivergentIndexFromBack ++;
321
354
}
322
355
323
- boolean hasDiverged = firstDivergentIndex < Math .max (hitPath .size (), mLastHitPath .size ());
356
+ boolean hasDiverged =
357
+ firstDivergentIndexFromBack < Math .max (hitPath .size (), mLastHitPath .size ());
324
358
325
- // Fire all relevant enter events
326
359
if (hasDiverged ) {
327
360
// If something has changed in either enter/exit, let's start a new coalescing key
328
361
mTouchEventCoalescingKeyHelper .incrementCoalescingKey (mHoverInteractionKey );
329
362
330
- List <ViewTarget > enterViewTargets = hitPath .subList (0 , hitPath .size () - firstDivergentIndex );
363
+ List <ViewTarget > enterViewTargets =
364
+ hitPath .subList (0 , hitPath .size () - firstDivergentIndexFromBack );
331
365
if (enterViewTargets .size () > 0 ) {
332
- // root -> child
333
- for (int i = enterViewTargets .size (); i -- > 0 ; ) {
334
- eventDispatcher .dispatchEvent (
335
- PointerEvent .obtain (
336
- PointerEventHelper .POINTER_ENTER ,
337
- surfaceId ,
338
- enterViewTargets .get (i ).getViewId (),
339
- motionEvent ));
340
- }
366
+ dispatchNonBubblingEventForPathWhenListened (
367
+ EVENT .ENTER ,
368
+ EVENT .ENTER_CAPTURE ,
369
+ enterViewTargets ,
370
+ eventDispatcher ,
371
+ surfaceId ,
372
+ motionEvent ,
373
+ nonDivergentListeningToEnter );
341
374
}
342
375
343
- // Fire all relevant exit events
344
376
List <ViewTarget > exitViewTargets =
345
- mLastHitPath .subList (0 , mLastHitPath .size () - firstDivergentIndex );
377
+ mLastHitPath .subList (0 , mLastHitPath .size () - firstDivergentIndexFromBack );
346
378
if (exitViewTargets .size () > 0 ) {
347
379
// child -> root
348
- for ( ViewTarget exitViewTarget : exitViewTargets ) {
349
- eventDispatcher . dispatchEvent (
350
- PointerEvent . obtain (
351
- PointerEventHelper . POINTER_LEAVE ,
352
- surfaceId ,
353
- exitViewTarget . getViewId () ,
354
- motionEvent ));
355
- }
380
+ dispatchNonBubblingEventForPathWhenListened (
381
+ EVENT . LEAVE ,
382
+ EVENT . LEAVE_CAPTURE ,
383
+ enterViewTargets ,
384
+ eventDispatcher ,
385
+ surfaceId ,
386
+ motionEvent ,
387
+ nonDivergentListeningToLeave );
356
388
}
357
389
}
358
390
359
391
int coalescingKey = mTouchEventCoalescingKeyHelper .getCoalescingKey (mHoverInteractionKey );
360
- eventDispatcher .dispatchEvent (
361
- PointerEvent .obtain (
362
- PointerEventHelper .POINTER_MOVE , surfaceId , targetTag , motionEvent , coalescingKey ));
392
+ boolean listeningToMove =
393
+ isAnyoneListeningForBubblingEvent (hitPath , EVENT .MOVE , EVENT .MOVE_CAPTURE );
394
+ if (listeningToMove ) {
395
+ eventDispatcher .dispatchEvent (
396
+ PointerEvent .obtain (
397
+ PointerEventHelper .POINTER_MOVE , surfaceId , targetTag , motionEvent , coalescingKey ));
398
+ }
363
399
364
400
mLastHitPath = hitPath ;
365
401
mLastEventCoordinates [0 ] = x ;
@@ -389,7 +425,13 @@ private void dispatchCancelEvent(
389
425
}
390
426
391
427
dispatchNonBubblingEventForPathWhenListened (
392
- EVENT .LEAVE , EVENT .LEAVE_CAPTURE , hitPath , eventDispatcher , surfaceId , motionEvent );
428
+ EVENT .LEAVE ,
429
+ EVENT .LEAVE_CAPTURE ,
430
+ hitPath ,
431
+ eventDispatcher ,
432
+ surfaceId ,
433
+ motionEvent ,
434
+ false );
393
435
394
436
mTouchEventCoalescingKeyHelper .removeCoalescingKey (mDownStartTime );
395
437
mDownStartTime = TouchEvent .UNSET ;
0 commit comments