Add TAPL tests for the keyboard quick switch view

Flag: ENABLE_KEYBOARD_QUICK_SWITCH
Bug: 267520665
Test: TaplTestsKeyboardQuickSwitch
Design doc: go/kqs-tapl-tests

Change-Id: I1c3c5c758011a36ed405426f543ce450910f774e
This commit is contained in:
Schneider Victor-tulias
2023-09-21 10:34:54 -04:00
parent 7f1b5d0a70
commit 41b42bf7d5
14 changed files with 597 additions and 41 deletions
@@ -0,0 +1,187 @@
/*
* Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.quickstep;
import android.content.Intent;
import androidx.annotation.NonNull;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
import com.android.launcher3.tapl.KeyboardQuickSwitch;
import com.android.launcher3.ui.TaplTestsLauncher3;
import org.junit.Assume;
import org.junit.Test;
import org.junit.runner.RunWith;
@LargeTest
@RunWith(AndroidJUnit4.class)
public class TaplTestsKeyboardQuickSwitch extends AbstractQuickStepTest {
private enum TestSurface {
HOME, LAUNCHED_APP, HOME_ALL_APPS, WIDGETS,
}
private enum TestCase {
DISMISS(0),
LAUNCH_LAST_APP(0),
LAUNCH_SELECTED_APP(1),
LAUNCH_OVERVIEW(5);
private final int mNumAdditionalRunningTasks;
TestCase(int numAdditionalRunningTasks) {
mNumAdditionalRunningTasks = numAdditionalRunningTasks;
}
}
private static final String CALCULATOR_APP_PACKAGE =
resolveSystemApp(Intent.CATEGORY_APP_CALCULATOR);
@Override
public void setUp() throws Exception {
Assume.assumeTrue(mLauncher.isTablet());
super.setUp();
TaplTestsLauncher3.initialize(this);
startAppFast(CALCULATOR_APP_PACKAGE);
startTestActivity(2);
}
@Test
public void testDismiss_fromHome() {
runTest(TestSurface.HOME, TestCase.DISMISS);
}
@Test
public void testDismiss_fromApp() {
runTest(TestSurface.LAUNCHED_APP, TestCase.DISMISS);
}
@Test
public void testDismiss_fromHomeAllApps() {
runTest(TestSurface.HOME_ALL_APPS, TestCase.DISMISS);
}
@Test
public void testDismiss_fromWidgets() {
runTest(TestSurface.WIDGETS, TestCase.DISMISS);
}
@Test
public void testLaunchLastTask_fromHome() {
runTest(TestSurface.HOME, TestCase.LAUNCH_LAST_APP);
}
@Test
public void testLaunchLastTask_fromApp() {
runTest(TestSurface.LAUNCHED_APP, TestCase.LAUNCH_LAST_APP);
}
@Test
public void testLaunchLastTask_fromHomeAllApps() {
runTest(TestSurface.HOME_ALL_APPS, TestCase.LAUNCH_LAST_APP);
}
@Test
public void testLaunchLastTask_fromWidgets() {
runTest(TestSurface.WIDGETS, TestCase.LAUNCH_LAST_APP);
}
@Test
public void testLaunchSelectedTask_fromHome() {
runTest(TestSurface.HOME, TestCase.LAUNCH_SELECTED_APP);
}
@Test
public void testLaunchSelectedTask_fromApp() {
runTest(TestSurface.LAUNCHED_APP, TestCase.LAUNCH_SELECTED_APP);
}
@Test
public void testLaunchSelectedTask_fromHomeAllApps() {
runTest(TestSurface.HOME_ALL_APPS, TestCase.LAUNCH_SELECTED_APP);
}
@Test
public void testLaunchSelectedTask_fromWidgets() {
runTest(TestSurface.WIDGETS, TestCase.LAUNCH_SELECTED_APP);
}
@Test
public void testLaunchOverviewTask_fromHome() {
runTest(TestSurface.HOME, TestCase.LAUNCH_OVERVIEW);
}
@Test
public void testLaunchOverviewTask_fromApp() {
runTest(TestSurface.LAUNCHED_APP, TestCase.LAUNCH_OVERVIEW);
}
@Test
public void testLaunchOverviewTask_fromHomeAllApps() {
runTest(TestSurface.HOME_ALL_APPS, TestCase.LAUNCH_OVERVIEW);
}
@Test
public void testLaunchOverviewTask_fromWidgets() {
runTest(TestSurface.WIDGETS, TestCase.LAUNCH_OVERVIEW);
}
private void runTest(@NonNull TestSurface testSurface, @NonNull TestCase testCase) {
for (int i = 0; i < testCase.mNumAdditionalRunningTasks; i++) {
startTestActivity(3 + i);
}
KeyboardQuickSwitch kqs;
switch (testSurface) {
case HOME:
kqs = mLauncher.goHome().showQuickSwitchView();
break;
case LAUNCHED_APP:
mLauncher.setIgnoreTaskbarVisibility(true);
kqs = mLauncher.getLaunchedAppState().showQuickSwitchView();
break;
case HOME_ALL_APPS:
kqs = mLauncher.goHome().switchToAllApps().showQuickSwitchView();
break;
case WIDGETS:
kqs = mLauncher.goHome().openAllWidgets().showQuickSwitchView();
break;
default:
throw new IllegalStateException(
"KeyboardQuickSwitch could not be initialized for test surface: "
+ testSurface);
}
switch (testCase) {
case DISMISS:
kqs.dismiss();
break;
case LAUNCH_LAST_APP:
kqs.launchFocusedAppTask(CALCULATOR_APP_PACKAGE);
break;
case LAUNCH_SELECTED_APP:
kqs.moveFocusForward().launchFocusedAppTask(CALCULATOR_APP_PACKAGE);
break;
case LAUNCH_OVERVIEW:
kqs.moveFocusBackward().moveFocusBackward().launchFocusedOverviewTask();
break;
default:
throw new IllegalStateException("Cannot run test case: " + testCase);
}
}
}
@@ -42,7 +42,8 @@ import java.util.stream.Collectors;
/**
* Operations on AllApps opened from Home. Also a parent for All Apps opened from Overview.
*/
public abstract class AllApps extends LauncherInstrumentation.VisibleContainer {
public abstract class AllApps extends LauncherInstrumentation.VisibleContainer
implements KeyboardQuickSwitchSource {
// Defer updates flag used to defer all apps updates by a test's request.
private static final int DEFER_UPDATES_TEST = 1 << 1;
@@ -65,6 +66,16 @@ public abstract class AllApps extends LauncherInstrumentation.VisibleContainer {
.getInt(TestProtocol.TEST_INFO_RESPONSE_FIELD);
}
@Override
public LauncherInstrumentation getLauncher() {
return mLauncher;
}
@Override
public LauncherInstrumentation.ContainerType getStartingContainerType() {
return getContainerType();
}
private boolean hasClickableIcon(UiObject2 allAppsContainer, UiObject2 appListRecycler,
BySelector appIconSelector, int displayBottom) {
final UiObject2 icon;
@@ -39,7 +39,8 @@ import java.util.regex.Pattern;
* Indicates the base state with a UI other than Overview running as foreground. It can also
* indicate Launcher as long as Launcher is not in Overview state.
*/
public abstract class Background extends LauncherInstrumentation.VisibleContainer {
public abstract class Background extends LauncherInstrumentation.VisibleContainer
implements KeyboardQuickSwitchSource {
private static final int ZERO_BUTTON_SWIPE_UP_GESTURE_DURATION = 500;
private static final Pattern SQUARE_BUTTON_EVENT = Pattern.compile("onOverviewToggle");
@@ -47,6 +48,16 @@ public abstract class Background extends LauncherInstrumentation.VisibleContaine
super(launcher);
}
@Override
public LauncherInstrumentation getLauncher() {
return mLauncher;
}
@Override
public LauncherInstrumentation.ContainerType getStartingContainerType() {
return getContainerType();
}
/**
* Swipes up or presses the square button to switch to Overview.
* Returns the base overview, which can be either in Launcher or the fallback recents.
@@ -62,4 +62,9 @@ public abstract class Home extends Background {
protected boolean zeroButtonToOverviewGestureStateTransitionWhileHolding() {
return true;
}
@Override
public boolean isHomeState() {
return true;
}
}
@@ -113,4 +113,9 @@ public class HomeAllApps extends AllApps {
protected void verifyVisibleContainerOnDismiss() {
mLauncher.getWorkspace();
}
@Override
public boolean isHomeState() {
return true;
}
}
@@ -0,0 +1,212 @@
/*
* Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.launcher3.tapl;
import static com.android.launcher3.tapl.LauncherInstrumentation.KEYBOARD_QUICK_SWITCH_RES_ID;
import android.view.KeyEvent;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.android.launcher3.testing.shared.TestProtocol;
import java.util.regex.Pattern;
/**
* Operations on the Keyboard Quick Switch View
*/
public final class KeyboardQuickSwitch {
private static final Pattern EVENT_ALT_TAB_DOWN = Pattern.compile(
"KeyboardQuickSwitchView key event: KeyEvent.*?action=ACTION_DOWN.*?keyCode=KEYCODE_TAB"
+ ".*?metaState=META_ALT_ON");
private static final Pattern EVENT_ALT_TAB_UP = Pattern.compile(
"KeyboardQuickSwitchView key event: KeyEvent.*?action=ACTION_UP.*?keyCode=KEYCODE_TAB"
+ ".*?metaState=META_ALT_ON");
private static final Pattern EVENT_ALT_SHIFT_TAB_DOWN = Pattern.compile(
"KeyboardQuickSwitchView key event: KeyEvent.*?action=ACTION_DOWN.*?keyCode=KEYCODE_TAB"
+ ".*?metaState=META_ALT_ON|META_SHIFT_ON");
private static final Pattern EVENT_ALT_SHIFT_TAB_UP = Pattern.compile(
"KeyboardQuickSwitchView key event: KeyEvent.*?action=ACTION_UP.*?keyCode=KEYCODE_TAB"
+ ".*?metaState=META_ALT_ON|META_SHIFT_ON");
private static final Pattern EVENT_ALT_ESC_DOWN = Pattern.compile(
"KeyboardQuickSwitchView key event: KeyEvent.*?action=ACTION_DOWN"
+ ".*?keyCode=KEYCODE_ESCAPE.*?metaState=META_ALT_ON");
private static final Pattern EVENT_ALT_ESC_UP = Pattern.compile(
"KeyboardQuickSwitchView key event: KeyEvent.*?action=ACTION_UP"
+ ".*?keyCode=KEYCODE_ESCAPE.*?metaState=META_ALT_ON");
private static final Pattern EVENT_ALT_LEFT_UP = Pattern.compile(
"Key event: KeyEvent.*?action=ACTION_UP"
+ ".*?keyCode=KEYCODE_ALT_LEFT");
private final LauncherInstrumentation mLauncher;
private final LauncherInstrumentation.ContainerType mStartingContainerType;
private final boolean mExpectHomeKeyEventsOnDismiss;
KeyboardQuickSwitch(
LauncherInstrumentation launcher,
LauncherInstrumentation.ContainerType startingContainerType,
boolean expectHomeKeyEventsOnDismiss) {
mLauncher = launcher;
mStartingContainerType = startingContainerType;
mExpectHomeKeyEventsOnDismiss = expectHomeKeyEventsOnDismiss;
}
/**
* Focuses the next task in the Keyboard quick switch view.
* <p>
* Tasks are ordered left-to-right in LTR, and vice versa in RLT, in a carousel.
* <ul>
* <li>If no task has been focused yet, and there is only one task, then that task will be
* focused</li>
* <li>If no task has been focused yet, and there are two or more tasks, then the second
* task will be focused</li>
* <li>If the currently-focused task is at the end of the list, the first task will be
* focused</li>
* </ul>
*/
public KeyboardQuickSwitch moveFocusForward() {
try (LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer(
"want to move keyboard quick switch focus forward")) {
mLauncher.waitForLauncherObject(KEYBOARD_QUICK_SWITCH_RES_ID);
try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck()) {
mLauncher.expectEvent(TestProtocol.SEQUENCE_MAIN, EVENT_ALT_TAB_DOWN);
mLauncher.expectEvent(TestProtocol.SEQUENCE_MAIN, EVENT_ALT_TAB_UP);
mLauncher.assertTrue("Failed to press alt+tab",
mLauncher.getDevice().pressKeyCode(
KeyEvent.KEYCODE_TAB, KeyEvent.META_ALT_ON));
try (LauncherInstrumentation.Closable c2 = mLauncher.addContextLayer(
"pressed alt+tab")) {
mLauncher.waitForLauncherObject(KEYBOARD_QUICK_SWITCH_RES_ID);
return this;
}
}
}
}
/**
* Focuses the next task in the Keyboard quick switch view.
* <p>
* Tasks are ordered left-to-right in LTR, and vice versa in RLT, in a carousel.
* <ul>
* <li>If no task has been focused yet, and there is only one task, then that task will be
* focused</li>
* <li>If no task has been focused yet, and there are two or more tasks, then the second
* task will be focused</li>
* <li>If the currently-focused task is at the start of the list, the last task will be
* focused</li>
* </ul>
*/
public KeyboardQuickSwitch moveFocusBackward() {
try (LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer(
"want to move keyboard quick switch focus backward")) {
mLauncher.waitForLauncherObject(KEYBOARD_QUICK_SWITCH_RES_ID);
try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck()) {
mLauncher.expectEvent(TestProtocol.SEQUENCE_MAIN, EVENT_ALT_SHIFT_TAB_DOWN);
mLauncher.expectEvent(TestProtocol.SEQUENCE_MAIN, EVENT_ALT_SHIFT_TAB_UP);
mLauncher.assertTrue("Failed to press alt+shift+tab",
mLauncher.getDevice().pressKeyCode(
KeyEvent.KEYCODE_TAB,
KeyEvent.META_ALT_ON | KeyEvent.META_SHIFT_ON));
try (LauncherInstrumentation.Closable c2 = mLauncher.addContextLayer(
"pressed alt+shift+tab")) {
mLauncher.waitForLauncherObject(KEYBOARD_QUICK_SWITCH_RES_ID);
return this;
}
}
}
}
/**
* Dismisses the Keyboard Quick Switch view without launching the focused task.
* <p>
* The device will return to the same state it started in before displaying the Keyboard Quick
* Switch view.
*/
public void dismiss() {
try (LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer(
"want to dismiss keyboard quick switch view")) {
mLauncher.waitForLauncherObject(KEYBOARD_QUICK_SWITCH_RES_ID);
try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck()) {
mLauncher.expectEvent(TestProtocol.SEQUENCE_MAIN, EVENT_ALT_ESC_DOWN);
mLauncher.expectEvent(TestProtocol.SEQUENCE_MAIN, EVENT_ALT_ESC_UP);
mLauncher.assertTrue("Failed to press alt+tab",
mLauncher.getDevice().pressKeyCode(
KeyEvent.KEYCODE_ESCAPE, KeyEvent.META_ALT_ON));
try (LauncherInstrumentation.Closable c2 = mLauncher.addContextLayer(
"pressed alt+esc")) {
mLauncher.waitUntilLauncherObjectGone(KEYBOARD_QUICK_SWITCH_RES_ID);
if (mExpectHomeKeyEventsOnDismiss) {
mLauncher.expectEvent(TestProtocol.SEQUENCE_MAIN, EVENT_ALT_LEFT_UP);
}
mLauncher.unpressKeyCode(KeyEvent.KEYCODE_ALT_LEFT, 0);
// Verify the final state is the same as the initial state
mLauncher.verifyContainerType(mStartingContainerType);
}
}
}
}
/**
* Launches the currently-focused app task.
* <p>
* This method should only be used if the focused task is for a recent running app, otherwise
* use {@link #launchFocusedOverviewTask()}.
*
* @param expectedPackageName the package name of the expected launched app
*/
public LaunchedAppState launchFocusedAppTask(@NonNull String expectedPackageName) {
return (LaunchedAppState) launchFocusedTask(expectedPackageName);
}
/**
* Launches the currently-focused overview task.
* <p>
* This method only should be used if the focused task is for overview, otherwise use
* {@link #launchFocusedAppTask(String)}.
*/
public Overview launchFocusedOverviewTask() {
return (Overview) launchFocusedTask(null);
}
private LauncherInstrumentation.VisibleContainer launchFocusedTask(
@Nullable String expectedPackageName) {
try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
"want to launch focused task: "
+ (expectedPackageName == null ? "Overview" : expectedPackageName))) {
mLauncher.unpressKeyCode(KeyEvent.KEYCODE_ALT_LEFT, 0);
mLauncher.waitUntilLauncherObjectGone(KEYBOARD_QUICK_SWITCH_RES_ID);
if (expectedPackageName != null) {
mLauncher.assertAppLaunched(expectedPackageName);
return mLauncher.getLaunchedAppState();
} else {
return mLauncher.getOverview();
}
}
}
}
@@ -0,0 +1,57 @@
/*
* Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.launcher3.tapl;
import static com.android.launcher3.tapl.LauncherInstrumentation.KEYBOARD_QUICK_SWITCH_RES_ID;
import android.view.KeyEvent;
/**
* {@link com.android.launcher3.tapl.LauncherInstrumentation.VisibleContainer} that can be used to
* show the keyboard quick switch view.
*/
interface KeyboardQuickSwitchSource {
/**
* Shows the Keyboard Quick Switch view.
*/
default KeyboardQuickSwitch showQuickSwitchView() {
LauncherInstrumentation launcher = getLauncher();
try (LauncherInstrumentation.Closable c1 = launcher.addContextLayer(
"want to show keyboard quick switch object")) {
launcher.pressAndHoldKeyCode(KeyEvent.KEYCODE_TAB, KeyEvent.META_ALT_LEFT_ON);
try (LauncherInstrumentation.Closable c2 = launcher.addContextLayer(
"press and held alt+tab")) {
launcher.waitForLauncherObject(KEYBOARD_QUICK_SWITCH_RES_ID);
launcher.unpressKeyCode(KeyEvent.KEYCODE_TAB, 0);
return new KeyboardQuickSwitch(
launcher, getStartingContainerType(), isHomeState());
}
}
}
/** This method requires public access, however should not be called in tests. */
LauncherInstrumentation getLauncher();
/** This method requires public access, however should not be called in tests. */
LauncherInstrumentation.ContainerType getStartingContainerType();
/** This method requires public access, however should not be called in tests. */
boolean isHomeState();
}
@@ -20,15 +20,10 @@ import static android.view.accessibility.AccessibilityEvent.TYPE_WINDOW_STATE_CH
import static com.android.launcher3.testing.shared.TestProtocol.SPRING_LOADED_STATE_ORDINAL;
import android.app.UiAutomation;
import android.graphics.Point;
import android.view.MotionEvent;
import android.view.accessibility.AccessibilityEvent;
import androidx.test.uiautomator.By;
import androidx.test.uiautomator.BySelector;
import androidx.test.uiautomator.UiObject2;
import androidx.test.uiautomator.Until;
import com.android.launcher3.testing.shared.TestProtocol;
@@ -57,7 +52,19 @@ public abstract class Launchable {
*/
public LaunchedAppState launch(String expectedPackageName) {
try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck()) {
return launch(By.pkg(expectedPackageName));
try (LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer(
"want to launch an app from " + launchableType())) {
LauncherInstrumentation.log("Launchable.launch before click "
+ mObject.getVisibleCenter() + " in "
+ mLauncher.getVisibleBounds(mObject));
mLauncher.clickLauncherObject(mObject);
try (LauncherInstrumentation.Closable c2 = mLauncher.addContextLayer("clicked")) {
expectActivityStartEvents();
return mLauncher.assertAppLaunched(expectedPackageName);
}
}
}
}
@@ -65,21 +72,6 @@ public abstract class Launchable {
protected abstract String launchableType();
private LaunchedAppState launch(BySelector selector) {
try (LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer(
"want to launch an app from " + launchableType())) {
LauncherInstrumentation.log("Launchable.launch before click "
+ mObject.getVisibleCenter() + " in " + mLauncher.getVisibleBounds(mObject));
mLauncher.clickLauncherObject(mObject);
try (LauncherInstrumentation.Closable c2 = mLauncher.addContextLayer("clicked")) {
expectActivityStartEvents();
return assertAppLaunched(selector);
}
}
}
/**
* Clicks a launcher object to initiate splitscreen, where the selected app will be one of two
* apps running on the screen. Should be called when Launcher is in a "split staging" state
@@ -107,14 +99,6 @@ public abstract class Launchable {
}
}
protected LaunchedAppState assertAppLaunched(BySelector selector) {
mLauncher.assertTrue(
"App didn't start: (" + selector + ")",
mLauncher.getDevice().wait(Until.hasObject(selector),
LauncherInstrumentation.WAIT_TIME_MS));
return new LaunchedAppState(mLauncher);
}
Point startDrag(long downTime, Runnable expectLongClickEvents, boolean runToSpringLoadedState) {
final Point iconCenter = getObject().getVisibleCenter();
final Point dragStartCenter = new Point(iconCenter.x,
@@ -34,7 +34,6 @@ import android.view.InputDevice;
import android.view.MotionEvent;
import android.view.ViewConfiguration;
import androidx.test.uiautomator.By;
import androidx.test.uiautomator.Condition;
import androidx.test.uiautomator.UiDevice;
@@ -72,6 +71,11 @@ public final class LaunchedAppState extends Background {
return LauncherInstrumentation.ContainerType.LAUNCHED_APP;
}
@Override
public boolean isHomeState() {
return false;
}
/**
* Returns the taskbar.
*
@@ -200,8 +204,8 @@ public final class LaunchedAppState extends Background {
try (LauncherInstrumentation.Closable c4 = launcher.addContextLayer(
"dropped item")) {
launchable.assertAppLaunched(By.pkg(expectedNewPackageName));
launchable.assertAppLaunched(By.pkg(expectedExistingPackageName));
launcher.assertAppLaunched(expectedNewPackageName);
launcher.assertAppLaunched(expectedExistingPackageName);
}
}
}
@@ -20,7 +20,10 @@ import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
import static android.content.pm.PackageManager.DONT_KILL_APP;
import static android.content.pm.PackageManager.MATCH_ALL;
import static android.content.pm.PackageManager.MATCH_DISABLED_COMPONENTS;
import static android.view.KeyEvent.ACTION_DOWN;
import static android.view.MotionEvent.ACTION_UP;
import static android.view.MotionEvent.AXIS_GESTURE_SWIPE_FINGER_COUNT;
import static com.android.launcher3.tapl.Folder.FOLDER_CONTENT_RES_ID;
import static com.android.launcher3.tapl.TestHelpers.getOverviewPackageName;
import static com.android.launcher3.testing.shared.TestProtocol.NORMAL_STATE_ORDINAL;
@@ -49,6 +52,9 @@ import android.os.SystemClock;
import android.text.TextUtils;
import android.util.Log;
import android.view.InputDevice;
import android.view.InputEvent;
import android.view.KeyCharacterMap;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.ViewConfiguration;
import android.view.WindowManager;
@@ -170,6 +176,7 @@ public final class LauncherInstrumentation {
private static final String OPEN_FOLDER_RES_ID = "folder_content";
static final String TASKBAR_RES_ID = "taskbar_view";
private static final String SPLIT_PLACEHOLDER_RES_ID = "split_placeholder";
static final String KEYBOARD_QUICK_SWITCH_RES_ID = "keyboard_quick_switch_view";
public static final int WAIT_TIME_MS = 30000;
static final long DEFAULT_POLL_INTERVAL = 1000;
private static final String SYSTEMUI_PACKAGE = "com.android.systemui";
@@ -755,7 +762,7 @@ public final class LauncherInstrumentation {
return isTablet() ? getLauncherPackageName() : SYSTEMUI_PACKAGE;
}
private UiObject2 verifyContainerType(ContainerType containerType) {
UiObject2 verifyContainerType(ContainerType containerType) {
waitForLauncherInitialized();
if (mExpectedRotationCheckEnabled && mExpectedRotation != null) {
@@ -784,6 +791,7 @@ public final class LauncherInstrumentation {
waitUntilLauncherObjectGone(WIDGETS_RES_ID);
waitUntilSystemLauncherObjectGone(OVERVIEW_RES_ID);
waitUntilSystemLauncherObjectGone(SPLIT_PLACEHOLDER_RES_ID);
waitUntilLauncherObjectGone(KEYBOARD_QUICK_SWITCH_RES_ID);
if (is3PLauncher() && isTablet()) {
waitForSystemLauncherObject(TASKBAR_RES_ID);
@@ -798,6 +806,7 @@ public final class LauncherInstrumentation {
waitUntilLauncherObjectGone(APPS_RES_ID);
waitUntilSystemLauncherObjectGone(OVERVIEW_RES_ID);
waitUntilSystemLauncherObjectGone(SPLIT_PLACEHOLDER_RES_ID);
waitUntilLauncherObjectGone(KEYBOARD_QUICK_SWITCH_RES_ID);
if (is3PLauncher() && isTablet()) {
waitForSystemLauncherObject(TASKBAR_RES_ID);
@@ -813,6 +822,7 @@ public final class LauncherInstrumentation {
waitUntilSystemLauncherObjectGone(OVERVIEW_RES_ID);
waitUntilSystemLauncherObjectGone(TASKBAR_RES_ID);
waitUntilSystemLauncherObjectGone(SPLIT_PLACEHOLDER_RES_ID);
waitUntilLauncherObjectGone(KEYBOARD_QUICK_SWITCH_RES_ID);
return waitForLauncherObject(APPS_RES_ID);
}
@@ -821,6 +831,7 @@ public final class LauncherInstrumentation {
waitUntilLauncherObjectGone(WIDGETS_RES_ID);
waitUntilSystemLauncherObjectGone(OVERVIEW_RES_ID);
waitUntilSystemLauncherObjectGone(SPLIT_PLACEHOLDER_RES_ID);
waitUntilLauncherObjectGone(KEYBOARD_QUICK_SWITCH_RES_ID);
if (is3PLauncher() && isTablet()) {
waitForSystemLauncherObject(TASKBAR_RES_ID);
@@ -841,6 +852,7 @@ public final class LauncherInstrumentation {
waitUntilSystemLauncherObjectGone(TASKBAR_RES_ID);
}
waitUntilSystemLauncherObjectGone(SPLIT_PLACEHOLDER_RES_ID);
waitUntilLauncherObjectGone(KEYBOARD_QUICK_SWITCH_RES_ID);
return waitForSystemLauncherObject(OVERVIEW_RES_ID);
}
@@ -855,6 +867,7 @@ public final class LauncherInstrumentation {
}
waitForSystemLauncherObject(SPLIT_PLACEHOLDER_RES_ID);
waitUntilLauncherObjectGone(KEYBOARD_QUICK_SWITCH_RES_ID);
return waitForSystemLauncherObject(OVERVIEW_RES_ID);
}
case LAUNCHED_APP: {
@@ -863,6 +876,7 @@ public final class LauncherInstrumentation {
waitUntilLauncherObjectGone(WIDGETS_RES_ID);
waitUntilSystemLauncherObjectGone(OVERVIEW_RES_ID);
waitUntilSystemLauncherObjectGone(SPLIT_PLACEHOLDER_RES_ID);
waitUntilLauncherObjectGone(KEYBOARD_QUICK_SWITCH_RES_ID);
if (mIgnoreTaskbarVisibility) {
return null;
@@ -1170,6 +1184,14 @@ public final class LauncherInstrumentation {
}
}
LaunchedAppState assertAppLaunched(@NonNull String expectedPackageName) {
BySelector packageSelector = By.pkg(expectedPackageName);
assertTrue("App didn't start: (" + packageSelector + ")",
mDevice.wait(Until.hasObject(packageSelector),
LauncherInstrumentation.WAIT_TIME_MS));
return new LaunchedAppState(this);
}
void waitUntilLauncherObjectGone(String resId) {
waitUntilGoneBySelector(getLauncherObjectSelector(resId));
}
@@ -1735,6 +1757,12 @@ public final class LauncherInstrumentation {
InputDevice.SOURCE_TOUCHSCREEN);
}
private void injectEvent(InputEvent event) {
assertTrue("injectInputEvent failed: event=" + event,
mInstrumentation.getUiAutomation().injectInputEvent(event, true, false));
event.recycle();
}
public void sendPointer(long downTime, long currentTime, int action, Point point,
GestureScope gestureScope, int source) {
final boolean hasTIS = hasTIS();
@@ -1772,9 +1800,39 @@ public final class LauncherInstrumentation {
|| action == MotionEvent.ACTION_BUTTON_RELEASE) {
event.setActionButton(MotionEvent.BUTTON_PRIMARY);
}
assertTrue("injectInputEvent failed",
mInstrumentation.getUiAutomation().injectInputEvent(event, true, false));
event.recycle();
injectEvent(event);
}
private KeyEvent createKeyEvent(int keyCode, int metaState, boolean actionDown) {
long eventTime = SystemClock.uptimeMillis();
return KeyEvent.obtain(
eventTime,
eventTime,
actionDown ? ACTION_DOWN : ACTION_UP,
keyCode,
/* repeat= */ 0,
metaState,
KeyCharacterMap.VIRTUAL_KEYBOARD,
/* scancode= */ 0,
/* flags= */ 0,
InputDevice.SOURCE_KEYBOARD,
/* characters =*/ null);
}
/**
* Sends a {@link KeyEvent} with {@link ACTION_DOWN} for the given key codes without sending
* a {@link KeyEvent} with {@link ACTION_UP}.
*/
public void pressAndHoldKeyCode(int keyCode, int metaState) {
injectEvent(createKeyEvent(keyCode, metaState, true));
}
/**
* Sends a {@link KeyEvent} with {@link ACTION_UP} for the given key codes.
*/
public void unpressKeyCode(int keyCode, int metaState) {
injectEvent(createKeyEvent(keyCode, metaState, false));
}
public long movePointer(long downTime, long startTime, long duration, Point from, Point to,
@@ -15,7 +15,7 @@
*/
package com.android.launcher3.tapl;
/** Launchable that can serve as a source for dragging and dropping to splitscreen. */
/** {@link Launchable} that can serve as a source for dragging and dropping to splitscreen. */
interface SplitscreenDragSource {
/**
@@ -35,5 +35,6 @@ interface SplitscreenDragSource {
}
}
/** This method requires public access, however should not be called in tests. */
Launchable getLaunchable();
}
@@ -73,4 +73,9 @@ public class TaskbarAllApps extends AllApps {
protected void verifyVisibleContainerOnDismiss() {
mLauncher.getLaunchedAppState().assertTaskbarVisible();
}
@Override
public boolean isHomeState() {
return false;
}
}
@@ -34,7 +34,8 @@ import java.util.Collection;
/**
* All widgets container.
*/
public final class Widgets extends LauncherInstrumentation.VisibleContainer {
public final class Widgets extends LauncherInstrumentation.VisibleContainer
implements KeyboardQuickSwitchSource {
private static final int FLING_STEPS = 10;
private static final int SCROLL_ATTEMPTS = 60;
@@ -43,6 +44,21 @@ public final class Widgets extends LauncherInstrumentation.VisibleContainer {
verifyActiveContainer();
}
@Override
public LauncherInstrumentation getLauncher() {
return mLauncher;
}
@Override
public LauncherInstrumentation.ContainerType getStartingContainerType() {
return getContainerType();
}
@Override
public boolean isHomeState() {
return true;
}
/**
* Flings forward (down) and waits the fling's end.
*/
@@ -19,7 +19,7 @@ import android.graphics.Point;
import java.util.function.Supplier;
/** Launchable that can serve as a source for dragging and dropping to the workspace. */
/** {@link Launchable} that can serve as a source for dragging and dropping to the workspace. */
interface WorkspaceDragSource {
/**