Fix crash when move on the edge of some phones like HUAWEI P9

Summary:
The app crashes because of `TouchEventCoalescingKeyHelper.getCoalescingKey` throwing an exception when move on the edge of some phones like HUAWEI P9. It's caused by that the down time differs from `ACTION_DOWN` to `ACTION_MOVE` which belongs to the same gesture when I touched on the edge of my HUAWEI P9. It seems a native bug of manufacturer. Related issue #11302.
```
java.lang.RuntimeException: Tried to get non-existent cookie
    at com.facebook.react.uimanager.events.TouchEventCoalescingKeyHelper.getCoalescingKey(TouchEventCoalescingKeyHelper.java:75)
    at com.facebook.react.uimanager.events.TouchEvent.init(TouchEvent.java:93)
    at com.facebook.react.uimanager.events.TouchEvent.obtain(TouchEvent.java:46)
    at com.facebook.react.uimanager.JSTouchDispatcher.handleTouchEvent(JSTouchDispatcher.java:118)
    at com.facebook.react.ReactRootView.dispatchJSTouchEvent(ReactRootView.java:158)
    at com.facebook.react.ReactRootView.onInterceptTouchEvent(ReactRootView.java:130)
    at android.view.Vie
Closes https://github.com/facebook/react-native/pull/12063

Differential Revision: D4779060

Pulled By: astreet

fbshipit-source-id: 5cf20084ff9081f2535ff9cb3b99d1d52c443f03
This commit is contained in:
wenzhe.lv 2017-03-27 07:00:58 -07:00 committed by Facebook Github Bot
parent 3b2864404e
commit d2939eafbf
2 changed files with 23 additions and 5 deletions

View File

@ -30,6 +30,7 @@ public class JSTouchDispatcher {
private int mTargetTag = -1;
private final float[] mTargetCoordinates = new float[2];
private boolean mChildIsHandlingNativeGesture = false;
private long mGestureStartTime = TouchEvent.UNSET;
private final ViewGroup mRootViewGroup;
private final TouchEventCoalescingKeyHelper mTouchEventCoalescingKeyHelper =
new TouchEventCoalescingKeyHelper();
@ -72,6 +73,7 @@ public class JSTouchDispatcher {
// {@link #findTargetTagForTouch} to find react view ID that will be responsible for handling
// this gesture
mChildIsHandlingNativeGesture = false;
mGestureStartTime = ev.getEventTime();
mTargetTag = TouchTargetHelper.findTargetTagAndCoordinatesForTouch(
ev.getX(),
ev.getY(),
@ -83,6 +85,7 @@ public class JSTouchDispatcher {
mTargetTag,
TouchEventType.START,
ev,
mGestureStartTime,
mTargetCoordinates[0],
mTargetCoordinates[1],
mTouchEventCoalescingKeyHelper));
@ -105,10 +108,12 @@ public class JSTouchDispatcher {
mTargetTag,
TouchEventType.END,
ev,
mGestureStartTime,
mTargetCoordinates[0],
mTargetCoordinates[1],
mTouchEventCoalescingKeyHelper));
mTargetTag = -1;
mGestureStartTime = TouchEvent.UNSET;
} else if (action == MotionEvent.ACTION_MOVE) {
// Update pointer position for current gesture
eventDispatcher.dispatchEvent(
@ -116,6 +121,7 @@ public class JSTouchDispatcher {
mTargetTag,
TouchEventType.MOVE,
ev,
mGestureStartTime,
mTargetCoordinates[0],
mTargetCoordinates[1],
mTouchEventCoalescingKeyHelper));
@ -126,6 +132,7 @@ public class JSTouchDispatcher {
mTargetTag,
TouchEventType.START,
ev,
mGestureStartTime,
mTargetCoordinates[0],
mTargetCoordinates[1],
mTouchEventCoalescingKeyHelper));
@ -136,6 +143,7 @@ public class JSTouchDispatcher {
mTargetTag,
TouchEventType.END,
ev,
mGestureStartTime,
mTargetCoordinates[0],
mTargetCoordinates[1],
mTouchEventCoalescingKeyHelper));
@ -149,6 +157,7 @@ public class JSTouchDispatcher {
);
}
mTargetTag = -1;
mGestureStartTime = TouchEvent.UNSET;
} else {
FLog.w(
ReactConstants.TAG,
@ -176,6 +185,7 @@ public class JSTouchDispatcher {
mTargetTag,
TouchEventType.CANCEL,
androidEvent,
mGestureStartTime,
mTargetCoordinates[0],
mTargetCoordinates[1],
mTouchEventCoalescingKeyHelper));

View File

@ -15,6 +15,7 @@ import android.support.v4.util.Pools;
import android.view.MotionEvent;
import com.facebook.infer.annotation.Assertions;
import com.facebook.react.bridge.SoftAssertions;
/**
* An event representing the start, end or movement of a touch. Corresponds to a single
@ -31,10 +32,13 @@ public class TouchEvent extends Event<TouchEvent> {
private static final Pools.SynchronizedPool<TouchEvent> EVENTS_POOL =
new Pools.SynchronizedPool<>(TOUCH_EVENTS_POOL_SIZE);
public static final long UNSET = Long.MIN_VALUE;
public static TouchEvent obtain(
int viewTag,
TouchEventType touchEventType,
MotionEvent motionEventToCopy,
long gestureStartTime,
float viewX,
float viewY,
TouchEventCoalescingKeyHelper touchEventCoalescingKeyHelper) {
@ -46,6 +50,7 @@ public class TouchEvent extends Event<TouchEvent> {
viewTag,
touchEventType,
motionEventToCopy,
gestureStartTime,
viewX,
viewY,
touchEventCoalescingKeyHelper);
@ -67,30 +72,33 @@ public class TouchEvent extends Event<TouchEvent> {
int viewTag,
TouchEventType touchEventType,
MotionEvent motionEventToCopy,
long gestureStartTime,
float viewX,
float viewY,
TouchEventCoalescingKeyHelper touchEventCoalescingKeyHelper) {
super.init(viewTag);
SoftAssertions.assertCondition(gestureStartTime != UNSET,
"Gesture start time must be initialized");
short coalescingKey = 0;
int action = (motionEventToCopy.getAction() & MotionEvent.ACTION_MASK);
switch (action) {
case MotionEvent.ACTION_DOWN:
touchEventCoalescingKeyHelper.addCoalescingKey(motionEventToCopy.getDownTime());
touchEventCoalescingKeyHelper.addCoalescingKey(gestureStartTime);
break;
case MotionEvent.ACTION_UP:
touchEventCoalescingKeyHelper.removeCoalescingKey(motionEventToCopy.getDownTime());
touchEventCoalescingKeyHelper.removeCoalescingKey(gestureStartTime);
break;
case MotionEvent.ACTION_POINTER_DOWN:
case MotionEvent.ACTION_POINTER_UP:
touchEventCoalescingKeyHelper.incrementCoalescingKey(motionEventToCopy.getDownTime());
touchEventCoalescingKeyHelper.incrementCoalescingKey(gestureStartTime);
break;
case MotionEvent.ACTION_MOVE:
coalescingKey =
touchEventCoalescingKeyHelper.getCoalescingKey(motionEventToCopy.getDownTime());
touchEventCoalescingKeyHelper.getCoalescingKey(gestureStartTime);
break;
case MotionEvent.ACTION_CANCEL:
touchEventCoalescingKeyHelper.removeCoalescingKey(motionEventToCopy.getDownTime());
touchEventCoalescingKeyHelper.removeCoalescingKey(gestureStartTime);
break;
default:
throw new RuntimeException("Unhandled MotionEvent action: " + action);