Merge "Introduce multi finger trackpad gestures to tapl tests" into udc-qpr-dev am: 666c3b231d

Original change: https://googleplex-android-review.googlesource.com/c/platform/packages/apps/Launcher3/+/23895346

Change-Id: Ib4732c4f6e117f378132e6c8e06eea29e7e2db5c
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
Tracy Zhou
2023-07-13 07:15:56 +00:00
committed by Automerger Merge Worker
3 changed files with 171 additions and 109 deletions
@@ -16,11 +16,13 @@
package com.android.quickstep;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assume.assumeTrue;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
import com.android.launcher3.tapl.LauncherInstrumentation.TrackpadGestureType;
import com.android.launcher3.ui.PortraitLandscapeRunner.PortraitLandscape;
import com.android.launcher3.ui.TaplTestsLauncher3;
import com.android.quickstep.NavigationModeSwitchRule.NavigationModeSwitch;
@@ -38,12 +40,11 @@ public class TaplTestsTrackpad extends AbstractQuickStepTest {
public void setUp() throws Exception {
super.setUp();
TaplTestsLauncher3.initialize(this);
mLauncher.setSwipeFromTrackpad(true);
}
@After
public void tearDown() {
mLauncher.setSwipeFromTrackpad(false);
mLauncher.setTrackpadGestureType(TrackpadGestureType.NONE);
}
@Test
@@ -52,7 +53,30 @@ public class TaplTestsTrackpad extends AbstractQuickStepTest {
public void goHome() throws Exception {
assumeTrue(mLauncher.isTablet());
mLauncher.setTrackpadGestureType(TrackpadGestureType.THREE_FINGER);
startTestActivity(2);
mLauncher.goHome();
}
@Test
@PortraitLandscape
@NavigationModeSwitch
public void switchToOverview() throws Exception {
assumeTrue(mLauncher.isTablet());
mLauncher.setTrackpadGestureType(TrackpadGestureType.THREE_FINGER);
startTestActivity(2);
mLauncher.goHome().switchToOverview();
}
@Test
@PortraitLandscape
@NavigationModeSwitch
public void testAllAppsFromHome() throws Exception {
assumeTrue(mLauncher.isTablet());
mLauncher.setTrackpadGestureType(TrackpadGestureType.TWO_FINGER);
assertNotNull("switchToAllApps() returned null",
mLauncher.getWorkspace().switchToAllApps());
}
}
@@ -30,6 +30,8 @@ import android.view.MotionEvent;
import androidx.annotation.NonNull;
import androidx.test.uiautomator.UiObject2;
import com.android.launcher3.tapl.LauncherInstrumentation.NavigationModel;
import com.android.launcher3.tapl.LauncherInstrumentation.TrackpadGestureType;
import com.android.launcher3.testing.shared.TestProtocol;
import java.util.List;
@@ -75,80 +77,76 @@ public abstract class Background extends LauncherInstrumentation.VisibleContaine
}
protected void goToOverviewUnchecked() {
switch (mLauncher.getNavigationModel()) {
case ZERO_BUTTON: {
final long downTime = SystemClock.uptimeMillis();
sendDownPointerToEnterOverviewToLauncher(downTime);
String swipeAndHoldToEnterOverviewActionName =
"swiping and holding to enter overview";
// If swiping from an app (e.g. Overview is in Background), we pause and hold on
// swipe up to make overview appear, or else swiping without holding would take
// us to the Home state. If swiping up from Home (e.g. Overview in Home or
// Workspace state where the below condition is true), there is no need to pause,
// and we will not test for an intermediate carousel as one will not exist.
if (zeroButtonToOverviewGestureStateTransitionWhileHolding()) {
mLauncher.runToState(
() -> sendSwipeUpAndHoldToEnterOverviewGestureToLauncher(downTime),
OVERVIEW_STATE_ORDINAL, swipeAndHoldToEnterOverviewActionName);
sendUpPointerToEnterOverviewToLauncher(downTime);
} else {
// If swiping up from an app to overview, pause on intermediate carousel
// until snapshots are visible. No intermediate carousel when swiping from
// Home. The task swiped up is not a snapshot but the TaskViewSimulator. If
// only a single task exists, no snapshots will be available during swipe up.
mLauncher.executeAndWaitForLauncherEvent(
() -> sendSwipeUpAndHoldToEnterOverviewGestureToLauncher(downTime),
event -> TestProtocol.PAUSE_DETECTED_MESSAGE.equals(
event.getClassName().toString()),
() -> "Pause wasn't detected",
swipeAndHoldToEnterOverviewActionName);
try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
"paused on swipe up to overview")) {
if (mLauncher.getRecentTasks().size() > 1) {
// When swiping up to grid-overview for tablets, the swiped tab will be
// in the middle of the screen (TaskViewSimulator, not a snapshot), and
// all remaining snapshots will be to the left of that task. In
// non-tablet overview, snapshots can be on either side of the swiped
// task, but we still check that they become visible after swiping and
// pausing.
mLauncher.waitForOverviewObject("snapshot");
if (mLauncher.isTablet()) {
List<UiObject2> tasks = mLauncher.getDevice().findObjects(
mLauncher.getOverviewObjectSelector("snapshot"));
final int centerX = mLauncher.getDevice().getDisplayWidth() / 2;
mLauncher.assertTrue(
"All tasks not to the left of the swiped task",
tasks.stream()
.allMatch(
t -> t.getVisibleBounds().right < centerX));
}
}
String upPointerToEnterOverviewActionName =
"sending UP pointer to enter overview";
mLauncher.runToState(() -> sendUpPointerToEnterOverviewToLauncher(downTime),
OVERVIEW_STATE_ORDINAL, upPointerToEnterOverviewActionName);
}
}
break;
}
case THREE_BUTTON:
if (mLauncher.isTablet()) {
mLauncher.expectEvent(TestProtocol.SEQUENCE_MAIN,
LauncherInstrumentation.EVENT_TOUCH_DOWN);
mLauncher.expectEvent(TestProtocol.SEQUENCE_MAIN,
LauncherInstrumentation.EVENT_TOUCH_UP);
}
if (mLauncher.isTrackpadGestureEnabled()) {
mLauncher.expectEvent(TestProtocol.SEQUENCE_TIS, EVENT_TOUCH_DOWN_TIS);
mLauncher.expectEvent(TestProtocol.SEQUENCE_TIS, EVENT_TOUCH_UP_TIS);
}
mLauncher.expectEvent(TestProtocol.SEQUENCE_MAIN, SQUARE_BUTTON_EVENT);
if (mLauncher.getNavigationModel() == NavigationModel.ZERO_BUTTON
|| mLauncher.getTrackpadGestureType() == TrackpadGestureType.THREE_FINGER) {
final long downTime = SystemClock.uptimeMillis();
sendDownPointerToEnterOverviewToLauncher(downTime);
String swipeAndHoldToEnterOverviewActionName =
"swiping and holding to enter overview";
// If swiping from an app (e.g. Overview is in Background), we pause and hold on
// swipe up to make overview appear, or else swiping without holding would take
// us to the Home state. If swiping up from Home (e.g. Overview in Home or
// Workspace state where the below condition is true), there is no need to pause,
// and we will not test for an intermediate carousel as one will not exist.
if (zeroButtonToOverviewGestureStateTransitionWhileHolding()) {
mLauncher.runToState(
() -> mLauncher.waitForNavigationUiObject("recent_apps").click(),
OVERVIEW_STATE_ORDINAL, "clicking Recents button");
break;
() -> sendSwipeUpAndHoldToEnterOverviewGestureToLauncher(downTime),
OVERVIEW_STATE_ORDINAL, swipeAndHoldToEnterOverviewActionName);
sendUpPointerToEnterOverviewToLauncher(downTime);
} else {
// If swiping up from an app to overview, pause on intermediate carousel
// until snapshots are visible. No intermediate carousel when swiping from
// Home. The task swiped up is not a snapshot but the TaskViewSimulator. If
// only a single task exists, no snapshots will be available during swipe up.
mLauncher.executeAndWaitForLauncherEvent(
() -> sendSwipeUpAndHoldToEnterOverviewGestureToLauncher(downTime),
event -> TestProtocol.PAUSE_DETECTED_MESSAGE.equals(
event.getClassName().toString()),
() -> "Pause wasn't detected",
swipeAndHoldToEnterOverviewActionName);
try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
"paused on swipe up to overview")) {
if (mLauncher.getRecentTasks().size() > 1) {
// When swiping up to grid-overview for tablets, the swiped tab will be
// in the middle of the screen (TaskViewSimulator, not a snapshot), and
// all remaining snapshots will be to the left of that task. In
// non-tablet overview, snapshots can be on either side of the swiped
// task, but we still check that they become visible after swiping and
// pausing.
mLauncher.waitForOverviewObject("snapshot");
if (mLauncher.isTablet()) {
List<UiObject2> tasks = mLauncher.getDevice().findObjects(
mLauncher.getOverviewObjectSelector("snapshot"));
final int centerX = mLauncher.getDevice().getDisplayWidth() / 2;
mLauncher.assertTrue(
"All tasks not to the left of the swiped task",
tasks.stream()
.allMatch(
t -> t.getVisibleBounds().right < centerX));
}
}
String upPointerToEnterOverviewActionName =
"sending UP pointer to enter overview";
mLauncher.runToState(() -> sendUpPointerToEnterOverviewToLauncher(downTime),
OVERVIEW_STATE_ORDINAL, upPointerToEnterOverviewActionName);
}
}
} else {
if (mLauncher.isTablet()) {
mLauncher.expectEvent(TestProtocol.SEQUENCE_MAIN,
LauncherInstrumentation.EVENT_TOUCH_DOWN);
mLauncher.expectEvent(TestProtocol.SEQUENCE_MAIN,
LauncherInstrumentation.EVENT_TOUCH_UP);
}
if (mLauncher.isTrackpadGestureEnabled()) {
mLauncher.expectEvent(TestProtocol.SEQUENCE_TIS, EVENT_TOUCH_DOWN_TIS);
mLauncher.expectEvent(TestProtocol.SEQUENCE_TIS, EVENT_TOUCH_UP_TIS);
}
mLauncher.expectEvent(TestProtocol.SEQUENCE_MAIN, SQUARE_BUTTON_EVENT);
mLauncher.runToState(
() -> mLauncher.waitForNavigationUiObject("recent_apps").click(),
OVERVIEW_STATE_ORDINAL, "clicking Recents button");
}
expectSwitchToOverviewEvents();
}
@@ -263,10 +261,8 @@ public abstract class Background extends LauncherInstrumentation.VisibleContaine
endY = startY;
}
final boolean isZeroButton = mLauncher.getNavigationModel()
== LauncherInstrumentation.NavigationModel.ZERO_BUTTON;
LauncherInstrumentation.GestureScope gestureScope =
launcherWasVisible && isZeroButton
launcherWasVisible
? LauncherInstrumentation.GestureScope.INSIDE_TO_OUTSIDE
: LauncherInstrumentation.GestureScope.OUTSIDE_WITH_PILFER;
mLauncher.executeAndWaitForEvent(
@@ -326,6 +322,8 @@ public abstract class Background extends LauncherInstrumentation.VisibleContaine
}
protected int getSwipeStartY() {
return mLauncher.getRealDisplaySize().y - 1;
return mLauncher.getTrackpadGestureType() == TrackpadGestureType.THREE_FINGER
? mLauncher.getDevice().getDisplayHeight() * 3 / 4
: mLauncher.getRealDisplaySize().y - 1;
}
}
@@ -139,6 +139,13 @@ public final class LauncherInstrumentation {
OUTSIDE_WITH_KEYCODE,
}
public enum TrackpadGestureType {
NONE,
TWO_FINGER,
THREE_FINGER,
FOUR_FINGER
}
// Base class for launcher containers.
abstract static class VisibleContainer {
protected final LauncherInstrumentation mLauncher;
@@ -198,7 +205,7 @@ public final class LauncherInstrumentation {
private boolean mCheckEventsForSuccessfulGestures = false;
private Runnable mOnLauncherCrashed;
private boolean mSwipeFromTrackpad = false;
private TrackpadGestureType mTrackpadGestureType = TrackpadGestureType.NONE;
private int mPointerCount = 0;
private static Pattern getTouchEventPattern(String prefix, String action) {
@@ -715,8 +722,17 @@ public final class LauncherInstrumentation {
mIgnoreTaskbarVisibility = ignoreTaskbarVisibility;
}
public void setSwipeFromTrackpad(boolean swipeFromTrackpad) {
mSwipeFromTrackpad = swipeFromTrackpad;
/**
* Set the trackpad gesture type of the interaction.
* @param trackpadGestureType whether it's not from trackpad, two-finger, three-finger, or
* four-finger gesture.
*/
public void setTrackpadGestureType(TrackpadGestureType trackpadGestureType) {
mTrackpadGestureType = trackpadGestureType;
}
TrackpadGestureType getTrackpadGestureType() {
return mTrackpadGestureType;
}
/**
@@ -1008,8 +1024,11 @@ public final class LauncherInstrumentation {
// We need waiting for any accessibility event generated after pressing Home because
// otherwise waitForIdle may return immediately in case when there was a big enough
// pause in accessibility events prior to pressing Home.
boolean isThreeFingerTrackpadGesture =
mTrackpadGestureType == TrackpadGestureType.THREE_FINGER;
final String action;
if (getNavigationModel() == NavigationModel.ZERO_BUTTON || mSwipeFromTrackpad) {
if (getNavigationModel() == NavigationModel.ZERO_BUTTON
|| isThreeFingerTrackpadGesture) {
checkForAnomaly(false, true);
final Point displaySize = getRealDisplaySize();
@@ -1025,8 +1044,9 @@ public final class LauncherInstrumentation {
} else {
action = "swiping up to home";
int startY = mSwipeFromTrackpad ? displaySize.y * 3 / 4 : displaySize.y - 1;
int endY = mSwipeFromTrackpad ? displaySize.y / 4 : displaySize.y / 2;
int startY = isThreeFingerTrackpadGesture ? displaySize.y * 3 / 4
: displaySize.y - 1;
int endY = isThreeFingerTrackpadGesture ? displaySize.y / 4 : displaySize.y / 2;
swipeToState(
displaySize.x / 2, startY,
displaySize.x / 2, endY,
@@ -1070,15 +1090,18 @@ public final class LauncherInstrumentation {
waitForLauncherInitialized();
final boolean launcherVisible =
isTablet() ? isLauncherContainerVisible() : isLauncherVisible();
if (getNavigationModel() == NavigationModel.ZERO_BUTTON || mSwipeFromTrackpad) {
boolean isThreeFingerTrackpadGesture =
mTrackpadGestureType == TrackpadGestureType.THREE_FINGER;
if (getNavigationModel() == NavigationModel.ZERO_BUTTON
|| isThreeFingerTrackpadGesture) {
final Point displaySize = getRealDisplaySize();
final GestureScope gestureScope =
launcherVisible ? GestureScope.INSIDE_TO_OUTSIDE_WITH_KEYCODE
: GestureScope.OUTSIDE_WITH_KEYCODE;
// TODO(b/225505986): change startY and endY back to displaySize.y / 2 once the
// issue is solved.
int startX = mSwipeFromTrackpad ? displaySize.x / 4 : 0;
int endX = mSwipeFromTrackpad ? displaySize.x * 3 / 4 : displaySize.x / 2;
int startX = isThreeFingerTrackpadGesture ? displaySize.x / 4 : 0;
int endX = isThreeFingerTrackpadGesture ? displaySize.x * 3 / 4 : displaySize.x / 2;
linearGesture(startX, displaySize.y / 4, endX, displaySize.y / 4,
10, false, gestureScope);
} else {
@@ -1615,19 +1638,29 @@ public final class LauncherInstrumentation {
final Point start = new Point(startX, startY);
final Point end = new Point(endX, endY);
sendPointer(downTime, downTime, MotionEvent.ACTION_DOWN, start, gestureScope);
if (mSwipeFromTrackpad) {
if (mTrackpadGestureType != TrackpadGestureType.NONE) {
sendPointer(downTime, downTime, getPointerAction(MotionEvent.ACTION_POINTER_DOWN, 1),
start, gestureScope);
sendPointer(downTime, downTime, getPointerAction(MotionEvent.ACTION_POINTER_DOWN, 2),
start, gestureScope);
if (mTrackpadGestureType == TrackpadGestureType.THREE_FINGER
|| mTrackpadGestureType == TrackpadGestureType.FOUR_FINGER) {
sendPointer(downTime, downTime,
getPointerAction(MotionEvent.ACTION_POINTER_DOWN, 2),
start, gestureScope);
if (mTrackpadGestureType == TrackpadGestureType.FOUR_FINGER) {
sendPointer(downTime, downTime,
getPointerAction(MotionEvent.ACTION_POINTER_DOWN, 3),
start, gestureScope);
}
}
}
final long endTime = movePointer(
start, end, steps, false, downTime, downTime, slowDown, gestureScope);
if (mSwipeFromTrackpad) {
sendPointer(downTime, downTime, getPointerAction(MotionEvent.ACTION_POINTER_UP, 2),
start, gestureScope);
sendPointer(downTime, downTime, getPointerAction(MotionEvent.ACTION_POINTER_UP, 1),
start, gestureScope);
if (mTrackpadGestureType != TrackpadGestureType.NONE) {
for (int i = mPointerCount; i >= 2; i--) {
sendPointer(downTime, downTime,
getPointerAction(MotionEvent.ACTION_POINTER_UP, i - 1),
start, gestureScope);
}
}
sendPointer(downTime, endTime, MotionEvent.ACTION_UP, end, gestureScope);
}
@@ -1659,20 +1692,25 @@ public final class LauncherInstrumentation {
return getContext().getResources();
}
private static MotionEvent getTrackpadThreeFingerMotionEvent(long downTime, long eventTime,
int action, float x, float y, int pointerCount) {
private static MotionEvent getTrackpadMotionEvent(long downTime, long eventTime,
int action, float x, float y, int pointerCount, TrackpadGestureType gestureType) {
MotionEvent.PointerProperties[] pointerProperties =
new MotionEvent.PointerProperties[pointerCount];
MotionEvent.PointerCoords[] pointerCoords = new MotionEvent.PointerCoords[pointerCount];
boolean isMultiFingerGesture = gestureType != TrackpadGestureType.TWO_FINGER;
for (int i = 0; i < pointerCount; i++) {
pointerProperties[i] = getPointerProperties(i);
pointerCoords[i] = getPointerCoords(x, y);
pointerCoords[i].setAxisValue(AXIS_GESTURE_SWIPE_FINGER_COUNT, 3);
if (isMultiFingerGesture) {
pointerCoords[i].setAxisValue(AXIS_GESTURE_SWIPE_FINGER_COUNT,
gestureType == TrackpadGestureType.THREE_FINGER ? 3 : 4);
}
}
return MotionEvent.obtain(downTime, eventTime, action, pointerCount, pointerProperties,
pointerCoords, 0, 0, 1.0f, 1.0f, 0, 0,
InputDevice.SOURCE_MOUSE | InputDevice.SOURCE_CLASS_POINTER, 0, 0,
MotionEvent.CLASSIFICATION_MULTI_FINGER_SWIPE);
isMultiFingerGesture ? MotionEvent.CLASSIFICATION_MULTI_FINGER_SWIPE
: MotionEvent.CLASSIFICATION_TWO_FINGER_SWIPE);
}
private static MotionEvent getMotionEvent(long downTime, long eventTime, int action,
@@ -1712,22 +1750,25 @@ public final class LauncherInstrumentation {
public void sendPointer(long downTime, long currentTime, int action, Point point,
GestureScope gestureScope) {
final boolean hasTIS = hasTIS();
int pointerCount = 1;
int pointerCount = mPointerCount;
boolean isTrackpadGesture = mTrackpadGestureType != TrackpadGestureType.NONE;
boolean isTwoFingerTrackpadGesture = mTrackpadGestureType == TrackpadGestureType.TWO_FINGER;
switch (action & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
if (gestureScope != GestureScope.OUTSIDE_WITH_PILFER
&& gestureScope != GestureScope.OUTSIDE_WITHOUT_PILFER
&& gestureScope != GestureScope.OUTSIDE_WITH_KEYCODE
&& !mSwipeFromTrackpad) {
&& (!isTrackpadGesture || isTwoFingerTrackpadGesture)) {
expectEvent(TestProtocol.SEQUENCE_MAIN, EVENT_TOUCH_DOWN);
}
if (hasTIS && (isTrackpadGestureEnabled()
|| getNavigationModel() != NavigationModel.THREE_BUTTON)) {
expectEvent(TestProtocol.SEQUENCE_TIS, EVENT_TOUCH_DOWN_TIS);
}
if (mSwipeFromTrackpad) {
if (isTrackpadGesture) {
mPointerCount = 1;
pointerCount = mPointerCount;
}
break;
case MotionEvent.ACTION_UP:
@@ -1740,7 +1781,7 @@ public final class LauncherInstrumentation {
if (gestureScope != GestureScope.OUTSIDE_WITH_PILFER
&& gestureScope != GestureScope.OUTSIDE_WITHOUT_PILFER
&& gestureScope != GestureScope.OUTSIDE_WITH_KEYCODE
&& !mSwipeFromTrackpad) {
&& (!isTrackpadGesture || isTwoFingerTrackpadGesture)) {
expectEvent(TestProtocol.SEQUENCE_MAIN,
gestureScope == GestureScope.INSIDE
|| gestureScope == GestureScope.OUTSIDE_WITHOUT_PILFER
@@ -1767,8 +1808,6 @@ public final class LauncherInstrumentation {
pointerCount = mPointerCount;
break;
case MotionEvent.ACTION_POINTER_UP:
pointerCount = mPointerCount;
// When the gesture is handled outside, it's cancelled within launcher.
if (gestureScope != GestureScope.INSIDE_TO_OUTSIDE_WITH_KEYCODE
&& gestureScope != GestureScope.OUTSIDE_WITH_KEYCODE) {
@@ -1779,9 +1818,10 @@ public final class LauncherInstrumentation {
break;
}
final MotionEvent event = mSwipeFromTrackpad
? getTrackpadThreeFingerMotionEvent(
downTime, currentTime, action, point.x, point.y, pointerCount)
final MotionEvent event = isTrackpadGesture
? getTrackpadMotionEvent(
downTime, currentTime, action, point.x, point.y, pointerCount,
mTrackpadGestureType)
: getMotionEvent(downTime, currentTime, action, point.x, point.y);
assertTrue("injectInputEvent failed",
mInstrumentation.getUiAutomation().injectInputEvent(event, true, false));