From 837aafde72fb43836aa7c36cf66db4e9abae0e17 Mon Sep 17 00:00:00 2001 From: Olivier Notteghem Date: Tue, 7 Jun 2016 11:53:28 -0700 Subject: [PATCH] Fix touch handling crash that can when Modal is displayed as a result of touch handling code Reviewed By: dmmiller Differential Revision: D3399325 fbshipit-source-id: 0a0bb179ef524bf35cc137d94ea3d5680a68aab2 --- .../react/uimanager/JSTouchDispatcher.java | 22 ++++++++++------ .../react/uimanager/events/TouchEvent.java | 25 +++++++++++++------ .../events/TouchEventCoalescingKeyHelper.java | 24 +++++++++--------- 3 files changed, 44 insertions(+), 27 deletions(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/JSTouchDispatcher.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/JSTouchDispatcher.java index a5d7056ce..0fba85655 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/JSTouchDispatcher.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/JSTouchDispatcher.java @@ -32,6 +32,8 @@ public class JSTouchDispatcher { private final float[] mTargetCoordinates = new float[2]; private boolean mChildIsHandlingNativeGesture = false; private final ViewGroup mRootViewGroup; + private final TouchEventCoalescingKeyHelper mTouchEventCoalescingKeyHelper = + new TouchEventCoalescingKeyHelper(); public JSTouchDispatcher(ViewGroup viewGroup) { mRootViewGroup = viewGroup; @@ -83,7 +85,8 @@ public class JSTouchDispatcher { TouchEventType.START, ev, mTargetCoordinates[0], - mTargetCoordinates[1])); + mTargetCoordinates[1], + mTouchEventCoalescingKeyHelper)); } else if (mChildIsHandlingNativeGesture) { // If the touch was intercepted by a child, we've already sent a cancel event to JS for this // gesture, so we shouldn't send any more touches related to it. @@ -105,7 +108,8 @@ public class JSTouchDispatcher { TouchEventType.END, ev, mTargetCoordinates[0], - mTargetCoordinates[1])); + mTargetCoordinates[1], + mTouchEventCoalescingKeyHelper)); mTargetTag = -1; } else if (action == MotionEvent.ACTION_MOVE) { // Update pointer position for current gesture @@ -116,7 +120,8 @@ public class JSTouchDispatcher { TouchEventType.MOVE, ev, mTargetCoordinates[0], - mTargetCoordinates[1])); + mTargetCoordinates[1], + mTouchEventCoalescingKeyHelper)); } else if (action == MotionEvent.ACTION_POINTER_DOWN) { // New pointer goes down, this can only happen after ACTION_DOWN is sent for the first pointer eventDispatcher.dispatchEvent( @@ -126,7 +131,8 @@ public class JSTouchDispatcher { TouchEventType.START, ev, mTargetCoordinates[0], - mTargetCoordinates[1])); + mTargetCoordinates[1], + mTouchEventCoalescingKeyHelper)); } else if (action == MotionEvent.ACTION_POINTER_UP) { // Exactly onw of the pointers goes up eventDispatcher.dispatchEvent( @@ -136,9 +142,10 @@ public class JSTouchDispatcher { TouchEventType.END, ev, mTargetCoordinates[0], - mTargetCoordinates[1])); + mTargetCoordinates[1], + mTouchEventCoalescingKeyHelper)); } else if (action == MotionEvent.ACTION_CANCEL) { - if (TouchEventCoalescingKeyHelper.hasCoalescingKey(ev.getDownTime())) { + if (mTouchEventCoalescingKeyHelper.hasCoalescingKey(ev.getDownTime())) { dispatchCancelEvent(ev, eventDispatcher); } else { FLog.e( @@ -176,6 +183,7 @@ public class JSTouchDispatcher { TouchEventType.CANCEL, androidEvent, mTargetCoordinates[0], - mTargetCoordinates[1])); + mTargetCoordinates[1], + mTouchEventCoalescingKeyHelper)); } } diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/events/TouchEvent.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/events/TouchEvent.java index 1600b7478..a7df8fb3e 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/events/TouchEvent.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/events/TouchEvent.java @@ -37,12 +37,20 @@ public class TouchEvent extends Event { TouchEventType touchEventType, MotionEvent motionEventToCopy, float viewX, - float viewY) { + float viewY, + TouchEventCoalescingKeyHelper touchEventCoalescingKeyHelper) { TouchEvent event = EVENTS_POOL.acquire(); if (event == null) { event = new TouchEvent(); } - event.init(viewTag, timestampMs, touchEventType, motionEventToCopy, viewX, viewY); + event.init( + viewTag, + timestampMs, + touchEventType, + motionEventToCopy, + viewX, + viewY, + touchEventCoalescingKeyHelper); return event; } @@ -63,28 +71,29 @@ public class TouchEvent extends Event { TouchEventType touchEventType, MotionEvent motionEventToCopy, float viewX, - float viewY) { + float viewY, + TouchEventCoalescingKeyHelper touchEventCoalescingKeyHelper) { super.init(viewTag, timestampMs); short coalescingKey = 0; int action = (motionEventToCopy.getAction() & MotionEvent.ACTION_MASK); switch (action) { case MotionEvent.ACTION_DOWN: - TouchEventCoalescingKeyHelper.addCoalescingKey(motionEventToCopy.getDownTime()); + touchEventCoalescingKeyHelper.addCoalescingKey(motionEventToCopy.getDownTime()); break; case MotionEvent.ACTION_UP: - TouchEventCoalescingKeyHelper.removeCoalescingKey(motionEventToCopy.getDownTime()); + touchEventCoalescingKeyHelper.removeCoalescingKey(motionEventToCopy.getDownTime()); break; case MotionEvent.ACTION_POINTER_DOWN: case MotionEvent.ACTION_POINTER_UP: - TouchEventCoalescingKeyHelper.incrementCoalescingKey(motionEventToCopy.getDownTime()); + touchEventCoalescingKeyHelper.incrementCoalescingKey(motionEventToCopy.getDownTime()); break; case MotionEvent.ACTION_MOVE: coalescingKey = - TouchEventCoalescingKeyHelper.getCoalescingKey(motionEventToCopy.getDownTime()); + touchEventCoalescingKeyHelper.getCoalescingKey(motionEventToCopy.getDownTime()); break; case MotionEvent.ACTION_CANCEL: - TouchEventCoalescingKeyHelper.removeCoalescingKey(motionEventToCopy.getDownTime()); + touchEventCoalescingKeyHelper.removeCoalescingKey(motionEventToCopy.getDownTime()); break; default: throw new RuntimeException("Unhandled MotionEvent action: " + action); diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/events/TouchEventCoalescingKeyHelper.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/events/TouchEventCoalescingKeyHelper.java index acc2d3afa..3003dedb4 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/events/TouchEventCoalescingKeyHelper.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/events/TouchEventCoalescingKeyHelper.java @@ -46,31 +46,31 @@ import android.util.SparseIntArray; */ public class TouchEventCoalescingKeyHelper { - private static final SparseIntArray sDownTimeToCoalescingKey = new SparseIntArray(); + private final SparseIntArray mDownTimeToCoalescingKey = new SparseIntArray(); /** * Starts tracking a new coalescing key corresponding to the gesture with this down time. */ - public static void addCoalescingKey(long downTime) { - sDownTimeToCoalescingKey.put((int) downTime, 0); + public void addCoalescingKey(long downTime) { + mDownTimeToCoalescingKey.put((int) downTime, 0); } /** * Increments the coalescing key corresponding to the gesture with this down time. */ - public static void incrementCoalescingKey(long downTime) { - int currentValue = sDownTimeToCoalescingKey.get((int) downTime, -1); + public void incrementCoalescingKey(long downTime) { + int currentValue = mDownTimeToCoalescingKey.get((int) downTime, -1); if (currentValue == -1) { throw new RuntimeException("Tried to increment non-existent cookie"); } - sDownTimeToCoalescingKey.put((int) downTime, currentValue + 1); + mDownTimeToCoalescingKey.put((int) downTime, currentValue + 1); } /** * Gets the coalescing key corresponding to the gesture with this down time. */ - public static short getCoalescingKey(long downTime) { - int currentValue = sDownTimeToCoalescingKey.get((int) downTime, -1); + public short getCoalescingKey(long downTime) { + int currentValue = mDownTimeToCoalescingKey.get((int) downTime, -1); if (currentValue == -1) { throw new RuntimeException("Tried to get non-existent cookie"); } @@ -80,12 +80,12 @@ public class TouchEventCoalescingKeyHelper { /** * Stops tracking a new coalescing key corresponding to the gesture with this down time. */ - public static void removeCoalescingKey(long downTime) { - sDownTimeToCoalescingKey.delete((int) downTime); + public void removeCoalescingKey(long downTime) { + mDownTimeToCoalescingKey.delete((int) downTime); } - public static boolean hasCoalescingKey(long downTime) { - int currentValue = sDownTimeToCoalescingKey.get((int) downTime, -1); + public boolean hasCoalescingKey(long downTime) { + int currentValue = mDownTimeToCoalescingKey.get((int) downTime, -1); if (currentValue == -1) { return false; }