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 65b6c5bbaf..2d21275824 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/JSPointerDispatcher.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/JSPointerDispatcher.java @@ -31,21 +31,23 @@ import java.util.List; * and also dispatch the appropriate event to JS */ public class JSPointerDispatcher { - - private final float[] mTargetCoordinates = new float[2]; - private int mChildHandlingNativeGesture = -1; - private long mDownStartTime = TouchEvent.UNSET; - private final ViewGroup mRootViewGroup; - private final TouchEventCoalescingKeyHelper mTouchEventCoalescingKeyHelper = - new TouchEventCoalescingKeyHelper(); - + private static final int UNSET_POINTER_ID = -1; private static final float ONMOVE_EPSILON = 0.1f; private static final String TAG = "POINTER EVENTS"; - // Set globally for hover interactions, referenced for coalescing hover events - private long mHoverInteractionKey = TouchEvent.UNSET; + private final TouchEventCoalescingKeyHelper mTouchEventCoalescingKeyHelper = + new TouchEventCoalescingKeyHelper(); private List mLastHitPath = Collections.emptyList(); private final float[] mLastEventCoordinates = new float[2]; + private final float[] mTargetCoordinates = new float[2]; + + private int mChildHandlingNativeGesture = -1; + private int mPrimaryPointerId = UNSET_POINTER_ID; + private long mDownStartTime = TouchEvent.UNSET; + private long mHoverInteractionKey = TouchEvent.UNSET; + private final ViewGroup mRootViewGroup; + + // Set globally for hover interactions, referenced for coalescing hover events public JSPointerDispatcher(ViewGroup viewGroup) { mRootViewGroup = viewGroup; @@ -110,6 +112,7 @@ public class JSPointerDispatcher { // Reset mChildHandlingNativeGesture like JSTouchDispatcher does mChildHandlingNativeGesture = -1; + mPrimaryPointerId = motionEvent.getPointerId(actionIndex); // Start a "down" coalescing key mDownStartTime = motionEvent.getEventTime(); @@ -138,7 +141,8 @@ public class JSPointerDispatcher { surfaceId, activeTargetTag, motionEvent, - mTargetCoordinates)); + mTargetCoordinates, + mPrimaryPointerId)); } return; @@ -163,7 +167,8 @@ public class JSPointerDispatcher { surfaceId, activeTargetTag, motionEvent, - mTargetCoordinates)); + mTargetCoordinates, + mPrimaryPointerId)); } return; @@ -182,7 +187,8 @@ public class JSPointerDispatcher { activeTargetTag, motionEvent, mTargetCoordinates, - coalescingKey)); + coalescingKey, + mPrimaryPointerId)); } return; @@ -201,7 +207,8 @@ public class JSPointerDispatcher { surfaceId, activeTargetTag, motionEvent, - mTargetCoordinates)); + mTargetCoordinates, + mPrimaryPointerId)); } return; @@ -223,7 +230,8 @@ public class JSPointerDispatcher { surfaceId, activeTargetTag, motionEvent, - mTargetCoordinates)); + mTargetCoordinates, + mPrimaryPointerId)); } if (!supportsHover) { @@ -238,6 +246,8 @@ public class JSPointerDispatcher { surfaceId, motionEvent); } + + mPrimaryPointerId = UNSET_POINTER_ID; return; } @@ -312,7 +322,8 @@ public class JSPointerDispatcher { for (ViewTarget viewTarget : viewTargets) { int viewId = viewTarget.getViewId(); dispatcher.dispatchEvent( - PointerEvent.obtain(eventName, surfaceId, viewId, motionEvent, mTargetCoordinates)); + PointerEvent.obtain( + eventName, surfaceId, viewId, motionEvent, mTargetCoordinates, mPrimaryPointerId)); } } @@ -445,7 +456,8 @@ public class JSPointerDispatcher { targetTag, motionEvent, mTargetCoordinates, - coalescingKey)); + coalescingKey, + mPrimaryPointerId)); } mLastHitPath = hitPath; @@ -476,7 +488,8 @@ public class JSPointerDispatcher { surfaceId, targetTag, motionEvent, - mTargetCoordinates)); + mTargetCoordinates, + mPrimaryPointerId)); } List leaveViewTargets = @@ -492,6 +505,7 @@ public class JSPointerDispatcher { mTouchEventCoalescingKeyHelper.removeCoalescingKey(mDownStartTime); mDownStartTime = TouchEvent.UNSET; + mPrimaryPointerId = UNSET_POINTER_ID; } } diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/events/PointerEvent.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/events/PointerEvent.java index e5ca07139b..21611af0ae 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/events/PointerEvent.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/events/PointerEvent.java @@ -31,7 +31,8 @@ public class PointerEvent extends Event { int surfaceId, int viewTag, MotionEvent motionEventToCopy, - float[] offsetCoords) { + float[] offsetCoords, + int primaryPointerId) { PointerEvent event = EVENTS_POOL.acquire(); if (event == null) { event = new PointerEvent(); @@ -42,7 +43,8 @@ public class PointerEvent extends Event { viewTag, Assertions.assertNotNull(motionEventToCopy), offsetCoords, - 0); + 0, + primaryPointerId); return event; } @@ -52,7 +54,8 @@ public class PointerEvent extends Event { int viewTag, MotionEvent motionEventToCopy, float[] offsetCoords, - int coalescingKey) { + int coalescingKey, + int primaryPointerId) { PointerEvent event = EVENTS_POOL.acquire(); if (event == null) { event = new PointerEvent(); @@ -63,7 +66,8 @@ public class PointerEvent extends Event { viewTag, Assertions.assertNotNull(motionEventToCopy), offsetCoords, - coalescingKey); + coalescingKey, + primaryPointerId); return event; } @@ -73,6 +77,7 @@ public class PointerEvent extends Event { private float mOffsetX; private float mOffsetY; private @Nullable List mPointersEventData; + private int mPrimaryPointerId; private void init( String eventName, @@ -80,7 +85,8 @@ public class PointerEvent extends Event { int viewTag, MotionEvent motionEventToCopy, float[] offsetCoords, - int coalescingKey) { + int coalescingKey, + int primaryPointerId) { super.init(surfaceId, viewTag, motionEventToCopy.getEventTime()); mEventName = eventName; @@ -88,6 +94,7 @@ public class PointerEvent extends Event { mCoalescingKey = coalescingKey; mOffsetX = offsetCoords[0]; mOffsetY = offsetCoords[1]; + mPrimaryPointerId = primaryPointerId; } private PointerEvent() {} @@ -160,16 +167,32 @@ public class PointerEvent extends Event { private WritableMap createPointerEventData(int index) { WritableMap pointerEvent = Arguments.createMap(); + int pointerId = mMotionEvent.getPointerId(index); - pointerEvent.putDouble("pointerId", mMotionEvent.getPointerId(index)); + // https://www.w3.org/TR/pointerevents/#pointerevent-interface + pointerEvent.putDouble("pointerId", pointerId); pointerEvent.putDouble("pressure", mMotionEvent.getPressure(index)); pointerEvent.putString( "pointerType", PointerEventHelper.getW3CPointerType(mMotionEvent.getToolType(index))); + pointerEvent.putBoolean( + "isPrimary", PointerEventHelper.isPrimary(pointerId, mPrimaryPointerId, mMotionEvent)); + + // https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent // Client refers to upper left edge of the content area (viewport) // We define the viewport to be ReactRootView - pointerEvent.putDouble("clientX", mMotionEvent.getX(index)); - pointerEvent.putDouble("clientY", mMotionEvent.getY(index)); + double clientX = mMotionEvent.getX(index); + double clientY = mMotionEvent.getX(index); + pointerEvent.putDouble("clientX", clientX); + pointerEvent.putDouble("clientY", clientY); + + // x,y values are aliases of clientX, clientY + pointerEvent.putDouble("x", clientX); + pointerEvent.putDouble("y", clientY); + + // page values in react-native are equivalent to client values since rootview is not scrollable + pointerEvent.putDouble("pageX", clientX); + pointerEvent.putDouble("pageY", clientY); // Offset refers to upper left edge of the target view pointerEvent.putDouble("offsetX", PixelUtil.toDIPFromPixel(mOffsetX)); @@ -177,6 +200,7 @@ public class PointerEvent extends Event { pointerEvent.putInt("target", this.getViewTag()); pointerEvent.putDouble("timestamp", this.getTimestampMs()); + return pointerEvent; } diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/events/PointerEventHelper.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/events/PointerEventHelper.java index d8134bd1e3..1b576137e6 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/events/PointerEventHelper.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/events/PointerEventHelper.java @@ -66,6 +66,14 @@ public class PointerEventHelper { } } + public static boolean isPrimary(int pointerId, int primaryPointerId, MotionEvent event) { + if (supportsHover(event)) { + return true; + } + + return pointerId == primaryPointerId; + } + public static String getW3CPointerType(final int toolType) { // https://www.w3.org/TR/pointerevents3/#dom-pointerevent-pointertype switch (toolType) {