From d666eb7a2205ed4bd69bd27029c61ed3457ef49f Mon Sep 17 00:00:00 2001 From: Luna Wei Date: Fri, 24 Jun 2022 15:10:50 -0700 Subject: [PATCH] Fix: PointerEvent filtering Summary: Changelog: [Internal] - Fix a bug in dispatch filtering that was too aggressively filtering out events to fire. My flaw in logic was limiting the `isListening(view, bubble)` logic to `i==0` for relevant `ViewTargets`, when in reality, we need to be checking if every `ViewTarget` passed to `filterByShouldDispatch` is listening to a bubble event. Further, as vincentriemer pointed out, `ancestorListening` should only be set true if a `ViewTarget` is listening to a capture event. Reviewed By: vincentriemer Differential Revision: D37423952 fbshipit-source-id: 2ed08038632677c24766bca6214dc00013fa2446 --- .../react/uimanager/JSPointerDispatcher.java | 20 +++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/JSPointerDispatcher.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/JSPointerDispatcher.java index 935941d60e6..71b9a6be59d 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/JSPointerDispatcher.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/JSPointerDispatcher.java @@ -249,28 +249,32 @@ public class JSPointerDispatcher { * Returns list of view targets that we should be dispatching events from * * @param viewTargets, ordered from target -> root - * @param bubble, name of event that bubbles - * @param capture, name of event that captures + * @param bubble, name of event that bubbles. Should only ever be enter or leave + * @param capture, name of event that captures. Should only ever be enter or leave * @param forceDispatch, if true, all viewTargets should dispatch * @return list of viewTargets filtered from target -> root */ private static List filterByShouldDispatch( List viewTargets, EVENT bubble, EVENT capture, boolean forceDispatch) { + + List dispatchableViewTargets = new ArrayList<>(viewTargets); if (forceDispatch) { - return viewTargets; + return dispatchableViewTargets; } boolean ancestorListening = false; - List dispatchableViewTargets = new ArrayList(viewTargets); + + // Start to filter which viewTargets may not need to dispatch an event for (int i = viewTargets.size() - 1; i >= 0; i--) { ViewTarget viewTarget = viewTargets.get(i); View view = viewTarget.getView(); + if (!ancestorListening - && (PointerEventHelper.isListening(view, capture) - || (i == 0 && PointerEventHelper.isListening(view, bubble)))) { - ancestorListening = true; - } else if (!ancestorListening) { + && !PointerEventHelper.isListening(view, capture) + && !PointerEventHelper.isListening(view, bubble)) { dispatchableViewTargets.remove(i); + } else if (!ancestorListening && PointerEventHelper.isListening(view, capture)) { + ancestorListening = true; } } return dispatchableViewTargets;