diff options
author | TreeHugger Robot <treehugger-gerrit@google.com> | 2018-07-24 19:39:54 +0000 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2018-07-24 19:39:54 +0000 |
commit | 1143469a7931b7fa4f708e1f1e663e9f0acf7d27 (patch) | |
tree | 750bca3cb26ba30973a30e99a408a022baf34972 /tests | |
parent | b70e1addb1b7d4c747b0851b7005135ada347519 (diff) | |
parent | 2ce6a13f6096ed5e08b252e7e53255ef1027f65e (diff) | |
download | android_packages_apps_Trebuchet-1143469a7931b7fa4f708e1f1e663e9f0acf7d27.tar.gz android_packages_apps_Trebuchet-1143469a7931b7fa4f708e1f1e663e9f0acf7d27.tar.bz2 android_packages_apps_Trebuchet-1143469a7931b7fa4f708e1f1e663e9f0acf7d27.zip |
Merge "Tapl library" into ub-launcher3-master
Diffstat (limited to 'tests')
-rw-r--r-- | tests/tapl/com/android/launcher3/tapl/AllApps.java (renamed from tests/tapl/com/android/launcher3/tapl/AllAppsFromHome.java) | 58 | ||||
-rw-r--r-- | tests/tapl/com/android/launcher3/tapl/AllAppsFromOverview.java | 25 | ||||
-rw-r--r-- | tests/tapl/com/android/launcher3/tapl/AppIcon.java | 16 | ||||
-rw-r--r-- | tests/tapl/com/android/launcher3/tapl/Background.java | 32 | ||||
-rw-r--r-- | tests/tapl/com/android/launcher3/tapl/Home.java | 152 | ||||
-rw-r--r-- | tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java (renamed from tests/tapl/com/android/launcher3/tapl/Launcher.java) | 225 | ||||
-rw-r--r-- | tests/tapl/com/android/launcher3/tapl/Overview.java | 43 | ||||
-rw-r--r-- | tests/tapl/com/android/launcher3/tapl/OverviewTask.java | 31 | ||||
-rw-r--r-- | tests/tapl/com/android/launcher3/tapl/Widgets.java | 33 | ||||
-rw-r--r-- | tests/tapl/com/android/launcher3/tapl/Workspace.java | 155 |
10 files changed, 422 insertions, 348 deletions
diff --git a/tests/tapl/com/android/launcher3/tapl/AllAppsFromHome.java b/tests/tapl/com/android/launcher3/tapl/AllApps.java index 02f8183c8..d849e2d80 100644 --- a/tests/tapl/com/android/launcher3/tapl/AllAppsFromHome.java +++ b/tests/tapl/com/android/launcher3/tapl/AllApps.java @@ -16,36 +16,32 @@ package com.android.launcher3.tapl; +import static org.junit.Assert.assertTrue; + import android.support.annotation.NonNull; import android.support.test.uiautomator.BySelector; import android.support.test.uiautomator.Direction; import android.support.test.uiautomator.UiObject2; /** - * Operations on AllApps opened from Home. + * Operations on AllApps opened from Home. Also a parent for All Apps opened from Overview. */ -public final class AllAppsFromHome { +public class AllApps extends LauncherInstrumentation.VisibleContainer { private static final int MAX_SCROLL_ATTEMPTS = 40; private static final int MIN_INTERACT_SIZE = 100; private static final int FLING_SPEED = 12000; - private final Launcher mLauncher; private final int mHeight; - AllAppsFromHome(Launcher launcher) { - mLauncher = launcher; - final UiObject2 allAppsContainer = assertState(); + AllApps(LauncherInstrumentation launcher) { + super(launcher); + final UiObject2 allAppsContainer = verifyActiveContainer(); mHeight = allAppsContainer.getVisibleBounds().height(); } - /** - * Asserts that we are in all apps. - * - * @return All apps container. - */ - @NonNull - private UiObject2 assertState() { - return mLauncher.assertState(Launcher.State.ALL_APPS); + @Override + protected LauncherInstrumentation.ContainerType getContainerType() { + return LauncherInstrumentation.ContainerType.ALL_APPS; } /** @@ -57,41 +53,45 @@ public final class AllAppsFromHome { */ @NonNull public AppIcon getAppIcon(String appName) { - final UiObject2 allAppsContainer = assertState(); + final UiObject2 allAppsContainer = verifyActiveContainer(); final BySelector appIconSelector = AppIcon.getAppIconSelector(appName); if (!allAppsContainer.hasObject(appIconSelector)) { scrollBackToBeginning(); int attempts = 0; while (!allAppsContainer.hasObject(appIconSelector) && allAppsContainer.scroll(Direction.DOWN, 0.8f)) { - mLauncher.assertTrue("Exceeded max scroll attempts: " + MAX_SCROLL_ATTEMPTS, + assertTrue("Exceeded max scroll attempts: " + MAX_SCROLL_ATTEMPTS, ++attempts <= MAX_SCROLL_ATTEMPTS); - assertState(); + verifyActiveContainer(); } } - assertState(); + verifyActiveContainer(); final UiObject2 appIcon = mLauncher.getObjectInContainer(allAppsContainer, appIconSelector); ensureIconVisible(appIcon, allAppsContainer); return new AppIcon(mLauncher, appIcon); } + protected int getBottomMarginForSwipeUp() { + return 5; + } + private void scrollBackToBeginning() { - final UiObject2 allAppsContainer = assertState(); + final UiObject2 allAppsContainer = verifyActiveContainer(); int attempts = 0; - allAppsContainer.setGestureMargins(5, 500, 5, 5); + allAppsContainer.setGestureMargins(5, 600, 5, getBottomMarginForSwipeUp()); while (allAppsContainer.scroll(Direction.UP, 0.5f)) { mLauncher.waitForIdle(); - assertState(); + verifyActiveContainer(); - mLauncher.assertTrue("Exceeded max scroll attempts: " + MAX_SCROLL_ATTEMPTS, + assertTrue("Exceeded max scroll attempts: " + MAX_SCROLL_ATTEMPTS, ++attempts <= MAX_SCROLL_ATTEMPTS); } mLauncher.waitForIdle(); - assertState(); + verifyActiveContainer(); } private void ensureIconVisible(UiObject2 appIcon, UiObject2 allAppsContainer) { @@ -102,7 +102,7 @@ public final class AllAppsFromHome { final float pct = Math.max(((float) (MIN_INTERACT_SIZE - appHeight)) / mHeight, 0.2f); allAppsContainer.scroll(Direction.DOWN, pct); mLauncher.waitForIdle(); - assertState(); + verifyActiveContainer(); } } @@ -110,22 +110,22 @@ public final class AllAppsFromHome { * Flings forward (down) and waits the fling's end. */ public void flingForward() { - final UiObject2 allAppsContainer = assertState(); + final UiObject2 allAppsContainer = verifyActiveContainer(); // Start the gesture in the center to avoid starting at elements near the top. allAppsContainer.setGestureMargins(0, 0, 0, mHeight / 2); allAppsContainer.fling(Direction.DOWN, FLING_SPEED); - assertState(); + verifyActiveContainer(); } /** * Flings backward (up) and waits the fling's end. */ public void flingBackward() { - final UiObject2 allAppsContainer = assertState(); + final UiObject2 allAppsContainer = verifyActiveContainer(); // Start the gesture in the center, for symmetry with forward. allAppsContainer.setGestureMargins(0, mHeight / 2, 0, 0); allAppsContainer.fling(Direction.UP, FLING_SPEED); - assertState(); + verifyActiveContainer(); } /** @@ -137,6 +137,6 @@ public final class AllAppsFromHome { @Deprecated @NonNull public UiObject2 getObjectDeprecated() { - return assertState(); + return verifyActiveContainer(); } } diff --git a/tests/tapl/com/android/launcher3/tapl/AllAppsFromOverview.java b/tests/tapl/com/android/launcher3/tapl/AllAppsFromOverview.java index cba708621..bc0dfc646 100644 --- a/tests/tapl/com/android/launcher3/tapl/AllAppsFromOverview.java +++ b/tests/tapl/com/android/launcher3/tapl/AllAppsFromOverview.java @@ -22,24 +22,17 @@ import android.support.test.uiautomator.UiObject2; /** * Operations on AllApps opened from Overview. - * Scroll gestures that are OK for {@link AllAppsFromHome} may close it, so they are not supported. */ -public final class AllAppsFromOverview { - private final Launcher mLauncher; +public final class AllAppsFromOverview extends AllApps { - AllAppsFromOverview(Launcher launcher) { - mLauncher = launcher; - assertState(); + AllAppsFromOverview(LauncherInstrumentation launcher) { + super(launcher); + verifyActiveContainer(); } - /** - * Asserts that we are in all apps. - * - * @return All apps container. - */ - @NonNull - private UiObject2 assertState() { - return mLauncher.assertState(Launcher.State.ALL_APPS); + @Override + protected int getBottomMarginForSwipeUp() { + return 600; } /** @@ -49,13 +42,13 @@ public final class AllAppsFromOverview { */ @NonNull public Overview switchBackToOverview() { - final UiObject2 allAppsContainer = assertState(); + final UiObject2 allAppsContainer = verifyActiveContainer(); // Swipe from the search box to the bottom. final UiObject2 qsb = mLauncher.waitForObjectInContainer( allAppsContainer, "search_container_all_apps"); final Point start = qsb.getVisibleCenter(); final int endY = (int) (mLauncher.getDevice().getDisplayHeight() * 0.6); - mLauncher.swipe(start.x, start.y, start.x, endY, (endY - start.y) / 100); // 100 px/step + mLauncher.swipe(start.x, start.y, start.x, endY); return new Overview(mLauncher); } diff --git a/tests/tapl/com/android/launcher3/tapl/AppIcon.java b/tests/tapl/com/android/launcher3/tapl/AppIcon.java index 73a74f2dd..721f7a8ef 100644 --- a/tests/tapl/com/android/launcher3/tapl/AppIcon.java +++ b/tests/tapl/com/android/launcher3/tapl/AppIcon.java @@ -16,6 +16,8 @@ package com.android.launcher3.tapl; +import static org.junit.Assert.assertTrue; + import android.support.test.uiautomator.By; import android.support.test.uiautomator.BySelector; import android.support.test.uiautomator.UiObject2; @@ -26,25 +28,25 @@ import android.widget.TextView; * App icon, whether in all apps or in workspace/ */ public final class AppIcon { - private final Launcher mLauncher; + private final LauncherInstrumentation mLauncher; private final UiObject2 mIcon; - AppIcon(Launcher launcher, UiObject2 icon) { + AppIcon(LauncherInstrumentation launcher, UiObject2 icon) { mLauncher = launcher; mIcon = icon; } static BySelector getAppIconSelector(String appName) { - return By.clazz(TextView.class).text(appName).pkg(Launcher.LAUNCHER_PKG); + return By.clazz(TextView.class).text(appName).pkg(LauncherInstrumentation.LAUNCHER_PKG); } /** * Clicks the icon to launch its app. */ - public void launch() { - mLauncher.assertTrue("Launching an app didn't open a new window: " + mIcon.getText(), - mIcon.clickAndWait(Until.newWindow(), Launcher.APP_LAUNCH_TIMEOUT_MS)); - mLauncher.assertState(Launcher.State.BACKGROUND); + public Background launch() { + assertTrue("Launching an app didn't open a new window: " + mIcon.getText(), + mIcon.clickAndWait(Until.newWindow(), LauncherInstrumentation.WAIT_TIME_MS)); + return new Background(mLauncher); } UiObject2 getIcon() { diff --git a/tests/tapl/com/android/launcher3/tapl/Background.java b/tests/tapl/com/android/launcher3/tapl/Background.java new file mode 100644 index 000000000..1aef9791d --- /dev/null +++ b/tests/tapl/com/android/launcher3/tapl/Background.java @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2018 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; + +/** + * Operations on a state when Launcher is inactive because some other app is active. + */ +public final class Background extends Home { + + Background(LauncherInstrumentation launcher) { + super(launcher); + } + + @Override + protected LauncherInstrumentation.ContainerType getContainerType() { + return LauncherInstrumentation.ContainerType.BACKGROUND; + } +} diff --git a/tests/tapl/com/android/launcher3/tapl/Home.java b/tests/tapl/com/android/launcher3/tapl/Home.java index 0ec1a644e..436e5ff6b 100644 --- a/tests/tapl/com/android/launcher3/tapl/Home.java +++ b/tests/tapl/com/android/launcher3/tapl/Home.java @@ -16,38 +16,22 @@ package com.android.launcher3.tapl; -import static junit.framework.TestCase.assertTrue; - -import android.graphics.Point; import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.support.test.uiautomator.Direction; import android.support.test.uiautomator.UiObject2; -import android.view.KeyEvent; /** * Operations on the home screen. + * + * Launcher can be invoked both when its activity is in the foreground and when it is in the + * background. This class is a parent of the two classes {@link Background} and {@link Workspace} + * that essentially represents these two activity states. Any gestures (e.g., switchToOverview) that + * can be performed in both of these states can be defined here. */ -public final class Home { +public abstract class Home extends LauncherInstrumentation.VisibleContainer { - private final Launcher mLauncher; - private final UiObject2 mHotseat; - private final int ICON_DRAG_SPEED = 2000; - - Home(Launcher launcher) { - mLauncher = launcher; - assertState(); - mHotseat = launcher.waitForLauncherObject("hotseat"); - } - - /** - * Asserts that we are in home. - * - * @return Workspace. - */ - @NonNull - private UiObject2 assertState() { - return mLauncher.assertState(Launcher.State.HOME); + protected Home(LauncherInstrumentation launcher) { + super(launcher); + verifyActiveContainer(); } /** @@ -57,131 +41,19 @@ public final class Home { */ @NonNull public Overview switchToOverview() { - assertState(); + verifyActiveContainer(); if (mLauncher.isSwipeUpEnabled()) { final int height = mLauncher.getDevice().getDisplayHeight(); final UiObject2 navBar = mLauncher.getSystemUiObject("navigation_bar_frame"); - // Swipe from nav bar to 2/3rd down the screen. mLauncher.swipe( navBar.getVisibleBounds().centerX(), navBar.getVisibleBounds().centerY(), - navBar.getVisibleBounds().centerX(), height * 2 / 3, - (navBar.getVisibleBounds().centerY() - height * 2 / 3) / 100); // 100 px/step + navBar.getVisibleBounds().centerX(), height - 300 + ); } else { mLauncher.getSystemUiObject("recent_apps").click(); } return new Overview(mLauncher); } - - /** - * Swipes up to All Apps. - * - * @return the App Apps object. - */ - @NonNull - public AllAppsFromHome switchToAllApps() { - assertState(); - if (mLauncher.isSwipeUpEnabled()) { - int midX = mLauncher.getDevice().getDisplayWidth() / 2; - int height = mLauncher.getDevice().getDisplayHeight(); - // Swipe from 6/7ths down the screen to 1/7th down the screen. - mLauncher.swipe( - midX, - height * 6 / 7, - midX, - height / 7, - (height * 2 / 3) / 100); // 100 px/step - } else { - // Swipe from the hotseat to near the top, e.g. 10% of the screen. - final UiObject2 hotseat = mHotseat; - final Point start = hotseat.getVisibleCenter(); - final int endY = (int) (mLauncher.getDevice().getDisplayHeight() * 0.1f); - mLauncher.swipe( - start.x, - start.y, - start.x, - endY, - (start.y - endY) / 100); // 100 px/step - } - - return new AllAppsFromHome(mLauncher); - } - - /** - * Returns an icon for the app, if currently visible. - * - * @param appName name of the app - * @return app icon, if found, null otherwise. - */ - @Nullable - public AppIcon tryGetWorkspaceAppIcon(String appName) { - final UiObject2 workspace = assertState(); - final UiObject2 icon = workspace.findObject(AppIcon.getAppIconSelector(appName)); - return icon != null ? new AppIcon(mLauncher, icon) : null; - } - - /** - * Ensures that workspace is scrollable. If it's not, drags an icon icons from hotseat to the - * second screen. - */ - public void ensureWorkspaceIsScrollable() { - final UiObject2 workspace = assertState(); - if (!isWorkspaceScrollable(workspace)) { - dragIconToNextScreen(getHotseatAppIcon("Messages"), workspace); - } - assertTrue("Home screen workspace didn't become scrollable", - isWorkspaceScrollable(workspace)); - } - - private boolean isWorkspaceScrollable(UiObject2 workspace) { - return workspace.isScrollable(); - } - - @NonNull - private AppIcon getHotseatAppIcon(String appName) { - return new AppIcon(mLauncher, mLauncher.getObjectInContainer( - mHotseat, AppIcon.getAppIconSelector(appName))); - } - - private void dragIconToNextScreen(AppIcon app, UiObject2 workspace) { - final Point dest = new Point( - mLauncher.getDevice().getDisplayWidth(), workspace.getVisibleBounds().centerY()); - app.getIcon().drag(dest, ICON_DRAG_SPEED); - assertState(); - } - - /** - * Flings to get to screens on the right. Waits for scrolling and a possible overscroll - * recoil to complete. - */ - public void flingForward() { - final UiObject2 workspace = assertState(); - workspace.fling(Direction.RIGHT); - mLauncher.waitForIdle(); - assertState(); - } - - /** - * Flings to get to screens on the left. Waits for scrolling and a possible overscroll - * recoil to complete. - */ - public void flingBackward() { - final UiObject2 workspace = assertState(); - workspace.fling(Direction.LEFT); - mLauncher.waitForIdle(); - assertState(); - } - - /** - * Opens widgets container by pressing Ctrl+W. - * - * @return the widgets container. - */ - @NonNull - public Widgets openAllWidgets() { - assertState(); - mLauncher.getDevice().pressKeyCode(KeyEvent.KEYCODE_W, KeyEvent.META_CTRL_ON); - return new Widgets(mLauncher); - } }
\ No newline at end of file diff --git a/tests/tapl/com/android/launcher3/tapl/Launcher.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java index 5201dc8ba..fc32fed2c 100644 --- a/tests/tapl/com/android/launcher3/tapl/Launcher.java +++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java @@ -16,10 +16,13 @@ package com.android.launcher3.tapl; -import static com.android.systemui.shared.system.SettingsCompat.SWIPE_UP_SETTING_NAME; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; +import android.app.ActivityManager; +import android.app.UiAutomation; import android.content.res.Resources; -import android.os.RemoteException; import android.provider.Settings; import android.support.annotation.NonNull; import android.support.annotation.Nullable; @@ -29,50 +32,76 @@ import android.support.test.uiautomator.BySelector; import android.support.test.uiautomator.UiDevice; import android.support.test.uiautomator.UiObject2; import android.support.test.uiautomator.Until; -import android.util.Log; import org.junit.Assert; -import java.io.ByteArrayOutputStream; -import java.io.IOException; +import java.lang.ref.WeakReference; +import java.util.concurrent.TimeoutException; /** * The main tapl object. The only object that can be explicitly constructed by the using code. It * produces all other objects. */ -public final class Launcher { +public final class LauncherInstrumentation { + + // Types for launcher containers that the user is interacting with. "Background" is a + // pseudo-container corresponding to inactive launcher covered by another app. + enum ContainerType { + WORKSPACE, ALL_APPS, OVERVIEW, WIDGETS, BACKGROUND + } + + // Base class for launcher containers. + static abstract class VisibleContainer { + protected final LauncherInstrumentation mLauncher; + + protected VisibleContainer(LauncherInstrumentation launcher) { + mLauncher = launcher; + launcher.setActiveContainer(this); + } + + protected abstract ContainerType getContainerType(); + + /** + * Asserts that the launcher is in the mode matching 'this' object. + * + * @return UI object for the container. + */ + final UiObject2 verifyActiveContainer() { + assertTrue("Attempt to use a stale container", this == sActiveContainer.get()); + return mLauncher.verifyContainerType(getContainerType()); + } + } private static final String WORKSPACE_RES_ID = "workspace"; private static final String APPS_RES_ID = "apps_view"; private static final String OVERVIEW_RES_ID = "overview_panel"; private static final String WIDGETS_RES_ID = "widgets_list_view"; - - enum State {HOME, ALL_APPS, OVERVIEW, WIDGETS, BACKGROUND} - static final String LAUNCHER_PKG = "com.google.android.apps.nexuslauncher"; - static final int APP_LAUNCH_TIMEOUT_MS = 10000; - private static final int UI_OBJECT_WAIT_TIMEOUT_MS = 10000; + static final int WAIT_TIME_MS = 10000; private static final String SWIPE_UP_SETTING_AVAILABLE_RES_NAME = "config_swipe_up_gesture_setting_available"; private static final String SWIPE_UP_ENABLED_DEFAULT_RES_NAME = "config_swipe_up_gesture_default"; private static final String SYSTEMUI_PACKAGE = "com.android.systemui"; - private static final String TAG = "tapl.Launcher"; + + private static WeakReference<VisibleContainer> sActiveContainer = new WeakReference<>(null); + private final UiDevice mDevice; private final boolean mSwipeUpEnabled; /** - * Constructs the root of TAPL hierarchy. You get all other object from it. + * Constructs the root of TAPL hierarchy. You get all other objects from it. */ - public Launcher(UiDevice device) { + public LauncherInstrumentation(UiDevice device) { mDevice = device; final boolean swipeUpEnabledDefault = !getSystemBooleanRes(SWIPE_UP_SETTING_AVAILABLE_RES_NAME) || getSystemBooleanRes(SWIPE_UP_ENABLED_DEFAULT_RES_NAME); mSwipeUpEnabled = Settings.Secure.getInt( InstrumentationRegistry.getTargetContext().getContentResolver(), - SWIPE_UP_SETTING_NAME, + "swipe_up_to_switch_apps_enabled", swipeUpEnabledDefault ? 1 : 0) == 1; + assertTrue("Device must run in a test harness", ActivityManager.isRunningInTestHarness()); } private boolean getSystemBooleanRes(String resName) { @@ -82,59 +111,18 @@ public final class Launcher { return res.getBoolean(resId); } - private void dumpViewHierarchy() { - final ByteArrayOutputStream stream = new ByteArrayOutputStream(); - try { - mDevice.dumpWindowHierarchy(stream); - stream.flush(); - stream.close(); - for (String line : stream.toString().split("\\r?\\n")) { - Log.e(TAG, line.trim()); - } - } catch (IOException e) { - Log.e(TAG, "error dumping XML to logcat", e); - } - } - - void fail(String message) { - dumpViewHierarchy(); - Assert.fail(message); - } - - void assertTrue(String message, boolean condition) { - if (!condition) { - fail(message); - } - } - - void assertNotNull(String message, Object object) { - assertTrue(message, object != null); - } - - private void failEquals(String message, Object actual) { - String formatted = "Values should be different. "; - if (message != null) { - formatted = message + ". "; - } - - formatted += "Actual: " + actual; - fail(formatted); - } - - void assertNotEquals(String message, int unexpected, int actual) { - if (unexpected == actual) { - failEquals(message, actual); - } + void setActiveContainer(VisibleContainer container) { + sActiveContainer = new WeakReference<>(container); } boolean isSwipeUpEnabled() { return mSwipeUpEnabled; } - UiObject2 assertState(State state) { - switch (state) { - case HOME: { - //waitUntilGone(APPS_RES_ID); + private UiObject2 verifyContainerType(ContainerType containerType) { + switch (containerType) { + case WORKSPACE: { + waitUntilGone(APPS_RES_ID); waitUntilGone(OVERVIEW_RES_ID); waitUntilGone(WIDGETS_RES_ID); return waitForLauncherObject(WORKSPACE_RES_ID); @@ -147,13 +135,11 @@ public final class Launcher { } case ALL_APPS: { waitUntilGone(OVERVIEW_RES_ID); - waitUntilGone(WORKSPACE_RES_ID); waitUntilGone(WIDGETS_RES_ID); return waitForLauncherObject(APPS_RES_ID); } case OVERVIEW: { - //waitForLauncherObject(APPS_RES_ID); - waitUntilGone(WORKSPACE_RES_ID); + waitForLauncherObject(APPS_RES_ID); waitUntilGone(WIDGETS_RES_ID); return waitForLauncherObject(OVERVIEW_RES_ID); } @@ -165,30 +151,62 @@ public final class Launcher { return null; } default: - fail("Invalid state: " + state); + fail("Invalid state: " + containerType); return null; } } + private void executeAndWaitForEvent(Runnable command, + UiAutomation.AccessibilityEventFilter eventFilter, String message) { + try { + assertNotNull("executeAndWaitForEvent returned null (this can't happen)", + InstrumentationRegistry.getInstrumentation().getUiAutomation() + .executeAndWaitForEvent( + command, eventFilter, WAIT_TIME_MS)); + } catch (TimeoutException e) { + fail(message); + } + } + /** * Presses nav bar home button. * - * @return the Home object. + * @return the Workspace object. */ - public Home pressHome() { - getSystemUiObject("home").click(); - return getHome(); + public Workspace pressHome() { + // Click home, then wait for any accessibility event, then wait until accessibility events + // stop. + // 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. + executeAndWaitForEvent( + () -> getSystemUiObject("home").click(), + event -> true, + "Pressing Home didn't produce any events"); + mDevice.waitForIdle(); + return getWorkspace(); } /** - * Gets the Home object if the current state is "active home", i.e. workspace. Fails if the + * Gets the Workspace object if the current state is "active home", i.e. workspace. Fails if the * launcher is not in that state. * - * @return Home object. + * @return Workspace object. + */ + @NonNull + public Workspace getWorkspace() { + return new Workspace(this); + } + + /** + * Gets the Workspace object if the current state is "background home", i.e. some other app is + * active. Fails if the launcher is not in that state. + * + * @return Background object. */ @NonNull - public Home getHome() { - return new Home(this); + public Background getBackground() { + return new Background(this); } /** @@ -214,40 +232,52 @@ public final class Launcher { } /** - * Gets the All Apps object if the current state is showing the all apps panel. Fails if the - * launcher is not in that state. + * Gets the All Apps object if the current state is showing the all apps panel opened by swiping + * from workspace. Fails if the launcher is not in that state. Please don't call this method if + * App Apps was opened by swiping up from Overview, as it won't fail and will return an + * incorrect object. + * + * @return All Aps object. + */ + @NonNull + public AllApps getAllApps() { + return new AllApps(this); + } + + /** + * Gets the All Apps object if the current state is showing the all apps panel opened by swiping + * from overview. Fails if the launcher is not in that state. Please don't call this method if + * App Apps was opened by swiping up from home, as it won't fail and will return an + * incorrect object. * * @return All Aps object. */ @NonNull - public AllAppsFromHome getAllApps() { - return new AllAppsFromHome(this); + public AllAppsFromOverview getAllAppsFromOverview() { + return new AllAppsFromOverview(this); } /** - * Gets the All Apps object if the current state is showing the all apps panel. Returns null if - * the launcher is not in that state. + * Gets the All Apps object if the current state is showing the all apps panel opened by swiping + * from workspace. Returns null if launcher is not in that state. Please don't call this method + * if App Apps was opened by swiping up from Overview, as it won't fail and will return an + * incorrect object. * * @return All Aps object or null. */ @Nullable - public AllAppsFromHome tryGetAllApps() { + public AllApps tryGetAllApps() { return tryGetLauncherObject(APPS_RES_ID) != null ? getAllApps() : null; } private void waitUntilGone(String resId) { -// assertTrue("Unexpected launcher object visible: " + resId, -// mDevice.wait(Until.gone(getLauncherObjectSelector(resId)), -// UI_OBJECT_WAIT_TIMEOUT_MS)); + assertTrue("Unexpected launcher object visible: " + resId, + mDevice.wait(Until.gone(getLauncherObjectSelector(resId)), + WAIT_TIME_MS)); } @NonNull UiObject2 getSystemUiObject(String resId) { - try { - mDevice.wakeUp(); - } catch (RemoteException e) { - fail("Failed to wake up the device: " + e); - } final UiObject2 object = mDevice.findObject(By.res(SYSTEMUI_PACKAGE, resId)); assertNotNull("Can't find a systemui object with id: " + resId, object); return object; @@ -269,8 +299,8 @@ public final class Launcher { UiObject2 waitForObjectInContainer(UiObject2 container, String resName) { final UiObject2 object = container.wait( Until.findObject(getLauncherObjectSelector(resName)), - UI_OBJECT_WAIT_TIMEOUT_MS); - assertNotNull("Can find a launcher object id: " + resName + " in container: " + + WAIT_TIME_MS); + assertNotNull("Can't find a launcher object id: " + resName + " in container: " + container.getResourceName(), object); return object; } @@ -278,8 +308,8 @@ public final class Launcher { @NonNull UiObject2 waitForLauncherObject(String resName) { final UiObject2 object = mDevice.wait(Until.findObject(getLauncherObjectSelector(resName)), - UI_OBJECT_WAIT_TIMEOUT_MS); - assertNotNull("Can find a launcher object; id: " + resName, object); + WAIT_TIME_MS); + assertNotNull("Can't find a launcher object; id: " + resName, object); return object; } @@ -292,9 +322,12 @@ public final class Launcher { return mDevice; } - void swipe(int startX, int startY, int endX, int endY, int steps) { - mDevice.swipe(startX, startY, endX, endY, steps); - waitForIdle(); + void swipe(int startX, int startY, int endX, int endY) { + executeAndWaitForEvent( + () -> mDevice.swipe(startX, startY, endX, endY, 60), + event -> "TAPL_WENT_TO_STATE".equals(event.getClassName()), + "Swipe failed to receive an event for the swipe end: " + startX + ", " + startY + + ", " + endX + ", " + endY); } void waitForIdle() { diff --git a/tests/tapl/com/android/launcher3/tapl/Overview.java b/tests/tapl/com/android/launcher3/tapl/Overview.java index 225165571..3d504c45e 100644 --- a/tests/tapl/com/android/launcher3/tapl/Overview.java +++ b/tests/tapl/com/android/launcher3/tapl/Overview.java @@ -16,6 +16,8 @@ package com.android.launcher3.tapl; +import static org.junit.Assert.assertNotEquals; + import android.graphics.Point; import android.support.annotation.NonNull; import android.support.test.uiautomator.Direction; @@ -27,44 +29,37 @@ import java.util.List; /** * Overview pane. */ -public final class Overview { +public final class Overview extends LauncherInstrumentation.VisibleContainer { private static final int DEFAULT_FLING_SPEED = 15000; - private final Launcher mLauncher; - - Overview(Launcher launcher) { - mLauncher = launcher; - assertState(); + Overview(LauncherInstrumentation launcher) { + super(launcher); + verifyActiveContainer(); } - /** - * Asserts that we are in overview. - * - * @return Overview panel. - */ - @NonNull - private UiObject2 assertState() { - return mLauncher.assertState(Launcher.State.OVERVIEW); + @Override + protected LauncherInstrumentation.ContainerType getContainerType() { + return LauncherInstrumentation.ContainerType.OVERVIEW; } /** * Flings forward (left) and waits the fling's end. */ public void flingForward() { - final UiObject2 overview = assertState(); + final UiObject2 overview = verifyActiveContainer(); overview.fling(Direction.LEFT, DEFAULT_FLING_SPEED); mLauncher.waitForIdle(); - assertState(); + verifyActiveContainer(); } /** * Flings backward (right) and waits the fling's end. */ public void flingBackward() { - final UiObject2 overview = assertState(); + final UiObject2 overview = verifyActiveContainer(); overview.fling(Direction.RIGHT, DEFAULT_FLING_SPEED); mLauncher.waitForIdle(); - assertState(); + verifyActiveContainer(); } /** @@ -74,10 +69,10 @@ public final class Overview { */ @NonNull public OverviewTask getCurrentTask() { - assertState(); + verifyActiveContainer(); final List<UiObject2> taskViews = mLauncher.getDevice().findObjects( - Launcher.getLauncherObjectSelector("snapshot")); - mLauncher.assertNotEquals("Unable to find a task", 0, taskViews.size()); + LauncherInstrumentation.getLauncherObjectSelector("snapshot")); + assertNotEquals("Unable to find a task", 0, taskViews.size()); // taskViews contains up to 3 task views: the 'main' (having the widest visible // part) one in the center, and parts of its right and left siblings. Find the @@ -86,7 +81,7 @@ public final class Overview { (t1, t2) -> Integer.compare(t1.getVisibleBounds().width(), t2.getVisibleBounds().width())); - return new OverviewTask(mLauncher, widestTask); + return new OverviewTask(mLauncher, widestTask, this); } /** @@ -96,7 +91,7 @@ public final class Overview { */ @NonNull public AllAppsFromOverview switchToAllApps() { - assertState(); + verifyActiveContainer(); // Swipe from the hotseat to near the top, e.g. 10% of the screen. final UiObject2 predictionRow = mLauncher.waitForLauncherObject( @@ -104,7 +99,7 @@ public final class Overview { final Point start = predictionRow.getVisibleCenter(); final int endY = (int) (mLauncher.getDevice().getDisplayHeight() * 0.1f); mLauncher.swipe( - start.x, start.y, start.x, endY, (start.y - endY) / 100); // 100 px/step + start.x, start.y, start.x, endY); return new AllAppsFromOverview(mLauncher); } diff --git a/tests/tapl/com/android/launcher3/tapl/OverviewTask.java b/tests/tapl/com/android/launcher3/tapl/OverviewTask.java index 68d308251..0b3a26492 100644 --- a/tests/tapl/com/android/launcher3/tapl/OverviewTask.java +++ b/tests/tapl/com/android/launcher3/tapl/OverviewTask.java @@ -16,6 +16,8 @@ package com.android.launcher3.tapl; +import static org.junit.Assert.assertTrue; + import android.support.test.uiautomator.Direction; import android.support.test.uiautomator.UiObject2; import android.support.test.uiautomator.Until; @@ -24,29 +26,26 @@ import android.support.test.uiautomator.Until; * A recent task in the overview panel carousel. */ public final class OverviewTask { - private final Launcher mLauncher; + private final LauncherInstrumentation mLauncher; private final UiObject2 mTask; + private final Overview mOverview; - OverviewTask(Launcher launcher, UiObject2 task) { + OverviewTask(LauncherInstrumentation launcher, UiObject2 task, Overview overview) { mLauncher = launcher; - assertState(); mTask = task; + mOverview = overview; + verifyActiveContainer(); } - /** - * Asserts that we are in overview. - * - * @return Overview panel. - */ - private void assertState() { - mLauncher.assertState(Launcher.State.OVERVIEW); + private void verifyActiveContainer() { + mOverview.verifyActiveContainer(); } /** * Swipes the task up. */ public void dismiss() { - assertState(); + verifyActiveContainer(); // Dismiss the task via flinging it up. mTask.fling(Direction.DOWN); mLauncher.waitForIdle(); @@ -55,11 +54,11 @@ public final class OverviewTask { /** * Clicks at the task. */ - public void open() { - assertState(); - mLauncher.assertTrue("Launching task didn't open a new window: " + + public Background open() { + verifyActiveContainer(); + assertTrue("Launching task didn't open a new window: " + mTask.getParent().getContentDescription(), - mTask.clickAndWait(Until.newWindow(), Launcher.APP_LAUNCH_TIMEOUT_MS)); - mLauncher.assertState(Launcher.State.BACKGROUND); + mTask.clickAndWait(Until.newWindow(), LauncherInstrumentation.WAIT_TIME_MS)); + return new Background(mLauncher); } } diff --git a/tests/tapl/com/android/launcher3/tapl/Widgets.java b/tests/tapl/com/android/launcher3/tapl/Widgets.java index 7a5198a80..f67ef4c77 100644 --- a/tests/tapl/com/android/launcher3/tapl/Widgets.java +++ b/tests/tapl/com/android/launcher3/tapl/Widgets.java @@ -16,50 +16,43 @@ package com.android.launcher3.tapl; -import android.support.annotation.NonNull; import android.support.test.uiautomator.Direction; import android.support.test.uiautomator.UiObject2; /** * All widgets container. */ -public final class Widgets { +public final class Widgets extends LauncherInstrumentation.VisibleContainer { private static final int FLING_SPEED = 12000; - private final Launcher mLauncher; - - Widgets(Launcher launcher) { - mLauncher = launcher; - assertState(); + Widgets(LauncherInstrumentation launcher) { + super(launcher); + verifyActiveContainer(); } /** * Flings forward (down) and waits the fling's end. */ public void flingForward() { - final UiObject2 widgetsContainer = assertState(); + final UiObject2 widgetsContainer = verifyActiveContainer(); + widgetsContainer.setGestureMargin(100); widgetsContainer.fling(Direction.DOWN, FLING_SPEED); - mLauncher.waitForIdle(); - assertState(); + verifyActiveContainer(); } /** * Flings backward (up) and waits the fling's end. */ public void flingBackward() { - final UiObject2 widgetsContainer = assertState(); + final UiObject2 widgetsContainer = verifyActiveContainer(); + widgetsContainer.setGestureMargin(100); widgetsContainer.fling(Direction.UP, FLING_SPEED); mLauncher.waitForIdle(); - assertState(); + verifyActiveContainer(); } - /** - * Asserts that we are in widgets. - * - * @return Widgets container. - */ - @NonNull - private UiObject2 assertState() { - return mLauncher.assertState(Launcher.State.WIDGETS); + @Override + protected LauncherInstrumentation.ContainerType getContainerType() { + return LauncherInstrumentation.ContainerType.WIDGETS; } } diff --git a/tests/tapl/com/android/launcher3/tapl/Workspace.java b/tests/tapl/com/android/launcher3/tapl/Workspace.java new file mode 100644 index 000000000..045ab5fcf --- /dev/null +++ b/tests/tapl/com/android/launcher3/tapl/Workspace.java @@ -0,0 +1,155 @@ +/* + * Copyright (C) 2018 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 junit.framework.TestCase.assertTrue; + +import android.graphics.Point; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.test.uiautomator.Direction; +import android.support.test.uiautomator.UiObject2; +import android.view.KeyEvent; + +/** + * Operations on the workspace screen. + */ +public final class Workspace extends Home { + private final UiObject2 mHotseat; + private final int ICON_DRAG_SPEED = 2000; + + Workspace(LauncherInstrumentation launcher) { + super(launcher); + mHotseat = launcher.waitForLauncherObject("hotseat"); + } + + @Override + protected LauncherInstrumentation.ContainerType getContainerType() { + return LauncherInstrumentation.ContainerType.WORKSPACE; + } + + /** + * Swipes up to All Apps. + * + * @return the App Apps object. + */ + @NonNull + public AllApps switchToAllApps() { + verifyActiveContainer(); + if (mLauncher.isSwipeUpEnabled()) { + int midX = mLauncher.getDevice().getDisplayWidth() / 2; + int height = mLauncher.getDevice().getDisplayHeight(); + // Swipe from 6/7ths down the screen to 1/7th down the screen. + mLauncher.swipe( + midX, + height * 6 / 7, + midX, + height / 7 + ); + } else { + // Swipe from the hotseat to near the top, e.g. 10% of the screen. + final UiObject2 hotseat = mHotseat; + final Point start = hotseat.getVisibleCenter(); + final int endY = (int) (mLauncher.getDevice().getDisplayHeight() * 0.1f); + mLauncher.swipe( + start.x, + start.y, + start.x, + endY + ); + } + + return new AllApps(mLauncher); + } + + /** + * Returns an icon for the app, if currently visible. + * + * @param appName name of the app + * @return app icon, if found, null otherwise. + */ + @Nullable + public AppIcon tryGetWorkspaceAppIcon(String appName) { + final UiObject2 workspace = verifyActiveContainer(); + final UiObject2 icon = workspace.findObject(AppIcon.getAppIconSelector(appName)); + return icon != null ? new AppIcon(mLauncher, icon) : null; + } + + /** + * Ensures that workspace is scrollable. If it's not, drags an icon icons from hotseat to the + * second screen. + */ + public void ensureWorkspaceIsScrollable() { + final UiObject2 workspace = verifyActiveContainer(); + if (!isWorkspaceScrollable(workspace)) { + dragIconToNextScreen(getHotseatAppIcon("Messages"), workspace); + } + assertTrue("Home screen workspace didn't become scrollable", + isWorkspaceScrollable(workspace)); + } + + private boolean isWorkspaceScrollable(UiObject2 workspace) { + return workspace.isScrollable(); + } + + @NonNull + private AppIcon getHotseatAppIcon(String appName) { + return new AppIcon(mLauncher, mLauncher.getObjectInContainer( + mHotseat, AppIcon.getAppIconSelector(appName))); + } + + private void dragIconToNextScreen(AppIcon app, UiObject2 workspace) { + final Point dest = new Point( + mLauncher.getDevice().getDisplayWidth(), workspace.getVisibleBounds().centerY()); + app.getIcon().drag(dest, ICON_DRAG_SPEED); + verifyActiveContainer(); + } + + /** + * Flings to get to screens on the right. Waits for scrolling and a possible overscroll + * recoil to complete. + */ + public void flingForward() { + final UiObject2 workspace = verifyActiveContainer(); + workspace.fling(Direction.RIGHT); + mLauncher.waitForIdle(); + verifyActiveContainer(); + } + + /** + * Flings to get to screens on the left. Waits for scrolling and a possible overscroll + * recoil to complete. + */ + public void flingBackward() { + final UiObject2 workspace = verifyActiveContainer(); + workspace.fling(Direction.LEFT); + mLauncher.waitForIdle(); + verifyActiveContainer(); + } + + /** + * Opens widgets container by pressing Ctrl+W. + * + * @return the widgets container. + */ + @NonNull + public Widgets openAllWidgets() { + verifyActiveContainer(); + mLauncher.getDevice().pressKeyCode(KeyEvent.KEYCODE_W, KeyEvent.META_CTRL_ON); + return new Widgets(mLauncher); + } +}
\ No newline at end of file |