Convert TouchEventDispatchTest to Kotlin (#37725)

Summary:
Converts TouchEventDispatchTest from Java to Kotlin, as per issue https://github.com/facebook/react-native/issues/37708

## Changelog:

[Internal] [Changed] - Convert TouchEventDispatchTest to Kotlin

Pull Request resolved: https://github.com/facebook/react-native/pull/37725

Test Plan:
Tests pass: `./gradlew :packages:react-native:ReactAndroid:test`
Formatted with [KtFmt](https://facebook.github.io/ktfmt/)

Reviewed By: cortinico

Differential Revision: D46486161

Pulled By: mdvacca

fbshipit-source-id: ab7872347b42871416a3d8f23b001c564ff8c18a
This commit is contained in:
M0Coding
2023-06-08 01:10:44 -07:00
committed by Facebook GitHub Bot
parent e5dfe9964f
commit 29ee917a0e
2 changed files with 600 additions and 612 deletions
@@ -1,612 +0,0 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
package com.facebook.react.fabric.events;
import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.*;
import static org.mockito.Mockito.times;
import android.util.DisplayMetrics;
import android.view.MotionEvent;
import android.view.MotionEvent.PointerCoords;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.JavaOnlyArray;
import com.facebook.react.bridge.JavaOnlyMap;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.fabric.FabricUIManager;
import com.facebook.react.uimanager.DisplayMetricsHolder;
import com.facebook.react.uimanager.events.TouchEvent;
import com.facebook.react.uimanager.events.TouchEventCoalescingKeyHelper;
import com.facebook.react.uimanager.events.TouchEventType;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mockito;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PowerMockIgnore;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.core.classloader.annotations.SuppressStaticInitializationFor;
import org.powermock.modules.junit4.rule.PowerMockRule;
import org.robolectric.RobolectricTestRunner;
@PrepareForTest({Arguments.class, FabricUIManager.class})
@SuppressStaticInitializationFor("com.facebook.react.fabric.FabricUIManager")
@RunWith(RobolectricTestRunner.class)
@PowerMockIgnore({"org.mockito.*", "org.robolectric.*", "androidx.*", "android.*"})
public class TouchEventDispatchTest {
private static final int SURFACE_ID = 121;
private static final int TARGET_VIEW_ID = 42;
private static final int GESTURE_START_TIME = 1;
@Rule public PowerMockRule rule = new PowerMockRule();
private final TouchEventCoalescingKeyHelper mTouchEventCoalescingKeyHelper =
new TouchEventCoalescingKeyHelper();
/** Events (1 pointer): START -> MOVE -> MOVE -> UP */
private final TouchEvent[] mStartMoveEndSequence =
new TouchEvent[] {
createTouchEvent(
GESTURE_START_TIME,
MotionEvent.ACTION_DOWN,
0,
new int[] {0},
new PointerCoords[] {pointerCoords(1f, 1f)}),
createTouchEvent(
GESTURE_START_TIME,
MotionEvent.ACTION_MOVE,
0,
new int[] {0},
new PointerCoords[] {pointerCoords(1f, 2f)}),
createTouchEvent(
GESTURE_START_TIME,
MotionEvent.ACTION_MOVE,
0,
new int[] {0},
new PointerCoords[] {pointerCoords(1f, 3f)}),
createTouchEvent(
GESTURE_START_TIME,
MotionEvent.ACTION_UP,
0,
new int[] {0},
new PointerCoords[] {pointerCoords(1f, 3f)})
};
/** Expected values for {@link #mStartMoveEndSequence} */
private final List<ReadableMap> mStartMoveEndExpectedSequence =
listOf(
/*
* START event for touch 1:
* {
* touches: [touch1],
* changed: [touch1]
* }
*/
buildGestureEvent(
SURFACE_ID,
TARGET_VIEW_ID,
1f,
1f,
GESTURE_START_TIME,
0,
listOf(buildGesture(SURFACE_ID, TARGET_VIEW_ID, 1f, 1f, GESTURE_START_TIME, 0)),
listOf(buildGesture(SURFACE_ID, TARGET_VIEW_ID, 1f, 1f, GESTURE_START_TIME, 0))),
/*
* MOVE event for touch 1:
* {
* touches: [touch1],
* changed: [touch1]
* }
*/
buildGestureEvent(
SURFACE_ID,
TARGET_VIEW_ID,
1f,
2f,
GESTURE_START_TIME,
0,
listOf(buildGesture(SURFACE_ID, TARGET_VIEW_ID, 1f, 2f, GESTURE_START_TIME, 0)),
listOf(buildGesture(SURFACE_ID, TARGET_VIEW_ID, 1f, 2f, GESTURE_START_TIME, 0))),
/*
* MOVE event for touch 1:
* {
* touches: [touch1],
* changed: [touch1]
* }
*/
buildGestureEvent(
SURFACE_ID,
TARGET_VIEW_ID,
1f,
3f,
GESTURE_START_TIME,
0,
listOf(buildGesture(SURFACE_ID, TARGET_VIEW_ID, 1f, 3f, GESTURE_START_TIME, 0)),
listOf(buildGesture(SURFACE_ID, TARGET_VIEW_ID, 1f, 3f, GESTURE_START_TIME, 0))),
/*
* END event for touch 1:
* {
* touches: [],
* changed: [touch1]
* }
*/
buildGestureEvent(
SURFACE_ID,
TARGET_VIEW_ID,
1f,
3f,
GESTURE_START_TIME,
0,
Collections.<WritableMap>emptyList(),
listOf(buildGesture(SURFACE_ID, TARGET_VIEW_ID, 1f, 3f, GESTURE_START_TIME, 0))));
/** Events (2 pointer): START 1st -> START 2nd -> MOVE 1st -> UP 2st -> UP 1st */
private final TouchEvent[] mStartPointerMoveUpSequence =
new TouchEvent[] {
createTouchEvent(
GESTURE_START_TIME,
MotionEvent.ACTION_DOWN,
0,
new int[] {0},
new PointerCoords[] {pointerCoords(1f, 1f)}),
createTouchEvent(
GESTURE_START_TIME,
MotionEvent.ACTION_POINTER_DOWN,
1,
new int[] {0, 1},
new PointerCoords[] {pointerCoords(1f, 1f), pointerCoords(2f, 1f)}),
createTouchEvent(
GESTURE_START_TIME,
MotionEvent.ACTION_MOVE,
0,
new int[] {0, 1},
new PointerCoords[] {pointerCoords(1f, 2f), pointerCoords(2f, 1f)}),
createTouchEvent(
GESTURE_START_TIME,
MotionEvent.ACTION_POINTER_UP,
1,
new int[] {0, 1},
new PointerCoords[] {pointerCoords(1f, 2f), pointerCoords(2f, 1f)}),
createTouchEvent(
GESTURE_START_TIME,
MotionEvent.ACTION_POINTER_UP,
0,
new int[] {0},
new PointerCoords[] {pointerCoords(1f, 2f)})
};
/** Expected values for {@link #mStartPointerMoveUpSequence} */
private final List<ReadableMap> mStartPointerMoveUpExpectedSequence =
listOf(
/*
* START event for touch 1:
* {
* touch: 0,
* touches: [touch1],
* changed: [touch1]
* }
*/
buildGestureEvent(
SURFACE_ID,
TARGET_VIEW_ID,
1f,
1f,
GESTURE_START_TIME,
0,
listOf(buildGesture(SURFACE_ID, TARGET_VIEW_ID, 1f, 1f, GESTURE_START_TIME, 0)),
listOf(buildGesture(SURFACE_ID, TARGET_VIEW_ID, 1f, 1f, GESTURE_START_TIME, 0))),
/*
* START event for touch 2:
* {
* touch: 1,
* touches: [touch0, touch1],
* changed: [touch1]
* }
*/
buildGestureEvent(
SURFACE_ID,
TARGET_VIEW_ID,
2f,
1f,
GESTURE_START_TIME,
1,
listOf(
buildGesture(SURFACE_ID, TARGET_VIEW_ID, 1f, 1f, GESTURE_START_TIME, 0),
buildGesture(SURFACE_ID, TARGET_VIEW_ID, 2f, 1f, GESTURE_START_TIME, 1)),
listOf(buildGesture(SURFACE_ID, TARGET_VIEW_ID, 2f, 1f, GESTURE_START_TIME, 1))),
/*
* MOVE event for touch 1:
* {
* touch: 0,
* touches: [touch0, touch1],
* changed: [touch0, touch1]
* }
* {
* touch: 1,
* touches: [touch0, touch1],
* changed: [touch0, touch1]
* }
*/
buildGestureEvent(
SURFACE_ID,
TARGET_VIEW_ID,
1f,
2f,
GESTURE_START_TIME,
0,
listOf(
buildGesture(SURFACE_ID, TARGET_VIEW_ID, 1f, 2f, GESTURE_START_TIME, 0),
buildGesture(SURFACE_ID, TARGET_VIEW_ID, 2f, 1f, GESTURE_START_TIME, 1)),
listOf(
buildGesture(SURFACE_ID, TARGET_VIEW_ID, 1f, 2f, GESTURE_START_TIME, 0),
buildGesture(SURFACE_ID, TARGET_VIEW_ID, 2f, 1f, GESTURE_START_TIME, 1))),
buildGestureEvent(
SURFACE_ID,
TARGET_VIEW_ID,
2f,
1f,
GESTURE_START_TIME,
1,
listOf(
buildGesture(SURFACE_ID, TARGET_VIEW_ID, 1f, 2f, GESTURE_START_TIME, 0),
buildGesture(SURFACE_ID, TARGET_VIEW_ID, 2f, 1f, GESTURE_START_TIME, 1)),
listOf(
buildGesture(SURFACE_ID, TARGET_VIEW_ID, 1f, 2f, GESTURE_START_TIME, 0),
buildGesture(SURFACE_ID, TARGET_VIEW_ID, 2f, 1f, GESTURE_START_TIME, 1))),
/*
* UP event pointer 1:
* {
* touch: 1,
* touches: [touch0],
* changed: [touch1]
* }
*/
buildGestureEvent(
SURFACE_ID,
TARGET_VIEW_ID,
2f,
1f,
GESTURE_START_TIME,
1,
listOf(buildGesture(SURFACE_ID, TARGET_VIEW_ID, 1f, 2f, GESTURE_START_TIME, 0)),
listOf(buildGesture(SURFACE_ID, TARGET_VIEW_ID, 2f, 1f, GESTURE_START_TIME, 1))),
/*
* UP event pointer 0:
* {
* touch: 0,
* touches: [],
* changed: [touch0]
* }
*/
buildGestureEvent(
SURFACE_ID,
TARGET_VIEW_ID,
1f,
2f,
GESTURE_START_TIME,
0,
Collections.<WritableMap>emptyList(),
listOf(buildGesture(SURFACE_ID, TARGET_VIEW_ID, 1f, 2f, GESTURE_START_TIME, 0))));
/** Events (2 pointer): START 1st -> START 2nd -> MOVE 1st -> CANCEL */
private final TouchEvent[] mStartMoveCancelSequence =
new TouchEvent[] {
createTouchEvent(
GESTURE_START_TIME,
MotionEvent.ACTION_DOWN,
0,
new int[] {0},
new PointerCoords[] {pointerCoords(1f, 1f)}),
createTouchEvent(
GESTURE_START_TIME,
MotionEvent.ACTION_POINTER_DOWN,
1,
new int[] {0, 1},
new PointerCoords[] {pointerCoords(1f, 1f), pointerCoords(2f, 1f)}),
createTouchEvent(
GESTURE_START_TIME,
MotionEvent.ACTION_MOVE,
0,
new int[] {0, 1},
new PointerCoords[] {pointerCoords(1f, 2f), pointerCoords(2f, 1f)}),
createTouchEvent(
GESTURE_START_TIME,
MotionEvent.ACTION_CANCEL,
0,
new int[] {0, 1},
new PointerCoords[] {pointerCoords(1f, 3f), pointerCoords(2f, 1f)})
};
/** Expected values for {@link #mStartMoveCancelSequence} */
private final List<ReadableMap> mStartMoveCancelExpectedSequence =
listOf(
/*
* START event for touch 1:
* {
* touch: 0,
* touches: [touch1],
* changed: [touch1]
* }
*/
buildGestureEvent(
SURFACE_ID,
TARGET_VIEW_ID,
1f,
1f,
GESTURE_START_TIME,
0,
listOf(buildGesture(SURFACE_ID, TARGET_VIEW_ID, 1f, 1f, GESTURE_START_TIME, 0)),
listOf(buildGesture(SURFACE_ID, TARGET_VIEW_ID, 1f, 1f, GESTURE_START_TIME, 0))),
/*
* START event for touch 2:
* {
* touch: 1,
* touches: [touch0, touch1],
* changed: [touch1]
* }
*/
buildGestureEvent(
SURFACE_ID,
TARGET_VIEW_ID,
2f,
1f,
GESTURE_START_TIME,
1,
listOf(
buildGesture(SURFACE_ID, TARGET_VIEW_ID, 1f, 1f, GESTURE_START_TIME, 0),
buildGesture(SURFACE_ID, TARGET_VIEW_ID, 2f, 1f, GESTURE_START_TIME, 1)),
listOf(buildGesture(SURFACE_ID, TARGET_VIEW_ID, 2f, 1f, GESTURE_START_TIME, 1))),
/*
* MOVE event for touch 1:
* {
* touch: 0,
* touches: [touch0, touch1],
* changed: [touch0, touch1]
* }
* {
* touch: 1,
* touches: [touch0, touch1],
* changed: [touch0, touch1]
* }
*/
buildGestureEvent(
SURFACE_ID,
TARGET_VIEW_ID,
1f,
2f,
GESTURE_START_TIME,
0,
listOf(
buildGesture(SURFACE_ID, TARGET_VIEW_ID, 1f, 2f, GESTURE_START_TIME, 0),
buildGesture(SURFACE_ID, TARGET_VIEW_ID, 2f, 1f, GESTURE_START_TIME, 1)),
listOf(
buildGesture(SURFACE_ID, TARGET_VIEW_ID, 1f, 2f, GESTURE_START_TIME, 0),
buildGesture(SURFACE_ID, TARGET_VIEW_ID, 2f, 1f, GESTURE_START_TIME, 1))),
buildGestureEvent(
SURFACE_ID,
TARGET_VIEW_ID,
2f,
1f,
GESTURE_START_TIME,
1,
listOf(
buildGesture(SURFACE_ID, TARGET_VIEW_ID, 1f, 2f, GESTURE_START_TIME, 0),
buildGesture(SURFACE_ID, TARGET_VIEW_ID, 2f, 1f, GESTURE_START_TIME, 1)),
listOf(
buildGesture(SURFACE_ID, TARGET_VIEW_ID, 1f, 2f, GESTURE_START_TIME, 0),
buildGesture(SURFACE_ID, TARGET_VIEW_ID, 2f, 1f, GESTURE_START_TIME, 1))),
/*
* CANCEL event:
* {
* touch: 0,
* touches: [],
* changed: [touch0, touch1]
* }
* {
* touch: 1,
* touches: [],
* changed: [touch0, touch1]
* }
*/
buildGestureEvent(
SURFACE_ID,
TARGET_VIEW_ID,
1f,
3f,
GESTURE_START_TIME,
0,
Collections.<WritableMap>emptyList(),
listOf(
buildGesture(SURFACE_ID, TARGET_VIEW_ID, 1f, 3f, GESTURE_START_TIME, 0),
buildGesture(SURFACE_ID, TARGET_VIEW_ID, 2f, 1f, GESTURE_START_TIME, 1))),
buildGestureEvent(
SURFACE_ID,
TARGET_VIEW_ID,
2f,
1f,
GESTURE_START_TIME,
1,
Collections.<WritableMap>emptyList(),
listOf(
buildGesture(SURFACE_ID, TARGET_VIEW_ID, 1f, 3f, GESTURE_START_TIME, 0),
buildGesture(SURFACE_ID, TARGET_VIEW_ID, 2f, 1f, GESTURE_START_TIME, 1))));
List<ReadableMap> mDispatchedEvents;
FabricEventEmitter mEventEmitter;
FabricUIManager mUIManager;
@Before
public void setUp() {
PowerMockito.mockStatic(Arguments.class);
PowerMockito.mockStatic(FabricUIManager.class);
PowerMockito.when(Arguments.createArray())
.thenAnswer(
new Answer<Object>() {
@Override
public Object answer(InvocationOnMock invocation) {
return new JavaOnlyArray();
}
});
PowerMockito.when(Arguments.createMap())
.thenAnswer(
new Answer<Object>() {
@Override
public Object answer(InvocationOnMock invocation) {
return new JavaOnlyMap();
}
});
DisplayMetrics metrics = new DisplayMetrics();
metrics.xdpi = 1f;
metrics.ydpi = 1f;
metrics.density = 1f;
DisplayMetricsHolder.setWindowDisplayMetrics(metrics);
mUIManager = Mockito.mock(FabricUIManager.class);
mEventEmitter = new FabricEventEmitter(mUIManager);
}
@Test
public void testFabric_startMoveEnd() {
for (TouchEvent event : mStartMoveEndSequence) {
event.dispatchModern(mEventEmitter);
}
ArgumentCaptor<WritableMap> argument = ArgumentCaptor.forClass(WritableMap.class);
verify(mUIManager, times(4))
.receiveEvent(
anyInt(), anyInt(), anyString(), anyBoolean(), anyInt(), argument.capture(), anyInt());
assertEquals(mStartMoveEndExpectedSequence, argument.getAllValues());
}
@Test
public void testFabric_startMoveCancel() {
for (TouchEvent event : mStartMoveCancelSequence) {
event.dispatchModern(mEventEmitter);
}
ArgumentCaptor<WritableMap> argument = ArgumentCaptor.forClass(WritableMap.class);
verify(mUIManager, times(6))
.receiveEvent(
anyInt(), anyInt(), anyString(), anyBoolean(), anyInt(), argument.capture(), anyInt());
assertEquals(mStartMoveCancelExpectedSequence, argument.getAllValues());
}
@Test
public void testFabric_startPointerUpCancel() {
for (TouchEvent event : mStartPointerMoveUpSequence) {
event.dispatchModern(mEventEmitter);
}
ArgumentCaptor<WritableMap> argument = ArgumentCaptor.forClass(WritableMap.class);
verify(mUIManager, times(6))
.receiveEvent(
anyInt(), anyInt(), anyString(), anyBoolean(), anyInt(), argument.capture(), anyInt());
assertEquals(mStartPointerMoveUpExpectedSequence, argument.getAllValues());
}
private TouchEvent createTouchEvent(
int gestureTime, int action, int pointerId, int[] pointerIds, PointerCoords[] pointerCoords) {
mTouchEventCoalescingKeyHelper.addCoalescingKey(gestureTime);
action |= pointerId << MotionEvent.ACTION_POINTER_INDEX_SHIFT;
return TouchEvent.obtain(
SURFACE_ID,
TARGET_VIEW_ID,
getType(action),
MotionEvent.obtain(
gestureTime,
gestureTime,
action,
pointerIds.length,
pointerIds,
pointerCoords,
0,
0f,
0f,
0,
0,
0,
0),
gestureTime,
pointerCoords[0].x,
pointerCoords[0].y,
mTouchEventCoalescingKeyHelper);
}
private static TouchEventType getType(int action) {
action &= ~MotionEvent.ACTION_POINTER_INDEX_MASK;
switch (action) {
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_POINTER_DOWN:
return TouchEventType.START;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_POINTER_UP:
return TouchEventType.END;
case MotionEvent.ACTION_MOVE:
return TouchEventType.MOVE;
case MotionEvent.ACTION_CANCEL:
return TouchEventType.CANCEL;
}
return TouchEventType.START;
}
private static ReadableMap buildGestureEvent(
int surfaceId,
int viewTag,
float locationX,
float locationY,
int time,
int pointerId,
List<WritableMap> touches,
List<WritableMap> changedTouches) {
WritableMap gesture = buildGesture(surfaceId, viewTag, locationX, locationY, time, pointerId);
gesture.putArray("changedTouches", JavaOnlyArray.from(changedTouches));
gesture.putArray("touches", JavaOnlyArray.from(touches));
return gesture;
}
private static WritableMap buildGesture(
int surfaceId, int viewTag, float locationX, float locationY, int time, int pointerId) {
WritableMap map = new JavaOnlyMap();
map.putInt("targetSurface", surfaceId);
map.putInt("target", viewTag);
map.putDouble("locationX", locationX);
map.putDouble("locationY", locationY);
map.putDouble("pageX", locationX);
map.putDouble("pageY", locationY);
map.putDouble("identifier", pointerId);
map.putDouble("timestamp", time);
return map;
}
@SafeVarargs
private static <E> List<E> listOf(E... args) {
return Arrays.asList(args);
}
private static PointerCoords pointerCoords(float x, float y) {
PointerCoords pointerCoords = new PointerCoords();
pointerCoords.x = x;
pointerCoords.y = y;
return pointerCoords;
}
}
@@ -0,0 +1,600 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
package com.facebook.react.fabric.events
import android.util.DisplayMetrics
import android.view.MotionEvent
import com.facebook.react.bridge.*
import com.facebook.react.fabric.FabricUIManager
import com.facebook.react.uimanager.DisplayMetricsHolder
import com.facebook.react.uimanager.events.TouchEvent
import com.facebook.react.uimanager.events.TouchEventCoalescingKeyHelper
import com.facebook.react.uimanager.events.TouchEventType
import org.junit.Assert
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.ArgumentCaptor
import org.mockito.ArgumentMatchers.*
import org.mockito.Mockito.mock
import org.mockito.Mockito.times
import org.mockito.Mockito.verify
import org.powermock.api.mockito.PowerMockito.mockStatic
import org.powermock.api.mockito.PowerMockito.`when` as whenever
import org.powermock.core.classloader.annotations.PowerMockIgnore
import org.powermock.core.classloader.annotations.PrepareForTest
import org.powermock.core.classloader.annotations.SuppressStaticInitializationFor
import org.powermock.modules.junit4.rule.PowerMockRule
import org.robolectric.RobolectricTestRunner
@PrepareForTest(Arguments::class, FabricUIManager::class)
@SuppressStaticInitializationFor("com.facebook.react.fabric.FabricUIManager")
@RunWith(RobolectricTestRunner::class)
@PowerMockIgnore("org.mockito.*", "org.robolectric.*", "androidx.*", "android.*")
class TouchEventDispatchTest {
@get:Rule var rule = PowerMockRule()
private val touchEventCoalescingKeyHelper = TouchEventCoalescingKeyHelper()
/** Events (1 pointer): START -> MOVE -> MOVE -> UP */
private val startMoveEndSequence =
listOf(
createTouchEvent(
gestureTime = GESTURE_START_TIME,
action = MotionEvent.ACTION_DOWN,
pointerId = 0,
pointerIds = intArrayOf(0),
pointerCoords = arrayOf(pointerCoords(1f, 1f))),
createTouchEvent(
gestureTime = GESTURE_START_TIME,
action = MotionEvent.ACTION_MOVE,
pointerId = 0,
pointerIds = intArrayOf(0),
pointerCoords = arrayOf(pointerCoords(1f, 2f))),
createTouchEvent(
gestureTime = GESTURE_START_TIME,
action = MotionEvent.ACTION_MOVE,
pointerId = 0,
pointerIds = intArrayOf(0),
pointerCoords = arrayOf(pointerCoords(1f, 3f))),
createTouchEvent(
gestureTime = GESTURE_START_TIME,
action = MotionEvent.ACTION_UP,
pointerId = 0,
pointerIds = intArrayOf(0),
pointerCoords = arrayOf(pointerCoords(1f, 3f))))
/** Expected values for [startMoveEndSequence] */
private val startMoveEndExpectedSequence =
listOf(
/*
* START event for touch 1:
* {
* touches: [touch1],
* changed: [touch1]
* }
*/
buildGestureEvent(
surfaceId = SURFACE_ID,
viewTag = TARGET_VIEW_ID,
locationX = 1f,
locationY = 1f,
time = GESTURE_START_TIME,
pointerId = 0,
touches =
listOf(buildGesture(SURFACE_ID, TARGET_VIEW_ID, 1f, 1f, GESTURE_START_TIME, 0)),
changedTouches =
listOf(buildGesture(SURFACE_ID, TARGET_VIEW_ID, 1f, 1f, GESTURE_START_TIME, 0))),
/*
* MOVE event for touch 1:
* {
* touches: [touch1],
* changed: [touch1]
* }
*/
buildGestureEvent(
surfaceId = SURFACE_ID,
viewTag = TARGET_VIEW_ID,
locationX = 1f,
locationY = 2f,
time = GESTURE_START_TIME,
pointerId = 0,
touches =
listOf(buildGesture(SURFACE_ID, TARGET_VIEW_ID, 1f, 2f, GESTURE_START_TIME, 0)),
changedTouches =
listOf(buildGesture(SURFACE_ID, TARGET_VIEW_ID, 1f, 2f, GESTURE_START_TIME, 0))),
/*
* MOVE event for touch 1:
* {
* touches: [touch1],
* changed: [touch1]
* }
*/
buildGestureEvent(
surfaceId = SURFACE_ID,
viewTag = TARGET_VIEW_ID,
locationX = 1f,
locationY = 3f,
time = GESTURE_START_TIME,
pointerId = 0,
touches =
listOf(buildGesture(SURFACE_ID, TARGET_VIEW_ID, 1f, 3f, GESTURE_START_TIME, 0)),
changedTouches =
listOf(buildGesture(SURFACE_ID, TARGET_VIEW_ID, 1f, 3f, GESTURE_START_TIME, 0))),
/*
* END event for touch 1:
* {
* touches: [],
* changed: [touch1]
* }
*/
buildGestureEvent(
surfaceId = SURFACE_ID,
viewTag = TARGET_VIEW_ID,
locationX = 1f,
locationY = 3f,
time = GESTURE_START_TIME,
pointerId = 0,
touches = emptyList(),
changedTouches =
listOf(buildGesture(SURFACE_ID, TARGET_VIEW_ID, 1f, 3f, GESTURE_START_TIME, 0))))
/** Events (2 pointer): START 1st -> START 2nd -> MOVE 1st -> UP 2st -> UP 1st */
private val startPointerMoveUpSequence =
listOf(
createTouchEvent(
gestureTime = GESTURE_START_TIME,
action = MotionEvent.ACTION_DOWN,
pointerId = 0,
pointerIds = intArrayOf(0),
pointerCoords = arrayOf(pointerCoords(1f, 1f))),
createTouchEvent(
gestureTime = GESTURE_START_TIME,
action = MotionEvent.ACTION_POINTER_DOWN,
pointerId = 1,
pointerIds = intArrayOf(0, 1),
pointerCoords = arrayOf(pointerCoords(1f, 1f), pointerCoords(2f, 1f))),
createTouchEvent(
gestureTime = GESTURE_START_TIME,
action = MotionEvent.ACTION_MOVE,
pointerId = 0,
pointerIds = intArrayOf(0, 1),
pointerCoords = arrayOf(pointerCoords(1f, 2f), pointerCoords(2f, 1f))),
createTouchEvent(
gestureTime = GESTURE_START_TIME,
action = MotionEvent.ACTION_POINTER_UP,
pointerId = 1,
pointerIds = intArrayOf(0, 1),
pointerCoords = arrayOf(pointerCoords(1f, 2f), pointerCoords(2f, 1f))),
createTouchEvent(
gestureTime = GESTURE_START_TIME,
action = MotionEvent.ACTION_POINTER_UP,
pointerId = 0,
pointerIds = intArrayOf(0),
pointerCoords = arrayOf(pointerCoords(1f, 2f))))
/** Expected values for [startPointerMoveUpSequence] */
private val startPointerMoveUpExpectedSequence =
listOf(
/*
* START event for touch 1:
* {
* touch: 0,
* touches: [touch1],
* changed: [touch1]
* }
*/
buildGestureEvent(
surfaceId = SURFACE_ID,
viewTag = TARGET_VIEW_ID,
locationX = 1f,
locationY = 1f,
time = GESTURE_START_TIME,
pointerId = 0,
touches =
listOf(buildGesture(SURFACE_ID, TARGET_VIEW_ID, 1f, 1f, GESTURE_START_TIME, 0)),
changedTouches =
listOf(buildGesture(SURFACE_ID, TARGET_VIEW_ID, 1f, 1f, GESTURE_START_TIME, 0))),
/*
* START event for touch 2:
* {
* touch: 1,
* touches: [touch0, touch1],
* changed: [touch1]
* }
*/
buildGestureEvent(
surfaceId = SURFACE_ID,
viewTag = TARGET_VIEW_ID,
locationX = 2f,
locationY = 1f,
time = GESTURE_START_TIME,
pointerId = 1,
touches =
listOf(
buildGesture(SURFACE_ID, TARGET_VIEW_ID, 1f, 1f, GESTURE_START_TIME, 0),
buildGesture(SURFACE_ID, TARGET_VIEW_ID, 2f, 1f, GESTURE_START_TIME, 1)),
changedTouches =
listOf(buildGesture(SURFACE_ID, TARGET_VIEW_ID, 2f, 1f, GESTURE_START_TIME, 1))),
/*
* MOVE event for touch 1:
* {
* touch: 0,
* touches: [touch0, touch1],
* changed: [touch0, touch1]
* }
* {
* touch: 1,
* touches: [touch0, touch1],
* changed: [touch0, touch1]
* }
*/
buildGestureEvent(
surfaceId = SURFACE_ID,
viewTag = TARGET_VIEW_ID,
locationX = 1f,
locationY = 2f,
time = GESTURE_START_TIME,
pointerId = 0,
touches =
listOf(
buildGesture(SURFACE_ID, TARGET_VIEW_ID, 1f, 2f, GESTURE_START_TIME, 0),
buildGesture(SURFACE_ID, TARGET_VIEW_ID, 2f, 1f, GESTURE_START_TIME, 1)),
changedTouches =
listOf(
buildGesture(SURFACE_ID, TARGET_VIEW_ID, 1f, 2f, GESTURE_START_TIME, 0),
buildGesture(SURFACE_ID, TARGET_VIEW_ID, 2f, 1f, GESTURE_START_TIME, 1))),
buildGestureEvent(
surfaceId = SURFACE_ID,
viewTag = TARGET_VIEW_ID,
locationX = 2f,
locationY = 1f,
time = GESTURE_START_TIME,
pointerId = 1,
touches =
listOf(
buildGesture(SURFACE_ID, TARGET_VIEW_ID, 1f, 2f, GESTURE_START_TIME, 0),
buildGesture(SURFACE_ID, TARGET_VIEW_ID, 2f, 1f, GESTURE_START_TIME, 1)),
changedTouches =
listOf(
buildGesture(SURFACE_ID, TARGET_VIEW_ID, 1f, 2f, GESTURE_START_TIME, 0),
buildGesture(SURFACE_ID, TARGET_VIEW_ID, 2f, 1f, GESTURE_START_TIME, 1))),
/*
* UP event pointer 1:
* {
* touch: 1,
* touches: [touch0],
* changed: [touch1]
* }
*/
buildGestureEvent(
surfaceId = SURFACE_ID,
viewTag = TARGET_VIEW_ID,
locationX = 2f,
locationY = 1f,
time = GESTURE_START_TIME,
pointerId = 1,
touches =
listOf(buildGesture(SURFACE_ID, TARGET_VIEW_ID, 1f, 2f, GESTURE_START_TIME, 0)),
changedTouches =
listOf(buildGesture(SURFACE_ID, TARGET_VIEW_ID, 2f, 1f, GESTURE_START_TIME, 1))),
/*
* UP event pointer 0:
* {
* touch: 0,
* touches: [],
* changed: [touch0]
* }
*/
buildGestureEvent(
surfaceId = SURFACE_ID,
viewTag = TARGET_VIEW_ID,
locationX = 1f,
locationY = 2f,
time = GESTURE_START_TIME,
pointerId = 0,
touches = emptyList(),
changedTouches =
listOf(buildGesture(SURFACE_ID, TARGET_VIEW_ID, 1f, 2f, GESTURE_START_TIME, 0))))
/** Events (2 pointer): START 1st -> START 2nd -> MOVE 1st -> CANCEL */
private val startMoveCancelSequence =
listOf(
createTouchEvent(
gestureTime = GESTURE_START_TIME,
action = MotionEvent.ACTION_DOWN,
pointerId = 0,
pointerIds = intArrayOf(0),
pointerCoords = arrayOf(pointerCoords(1f, 1f))),
createTouchEvent(
gestureTime = GESTURE_START_TIME,
action = MotionEvent.ACTION_POINTER_DOWN,
pointerId = 1,
pointerIds = intArrayOf(0, 1),
pointerCoords = arrayOf(pointerCoords(1f, 1f), pointerCoords(2f, 1f))),
createTouchEvent(
gestureTime = GESTURE_START_TIME,
action = MotionEvent.ACTION_MOVE,
pointerId = 0,
pointerIds = intArrayOf(0, 1),
pointerCoords = arrayOf(pointerCoords(1f, 2f), pointerCoords(2f, 1f))),
createTouchEvent(
gestureTime = GESTURE_START_TIME,
action = MotionEvent.ACTION_CANCEL,
pointerId = 0,
pointerIds = intArrayOf(0, 1),
pointerCoords = arrayOf(pointerCoords(1f, 3f), pointerCoords(2f, 1f))))
/** Expected values for [startMoveCancelSequence] */
private val startMoveCancelExpectedSequence =
listOf(
/*
* START event for touch 1:
* {
* touch: 0,
* touches: [touch1],
* changed: [touch1]
* }
*/
buildGestureEvent(
surfaceId = SURFACE_ID,
viewTag = TARGET_VIEW_ID,
locationX = 1f,
locationY = 1f,
time = GESTURE_START_TIME,
pointerId = 0,
touches =
listOf(buildGesture(SURFACE_ID, TARGET_VIEW_ID, 1f, 1f, GESTURE_START_TIME, 0)),
changedTouches =
listOf(buildGesture(SURFACE_ID, TARGET_VIEW_ID, 1f, 1f, GESTURE_START_TIME, 0))),
/*
* START event for touch 2:
* {
* touch: 1,
* touches: [touch0, touch1],
* changed: [touch1]
* }
*/
buildGestureEvent(
surfaceId = SURFACE_ID,
viewTag = TARGET_VIEW_ID,
locationX = 2f,
locationY = 1f,
time = GESTURE_START_TIME,
pointerId = 1,
touches =
listOf(
buildGesture(SURFACE_ID, TARGET_VIEW_ID, 1f, 1f, GESTURE_START_TIME, 0),
buildGesture(SURFACE_ID, TARGET_VIEW_ID, 2f, 1f, GESTURE_START_TIME, 1)),
changedTouches =
listOf(buildGesture(SURFACE_ID, TARGET_VIEW_ID, 2f, 1f, GESTURE_START_TIME, 1))),
/*
* MOVE event for touch 1:
* {
* touch: 0,
* touches: [touch0, touch1],
* changed: [touch0, touch1]
* }
* {
* touch: 1,
* touches: [touch0, touch1],
* changed: [touch0, touch1]
* }
*/
buildGestureEvent(
surfaceId = SURFACE_ID,
viewTag = TARGET_VIEW_ID,
locationX = 1f,
locationY = 2f,
time = GESTURE_START_TIME,
pointerId = 0,
touches =
listOf(
buildGesture(SURFACE_ID, TARGET_VIEW_ID, 1f, 2f, GESTURE_START_TIME, 0),
buildGesture(SURFACE_ID, TARGET_VIEW_ID, 2f, 1f, GESTURE_START_TIME, 1)),
changedTouches =
listOf(
buildGesture(SURFACE_ID, TARGET_VIEW_ID, 1f, 2f, GESTURE_START_TIME, 0),
buildGesture(SURFACE_ID, TARGET_VIEW_ID, 2f, 1f, GESTURE_START_TIME, 1))),
buildGestureEvent(
SURFACE_ID,
TARGET_VIEW_ID,
2f,
1f,
GESTURE_START_TIME,
1,
listOf(
buildGesture(SURFACE_ID, TARGET_VIEW_ID, 1f, 2f, GESTURE_START_TIME, 0),
buildGesture(SURFACE_ID, TARGET_VIEW_ID, 2f, 1f, GESTURE_START_TIME, 1)),
listOf(
buildGesture(SURFACE_ID, TARGET_VIEW_ID, 1f, 2f, GESTURE_START_TIME, 0),
buildGesture(SURFACE_ID, TARGET_VIEW_ID, 2f, 1f, GESTURE_START_TIME, 1))),
/*
* CANCEL event:
* {
* touch: 0,
* touches: [],
* changed: [touch0, touch1]
* }
* {
* touch: 1,
* touches: [],
* changed: [touch0, touch1]
* }
*/
buildGestureEvent(
surfaceId = SURFACE_ID,
viewTag = TARGET_VIEW_ID,
locationX = 1f,
locationY = 3f,
time = GESTURE_START_TIME,
pointerId = 0,
touches = emptyList(),
changedTouches =
listOf(
buildGesture(SURFACE_ID, TARGET_VIEW_ID, 1f, 3f, GESTURE_START_TIME, 0),
buildGesture(SURFACE_ID, TARGET_VIEW_ID, 2f, 1f, GESTURE_START_TIME, 1))),
buildGestureEvent(
surfaceId = SURFACE_ID,
viewTag = TARGET_VIEW_ID,
locationX = 2f,
locationY = 1f,
time = GESTURE_START_TIME,
pointerId = 1,
touches = emptyList(),
changedTouches =
listOf(
buildGesture(SURFACE_ID, TARGET_VIEW_ID, 1f, 3f, GESTURE_START_TIME, 0),
buildGesture(SURFACE_ID, TARGET_VIEW_ID, 2f, 1f, GESTURE_START_TIME, 1))))
private var dispatchedEvents: List<ReadableMap> = emptyList()
private lateinit var eventEmitter: FabricEventEmitter
private lateinit var uiManager: FabricUIManager
@Before
fun setUp() {
mockStatic(Arguments::class.java)
mockStatic(FabricUIManager::class.java)
whenever(Arguments.createArray()).thenAnswer { JavaOnlyArray() }
whenever(Arguments.createMap()).thenAnswer { JavaOnlyMap() }
val metrics = DisplayMetrics()
metrics.xdpi = 1f
metrics.ydpi = 1f
metrics.density = 1f
DisplayMetricsHolder.setWindowDisplayMetrics(metrics)
uiManager = mock(FabricUIManager::class.java)
eventEmitter = FabricEventEmitter(uiManager)
}
@Test
fun testFabric_startMoveEnd() {
for (event in startMoveEndSequence) {
event.dispatchModern(eventEmitter)
}
val argument = ArgumentCaptor.forClass(WritableMap::class.java)
verify(uiManager, times(4))
.receiveEvent(
anyInt(), anyInt(), anyString(), anyBoolean(), anyInt(), argument.capture(), anyInt())
Assert.assertEquals(startMoveEndExpectedSequence, argument.allValues)
}
@Test
fun testFabric_startMoveCancel() {
for (event in startMoveCancelSequence) {
event.dispatchModern(eventEmitter)
}
val argument = ArgumentCaptor.forClass(WritableMap::class.java)
verify(uiManager, times(6))
.receiveEvent(
anyInt(), anyInt(), anyString(), anyBoolean(), anyInt(), argument.capture(), anyInt())
Assert.assertEquals(startMoveCancelExpectedSequence, argument.allValues)
}
@Test
fun testFabric_startPointerUpCancel() {
for (event in startPointerMoveUpSequence) {
event.dispatchModern(eventEmitter)
}
val argument = ArgumentCaptor.forClass(WritableMap::class.java)
verify(uiManager, times(6))
.receiveEvent(
anyInt(), anyInt(), anyString(), anyBoolean(), anyInt(), argument.capture(), anyInt())
Assert.assertEquals(startPointerMoveUpExpectedSequence, argument.allValues)
}
private fun createTouchEvent(
gestureTime: Int,
action: Int,
pointerId: Int,
pointerIds: IntArray,
pointerCoords: Array<MotionEvent.PointerCoords>
): TouchEvent {
touchEventCoalescingKeyHelper.addCoalescingKey(gestureTime.toLong())
val action = action or (pointerId shl MotionEvent.ACTION_POINTER_INDEX_SHIFT)
return TouchEvent.obtain(
SURFACE_ID,
TARGET_VIEW_ID,
getType(action),
MotionEvent.obtain(
gestureTime.toLong(),
gestureTime.toLong(),
action,
pointerIds.size,
pointerIds,
pointerCoords,
0,
0f,
0f,
0,
0,
0,
0),
gestureTime.toLong(),
pointerCoords[0].x,
pointerCoords[0].y,
touchEventCoalescingKeyHelper)
}
companion object {
private const val SURFACE_ID = 121
private const val TARGET_VIEW_ID = 42
private const val GESTURE_START_TIME = 1
private fun getType(action: Int): TouchEventType {
val action = action and MotionEvent.ACTION_POINTER_INDEX_MASK.inv()
when (action) {
MotionEvent.ACTION_DOWN,
MotionEvent.ACTION_POINTER_DOWN -> return TouchEventType.START
MotionEvent.ACTION_UP,
MotionEvent.ACTION_POINTER_UP -> return TouchEventType.END
MotionEvent.ACTION_MOVE -> return TouchEventType.MOVE
MotionEvent.ACTION_CANCEL -> return TouchEventType.CANCEL
}
return TouchEventType.START
}
private fun buildGestureEvent(
surfaceId: Int,
viewTag: Int,
locationX: Float,
locationY: Float,
time: Int,
pointerId: Int,
touches: List<WritableMap>,
changedTouches: List<WritableMap>
): ReadableMap =
buildGesture(surfaceId, viewTag, locationX, locationY, time, pointerId).apply {
putArray("changedTouches", JavaOnlyArray.from(changedTouches))
putArray("touches", JavaOnlyArray.from(touches))
}
private fun buildGesture(
surfaceId: Int,
viewTag: Int,
locationX: Float,
locationY: Float,
time: Int,
pointerId: Int
): WritableMap =
JavaOnlyMap().apply {
putInt("targetSurface", surfaceId)
putInt("target", viewTag)
putDouble("locationX", locationX.toDouble())
putDouble("locationY", locationY.toDouble())
putDouble("pageX", locationX.toDouble())
putDouble("pageY", locationY.toDouble())
putDouble("identifier", pointerId.toDouble())
putDouble("timestamp", time.toDouble())
}
private fun pointerCoords(x: Float, y: Float): MotionEvent.PointerCoords =
MotionEvent.PointerCoords().apply {
this.x = x
this.y = y
}
}
}