Tapl library
The public API of the library has finalized; flakiness has been removed;
code polished.
Bug: 110103162
Test: TaplTests suite
Change-Id: Ic156bbfeedb1cb9c4a48ef907f97e396e8e81936
diff --git a/quickstep/src/com/android/quickstep/ActivityControlHelper.java b/quickstep/src/com/android/quickstep/ActivityControlHelper.java
index d37ac49..6300ed3 100644
--- a/quickstep/src/com/android/quickstep/ActivityControlHelper.java
+++ b/quickstep/src/com/android/quickstep/ActivityControlHelper.java
@@ -57,6 +57,7 @@
import com.android.launcher3.allapps.DiscoveryBounce;
import com.android.launcher3.anim.AnimationSuccessListener;
import com.android.launcher3.anim.AnimatorPlaybackController;
+import com.android.launcher3.compat.AccessibilityManagerCompat;
import com.android.launcher3.dragndrop.DragLayer;
import com.android.launcher3.uioverrides.FastOverviewState;
import com.android.launcher3.userevent.nano.LauncherLogProto;
@@ -230,6 +231,8 @@
// Optimization, hide the all apps view to prevent layout while initializing
activity.getAppsView().getContentView().setVisibility(View.GONE);
+
+ AccessibilityManagerCompat.sendEventToTest(activity, "TAPL_WENT_TO_STATE");
}
return new AnimationFactory() {
diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java
index 8683b21..7c5bb1a 100644
--- a/src/com/android/launcher3/Utilities.java
+++ b/src/com/android/launcher3/Utilities.java
@@ -16,6 +16,7 @@
package com.android.launcher3;
+import android.app.ActivityManager;
import android.app.WallpaperManager;
import android.content.ComponentName;
import android.content.Context;
@@ -130,6 +131,9 @@
CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,
TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());
+ public static final boolean IS_RUNNING_IN_TEST_HARNESS =
+ ActivityManager.isRunningInTestHarness();
+
public static boolean isPropertyEnabled(String propertyName) {
return Log.isLoggable(propertyName, Log.VERBOSE);
}
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index 67bdd3b..0052701 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -1034,7 +1034,7 @@
}
protected void onScrollInteractionBegin() {
- super.onScrollInteractionEnd();
+ super.onScrollInteractionBegin();
mScrollInteractionBegan = true;
}
diff --git a/src/com/android/launcher3/compat/AccessibilityManagerCompat.java b/src/com/android/launcher3/compat/AccessibilityManagerCompat.java
index 0c78381..29fc2bc 100644
--- a/src/com/android/launcher3/compat/AccessibilityManagerCompat.java
+++ b/src/com/android/launcher3/compat/AccessibilityManagerCompat.java
@@ -16,11 +16,14 @@
package com.android.launcher3.compat;
+import android.accessibilityservice.AccessibilityServiceInfo;
import android.content.Context;
import android.view.View;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
+import com.android.launcher3.Utilities;
+
public class AccessibilityManagerCompat {
public static boolean isAccessibilityEnabled(Context context) {
@@ -44,4 +47,19 @@
private static AccessibilityManager getManager(Context context) {
return (AccessibilityManager) context.getSystemService(Context.ACCESSIBILITY_SERVICE);
}
+
+ public static void sendEventToTest(Context context, String eventTag) {
+ if (!Utilities.IS_RUNNING_IN_TEST_HARNESS) return;
+
+ final AccessibilityManager accessibilityManager = getManager(context);
+ if (accessibilityManager.isEnabled() &&
+ accessibilityManager.getEnabledAccessibilityServiceList(
+ AccessibilityServiceInfo.FEEDBACK_ALL_MASK).size() == 0) {
+
+ final AccessibilityEvent e = AccessibilityEvent.obtain(
+ AccessibilityEvent.TYPE_ANNOUNCEMENT);
+ e.setClassName(eventTag);
+ accessibilityManager.sendAccessibilityEvent(e);
+ }
+ }
}
diff --git a/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java b/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java
index 55f850c..0e277ea 100644
--- a/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java
+++ b/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java
@@ -43,6 +43,7 @@
import com.android.launcher3.anim.AnimationSuccessListener;
import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.anim.AnimatorSetBuilder;
+import com.android.launcher3.compat.AccessibilityManagerCompat;
import com.android.launcher3.userevent.nano.LauncherLogProto;
import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Direction;
import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch;
@@ -515,6 +516,8 @@
logReachedState(logAction, targetState);
}
mLauncher.getStateManager().goToState(targetState, false /* animated */);
+
+ AccessibilityManagerCompat.sendEventToTest(mLauncher, "TAPL_WENT_TO_STATE");
}
}
diff --git a/src/com/android/launcher3/views/OptionsPopupView.java b/src/com/android/launcher3/views/OptionsPopupView.java
index 5046639..dc6d2ff 100644
--- a/src/com/android/launcher3/views/OptionsPopupView.java
+++ b/src/com/android/launcher3/views/OptionsPopupView.java
@@ -22,6 +22,7 @@
import android.content.Intent;
import android.graphics.Rect;
import android.graphics.RectF;
+import android.support.annotation.VisibleForTesting;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.AttributeSet;
@@ -133,6 +134,11 @@
popup.reorderAndShow(popup.getChildCount());
}
+ @VisibleForTesting
+ public static OptionsPopupView getOptionsPopup(Launcher launcher) {
+ return launcher.findViewById(R.id.deep_shortcuts_container);
+ }
+
public static void showDefaultOptions(Launcher launcher, float x, float y) {
float halfSize = launcher.getResources().getDimension(R.dimen.options_menu_thumb_size) / 2;
if (x < 0 || y < 0) {
diff --git a/src/com/android/launcher3/widget/WidgetsFullSheet.java b/src/com/android/launcher3/widget/WidgetsFullSheet.java
index e94d81d..b493228 100644
--- a/src/com/android/launcher3/widget/WidgetsFullSheet.java
+++ b/src/com/android/launcher3/widget/WidgetsFullSheet.java
@@ -20,6 +20,7 @@
import android.animation.PropertyValuesHolder;
import android.content.Context;
import android.graphics.Rect;
+import android.support.annotation.VisibleForTesting;
import android.util.AttributeSet;
import android.util.Pair;
import android.view.LayoutInflater;
@@ -224,6 +225,11 @@
return sheet;
}
+ @VisibleForTesting
+ public static WidgetsRecyclerView getWidgetsView(Launcher launcher) {
+ return launcher.findViewById(R.id.widgets_list_view);
+ }
+
@Override
protected int getElementsRowCount() {
return mAdapter.getItemCount();
diff --git a/tests/tapl/com/android/launcher3/tapl/AllAppsFromHome.java b/tests/tapl/com/android/launcher3/tapl/AllApps.java
similarity index 73%
rename from tests/tapl/com/android/launcher3/tapl/AllAppsFromHome.java
rename to tests/tapl/com/android/launcher3/tapl/AllApps.java
index 02f8183..d849e2d 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 @@
*/
@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 @@
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 @@
* 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 @@
@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 cba7086..bc0dfc6 100644
--- a/tests/tapl/com/android/launcher3/tapl/AllAppsFromOverview.java
+++ b/tests/tapl/com/android/launcher3/tapl/AllAppsFromOverview.java
@@ -22,24 +22,17 @@
/**
* 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 @@
*/
@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 73a74f2..721f7a8 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 @@
* 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 0000000..1aef979
--- /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 0ec1a64..436e5ff 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 @@
*/
@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/Launcher.java
deleted file mode 100644
index 5201dc8..0000000
--- a/tests/tapl/com/android/launcher3/tapl/Launcher.java
+++ /dev/null
@@ -1,303 +0,0 @@
-/*
- * 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 com.android.systemui.shared.system.SettingsCompat.SWIPE_UP_SETTING_NAME;
-
-import android.content.res.Resources;
-import android.os.RemoteException;
-import android.provider.Settings;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.uiautomator.By;
-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;
-
-/**
- * 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 {
-
- 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;
- 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 final UiDevice mDevice;
- private final boolean mSwipeUpEnabled;
-
- /**
- * Constructs the root of TAPL hierarchy. You get all other object from it.
- */
- public Launcher(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,
- swipeUpEnabledDefault ? 1 : 0) == 1;
- }
-
- private boolean getSystemBooleanRes(String resName) {
- final Resources res = Resources.getSystem();
- final int resId = res.getIdentifier(resName, "bool", "android");
- assertTrue("Resource not found: " + resName, resId != 0);
- 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);
- }
- }
-
- boolean isSwipeUpEnabled() {
- return mSwipeUpEnabled;
- }
-
- UiObject2 assertState(State state) {
- switch (state) {
- case HOME: {
- //waitUntilGone(APPS_RES_ID);
- waitUntilGone(OVERVIEW_RES_ID);
- waitUntilGone(WIDGETS_RES_ID);
- return waitForLauncherObject(WORKSPACE_RES_ID);
- }
- case WIDGETS: {
- waitUntilGone(WORKSPACE_RES_ID);
- waitUntilGone(APPS_RES_ID);
- waitUntilGone(OVERVIEW_RES_ID);
- return waitForLauncherObject(WIDGETS_RES_ID);
- }
- 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);
- waitUntilGone(WIDGETS_RES_ID);
- return waitForLauncherObject(OVERVIEW_RES_ID);
- }
- case BACKGROUND: {
- waitUntilGone(WORKSPACE_RES_ID);
- waitUntilGone(APPS_RES_ID);
- waitUntilGone(OVERVIEW_RES_ID);
- waitUntilGone(WIDGETS_RES_ID);
- return null;
- }
- default:
- fail("Invalid state: " + state);
- return null;
- }
- }
-
- /**
- * Presses nav bar home button.
- *
- * @return the Home object.
- */
- public Home pressHome() {
- getSystemUiObject("home").click();
- return getHome();
- }
-
- /**
- * Gets the Home object if the current state is "active home", i.e. workspace. Fails if the
- * launcher is not in that state.
- *
- * @return Home object.
- */
- @NonNull
- public Home getHome() {
- return new Home(this);
- }
-
- /**
- * Gets the Widgets object if the current state is showing all widgets. Fails if the launcher is
- * not in that state.
- *
- * @return Widgets object.
- */
- @NonNull
- public Widgets getAllWidgets() {
- return new Widgets(this);
- }
-
- /**
- * Gets the Overview object if the current state is showing the overview panel. Fails if the
- * launcher is not in that state.
- *
- * @return Overview object.
- */
- @NonNull
- public Overview getOverview() {
- return new Overview(this);
- }
-
- /**
- * Gets the All Apps object if the current state is showing the all apps panel. Fails if the
- * launcher is not in that state.
- *
- * @return All Aps object.
- */
- @NonNull
- public AllAppsFromHome getAllApps() {
- return new AllAppsFromHome(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.
- *
- * @return All Aps object or null.
- */
- @Nullable
- public AllAppsFromHome 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));
- }
-
- @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;
- }
-
- @NonNull
- UiObject2 getObjectInContainer(UiObject2 container, BySelector selector) {
- final UiObject2 object = container.findObject(selector);
- assertNotNull("Can't find an object with selector: " + selector, object);
- return object;
- }
-
- @Nullable
- private UiObject2 tryGetLauncherObject(String resName) {
- return mDevice.findObject(getLauncherObjectSelector(resName));
- }
-
- @NonNull
- 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: " +
- container.getResourceName(), object);
- return object;
- }
-
- @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);
- return object;
- }
-
- static BySelector getLauncherObjectSelector(String resName) {
- return By.res(LAUNCHER_PKG, resName);
- }
-
- @NonNull
- UiDevice getDevice() {
- return mDevice;
- }
-
- void swipe(int startX, int startY, int endX, int endY, int steps) {
- mDevice.swipe(startX, startY, endX, endY, steps);
- waitForIdle();
- }
-
- void waitForIdle() {
- mDevice.waitForIdle();
- }
-}
\ No newline at end of file
diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
new file mode 100644
index 0000000..fc32fed
--- /dev/null
+++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
@@ -0,0 +1,336 @@
+/*
+ * 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 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.provider.Settings;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.uiautomator.By;
+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 org.junit.Assert;
+
+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 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";
+ static final String LAUNCHER_PKG = "com.google.android.apps.nexuslauncher";
+ 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 WeakReference<VisibleContainer> sActiveContainer = new WeakReference<>(null);
+
+ private final UiDevice mDevice;
+ private final boolean mSwipeUpEnabled;
+
+ /**
+ * Constructs the root of TAPL hierarchy. You get all other objects from it.
+ */
+ 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_to_switch_apps_enabled",
+ swipeUpEnabledDefault ? 1 : 0) == 1;
+ assertTrue("Device must run in a test harness", ActivityManager.isRunningInTestHarness());
+ }
+
+ private boolean getSystemBooleanRes(String resName) {
+ final Resources res = Resources.getSystem();
+ final int resId = res.getIdentifier(resName, "bool", "android");
+ assertTrue("Resource not found: " + resName, resId != 0);
+ return res.getBoolean(resId);
+ }
+
+ void setActiveContainer(VisibleContainer container) {
+ sActiveContainer = new WeakReference<>(container);
+ }
+
+ boolean isSwipeUpEnabled() {
+ return mSwipeUpEnabled;
+ }
+
+ 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);
+ }
+ case WIDGETS: {
+ waitUntilGone(WORKSPACE_RES_ID);
+ waitUntilGone(APPS_RES_ID);
+ waitUntilGone(OVERVIEW_RES_ID);
+ return waitForLauncherObject(WIDGETS_RES_ID);
+ }
+ case ALL_APPS: {
+ waitUntilGone(OVERVIEW_RES_ID);
+ waitUntilGone(WIDGETS_RES_ID);
+ return waitForLauncherObject(APPS_RES_ID);
+ }
+ case OVERVIEW: {
+ waitForLauncherObject(APPS_RES_ID);
+ waitUntilGone(WIDGETS_RES_ID);
+ return waitForLauncherObject(OVERVIEW_RES_ID);
+ }
+ case BACKGROUND: {
+ waitUntilGone(WORKSPACE_RES_ID);
+ waitUntilGone(APPS_RES_ID);
+ waitUntilGone(OVERVIEW_RES_ID);
+ waitUntilGone(WIDGETS_RES_ID);
+ return null;
+ }
+ default:
+ 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 Workspace object.
+ */
+ 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 Workspace object if the current state is "active home", i.e. workspace. Fails if the
+ * launcher is not in that state.
+ *
+ * @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 Background getBackground() {
+ return new Background(this);
+ }
+
+ /**
+ * Gets the Widgets object if the current state is showing all widgets. Fails if the launcher is
+ * not in that state.
+ *
+ * @return Widgets object.
+ */
+ @NonNull
+ public Widgets getAllWidgets() {
+ return new Widgets(this);
+ }
+
+ /**
+ * Gets the Overview object if the current state is showing the overview panel. Fails if the
+ * launcher is not in that state.
+ *
+ * @return Overview object.
+ */
+ @NonNull
+ public Overview getOverview() {
+ return new Overview(this);
+ }
+
+ /**
+ * 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 AllAppsFromOverview getAllAppsFromOverview() {
+ return new AllAppsFromOverview(this);
+ }
+
+ /**
+ * 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 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)),
+ WAIT_TIME_MS));
+ }
+
+ @NonNull
+ UiObject2 getSystemUiObject(String resId) {
+ final UiObject2 object = mDevice.findObject(By.res(SYSTEMUI_PACKAGE, resId));
+ assertNotNull("Can't find a systemui object with id: " + resId, object);
+ return object;
+ }
+
+ @NonNull
+ UiObject2 getObjectInContainer(UiObject2 container, BySelector selector) {
+ final UiObject2 object = container.findObject(selector);
+ assertNotNull("Can't find an object with selector: " + selector, object);
+ return object;
+ }
+
+ @Nullable
+ private UiObject2 tryGetLauncherObject(String resName) {
+ return mDevice.findObject(getLauncherObjectSelector(resName));
+ }
+
+ @NonNull
+ UiObject2 waitForObjectInContainer(UiObject2 container, String resName) {
+ final UiObject2 object = container.wait(
+ Until.findObject(getLauncherObjectSelector(resName)),
+ WAIT_TIME_MS);
+ assertNotNull("Can't find a launcher object id: " + resName + " in container: " +
+ container.getResourceName(), object);
+ return object;
+ }
+
+ @NonNull
+ UiObject2 waitForLauncherObject(String resName) {
+ final UiObject2 object = mDevice.wait(Until.findObject(getLauncherObjectSelector(resName)),
+ WAIT_TIME_MS);
+ assertNotNull("Can't find a launcher object; id: " + resName, object);
+ return object;
+ }
+
+ static BySelector getLauncherObjectSelector(String resName) {
+ return By.res(LAUNCHER_PKG, resName);
+ }
+
+ @NonNull
+ UiDevice getDevice() {
+ return mDevice;
+ }
+
+ 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() {
+ mDevice.waitForIdle();
+ }
+}
\ No newline at end of file
diff --git a/tests/tapl/com/android/launcher3/tapl/Overview.java b/tests/tapl/com/android/launcher3/tapl/Overview.java
index 2251655..3d504c4 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 @@
/**
* 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 @@
*/
@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 @@
(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 @@
*/
@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 @@
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 68d3082..0b3a264 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 @@
* 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 @@
/**
* 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 7a5198a..f67ef4c 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 0000000..045ab5f
--- /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