diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsTrackpad.java b/quickstep/tests/src/com/android/quickstep/TaplTestsTrackpad.java index e92dc8fa04..4c6874e47b 100644 --- a/quickstep/tests/src/com/android/quickstep/TaplTestsTrackpad.java +++ b/quickstep/tests/src/com/android/quickstep/TaplTestsTrackpad.java @@ -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()); + } } diff --git a/tests/tapl/com/android/launcher3/tapl/Background.java b/tests/tapl/com/android/launcher3/tapl/Background.java index 31e9aa28ef..3dab9a8ebe 100644 --- a/tests/tapl/com/android/launcher3/tapl/Background.java +++ b/tests/tapl/com/android/launcher3/tapl/Background.java @@ -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 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 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; } } diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java index ce50e2255c..5b67d73e8e 100644 --- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java +++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java @@ -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));