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:
@@ -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 {
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user