Recents and multiwindow functional tests
am: 817cde1ddb
Change-Id: I16e8b35609ca1143e6bd1ffb25e773b19ab8431d
diff --git a/tests/functional/overviewtests/Android.mk b/tests/functional/overviewtests/Android.mk
new file mode 100644
index 0000000..6d6cec7
--- /dev/null
+++ b/tests/functional/overviewtests/Android.mk
@@ -0,0 +1,26 @@
+# Copyright (C) 2016 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.
+
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_PACKAGE_NAME := OverviewFunctionalTests
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_STATIC_JAVA_LIBRARIES := ub-uiautomator timeresult-helper-lib launcher-helper-lib android-support-test
+
+LOCAL_SDK_VERSION := current
+
+include $(BUILD_PACKAGE)
diff --git a/tests/functional/overviewtests/AndroidManifest.xml b/tests/functional/overviewtests/AndroidManifest.xml
new file mode 100644
index 0000000..160eab5
--- /dev/null
+++ b/tests/functional/overviewtests/AndroidManifest.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.overview.functional">
+
+ <application>
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+ <uses-sdk android:minSdkVersion="19"
+ android:targetSdkVersion="23"/>
+
+ <instrumentation
+ android:name="android.support.test.runner.AndroidJUnitRunner"
+ android:targetPackage="android.overview.functional"
+ android:label="Platform Android Overview Functional Tests" />
+</manifest>
diff --git a/tests/functional/overviewtests/src/com/android/overview/functional/MultiWindowTests.java b/tests/functional/overviewtests/src/com/android/overview/functional/MultiWindowTests.java
new file mode 100644
index 0000000..4cbf7e7
--- /dev/null
+++ b/tests/functional/overviewtests/src/com/android/overview/functional/MultiWindowTests.java
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2016 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 android.overview.functional;
+
+import java.io.File;
+import java.io.IOException;
+
+import android.app.UiAutomation;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.Context;
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.os.PowerManager;
+import android.os.RemoteException;
+import android.os.SystemClock;
+import android.support.test.launcherhelper.ILauncherStrategy;
+import android.support.test.launcherhelper.LauncherStrategyFactory;
+import android.support.test.uiautomator.By;
+import android.support.test.uiautomator.Direction;
+import android.support.test.uiautomator.UiDevice;
+import android.support.test.uiautomator.UiObject2;
+import android.support.test.uiautomator.UiObjectNotFoundException;
+import android.support.test.uiautomator.Until;
+import android.test.InstrumentationTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.util.Log;
+import android.view.accessibility.AccessibilityWindowInfo;
+import android.view.KeyEvent;
+
+public class MultiWindowTests extends InstrumentationTestCase {
+
+ private static final int TIMEOUT = 3000;
+ private static final String HOTSEAT = "hotseat";
+ private static final String CALCULATOR_PACKAGE = "com.google.android.calculator";
+ private static final String GMAIL_PACKAGE = "com.google.android.gm";
+ private UiDevice mDevice;
+ private PackageManager mPackageManager;
+ private ILauncherStrategy mLauncherStrategy = null;
+ private UiAutomation mUiAutomation = null;
+ private OverviewHelper mOverviewHelper;
+
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+ mDevice = UiDevice.getInstance(getInstrumentation());
+ mUiAutomation = getInstrumentation().getUiAutomation();
+ mPackageManager = getInstrumentation().getContext().getPackageManager();
+ mDevice.setOrientationNatural();
+ mLauncherStrategy = LauncherStrategyFactory.getInstance(mDevice).getLauncherStrategy();
+ mOverviewHelper = new OverviewHelper(mDevice, getInstrumentation());
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ mDevice.pressHome();
+ mDevice.unfreezeRotation();
+ mDevice.waitForIdle();
+ super.tearDown();
+ }
+
+ public String getLauncherPackage() {
+ return mDevice.getLauncherPackageName();
+ }
+
+ @MediumTest
+ public void testDockingUndockingOnMultiwindow() throws Exception {
+ mOverviewHelper.dockAppToTopMultiwindowSlot(CALCULATOR_PACKAGE, "Calculator");
+ // Click to check for split windows
+ mDevice.click(mDevice.getDisplayHeight() * 3/4, mDevice.getDisplayWidth() / 2);
+ assertTrue("Bottom half of screen doesn't have empty recents list",
+ mDevice.wait(Until.hasObject(By.text("No recent items")), TIMEOUT));
+ // Calculate midpoint for Calculator window and click
+ mDevice.click(mDevice.getDisplayHeight() / 4, mDevice.getDisplayWidth() / 2);
+ UiObject2 calcArea = mDevice.wait(Until.findObject(By.res("android:id/content")), TIMEOUT);
+ assertNotNull("Top half of screen doesn't have Calculator", calcArea);
+ mOverviewHelper.undockAppFromMultiwindow(CALCULATOR_PACKAGE);
+ assertFalse("Calculator isn't full screen after dragging",
+ mDevice.wait(Until.hasObject(By.text("No recent items")), TIMEOUT));
+ }
+
+ @MediumTest
+ public void testResizeHandleOnMultiwindow() throws Exception {
+ mOverviewHelper.dockAppsToBothMultiwindowAreas(CALCULATOR_PACKAGE, "Calculator",
+ GMAIL_PACKAGE);
+ // verify initial bounds for top and bottom
+ mDevice.click(mDevice.getDisplayHeight() / 4, mDevice.getDisplayWidth() / 2);
+ UiObject2 calcArea = mDevice.wait(Until.findObject
+ (By.pkg(CALCULATOR_PACKAGE).res("android:id/content")), TIMEOUT);
+ Rect initialCalcBounds = calcArea.getVisibleBounds();
+ mDevice.click(mDevice.getDisplayHeight() * 3/4, mDevice.getDisplayWidth() / 2);
+ UiObject2 gmailArea = mDevice.wait(Until.findObject
+ (By.pkg(GMAIL_PACKAGE).res("android:id/content")), TIMEOUT);
+ Rect initialGmailBounds = gmailArea.getVisibleBounds();
+ // Move handle so Calculator occupies about 3/4 of the screen
+ int xCoordinate = mDevice.getDisplayWidth() / 2;
+ mDevice.drag(xCoordinate, initialCalcBounds.bottom,
+ xCoordinate, mDevice.getDisplayHeight() * 3/4, 2);
+ // Verify that final area for calculator is larger than initial
+ calcArea = mDevice.wait(Until.findObject
+ (By.pkg(CALCULATOR_PACKAGE).res("android:id/content")), TIMEOUT);
+ Rect finalCalcBounds = calcArea.getVisibleBounds();
+ mDevice.click(mDevice.getDisplayHeight() * 3/4, mDevice.getDisplayWidth() / 2);
+ gmailArea = mDevice.wait(Until.findObject
+ (By.pkg(GMAIL_PACKAGE).res("android:id/content")), TIMEOUT);
+ Rect finalGmailBounds = gmailArea.getVisibleBounds();
+ // Verify that final area for gmail is smaller than initial
+ assertTrue("Calculator area not larger than before resize",
+ finalCalcBounds.bottom > initialCalcBounds.bottom);
+ assertTrue("GMail area not smaller than before resize",
+ finalGmailBounds.top > initialGmailBounds.top);
+ mOverviewHelper.undockAppFromMultiwindow(CALCULATOR_PACKAGE);
+ }
+
+ @MediumTest
+ public void testLandscapeModeMultiwindow() throws Exception {
+ mOverviewHelper.dockAppsToBothMultiwindowAreas(CALCULATOR_PACKAGE, "Calculator",
+ GMAIL_PACKAGE);
+ mDevice.setOrientationLeft();
+ // Adding a sleep here as otherwise the test attempts to click too quickly
+ // before the orientation has a chance to change.
+ Thread.sleep(TIMEOUT);
+ // Click on the left of the device
+ mDevice.click(mDevice.getDisplayHeight() / 2, mDevice.getDisplayWidth() / 4);
+ assertNotNull("Calculator not found on left in landscape mode",
+ mDevice.wait(Until.hasObject
+ (By.pkg(CALCULATOR_PACKAGE).res("android:id/content")), TIMEOUT));
+ mDevice.click(mDevice.getDisplayHeight() / 2, mDevice.getDisplayWidth() * 3/4);
+ assertNotNull("Gmail not found on right in landscape mode",
+ mDevice.wait(Until.hasObject
+ (By.pkg(GMAIL_PACKAGE).res("android:id/content")), TIMEOUT));
+ mDevice.setOrientationNatural();
+ mOverviewHelper.undockAppFromMultiwindow(CALCULATOR_PACKAGE);
+ }
+}
diff --git a/tests/functional/overviewtests/src/com/android/overview/functional/OverviewHelper.java b/tests/functional/overviewtests/src/com/android/overview/functional/OverviewHelper.java
new file mode 100644
index 0000000..8f4fd12
--- /dev/null
+++ b/tests/functional/overviewtests/src/com/android/overview/functional/OverviewHelper.java
@@ -0,0 +1,197 @@
+/*
+ * Copyright (C) 2016 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 android.overview.functional;
+
+import java.io.File;
+import java.io.IOException;
+
+import android.app.Instrumentation;
+import android.app.UiAutomation;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.Context;
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.os.PowerManager;
+import android.os.RemoteException;
+import android.os.SystemClock;
+import android.support.test.launcherhelper.ILauncherStrategy;
+import android.support.test.launcherhelper.LauncherStrategyFactory;
+import android.support.test.uiautomator.By;
+import android.support.test.uiautomator.UiDevice;
+import android.support.test.uiautomator.UiObject2;
+import android.support.test.uiautomator.UiObjectNotFoundException;
+import android.support.test.uiautomator.Until;
+import android.test.InstrumentationTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.util.Log;
+import org.junit.Assert;
+
+public class OverviewHelper {
+
+ private static final int TIMEOUT = 3000;
+ private static final String RECENTS = "com.android.systemui:id/recents_view";
+
+ private UiDevice mDevice;
+ private Instrumentation mInstrumentation;
+ private PackageManager mPackageManager;
+ private Context mContext = null;
+
+ public OverviewHelper(UiDevice device, Instrumentation inst) {
+ this.mDevice = device;
+ mInstrumentation = inst;
+ mPackageManager = inst.getContext().getPackageManager();
+ }
+
+ public String getLauncherPackage() {
+ return mDevice.getLauncherPackageName();
+ }
+
+ /*
+ * Launches an app with the given package name
+ * @param appPackageName Name of package to be launched
+ */
+ public void launchAppWithIntent(String appPackageName) {
+ Intent appIntent = mPackageManager.getLaunchIntentForPackage(appPackageName);
+ Assert.assertNotNull("App intent to launch package " + appPackageName +
+ " is null, please check package name", appIntent);
+ appIntent.addCategory(Intent.CATEGORY_LAUNCHER);
+ appIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ mInstrumentation.getContext().startActivity(appIntent);
+ // Adding a sleep here to wait for app to finish launching
+ // This allows it to be present in the UI before moving on.
+ SystemClock.sleep(TIMEOUT);
+ }
+
+ /*
+ * Navigates to the recents screen
+ * @returns recents object
+ * @throws UiObjectNotFoundException
+ */
+ public UiObject2 navigateToRecents() throws Exception {
+ mDevice.pressRecentApps();
+ mDevice.waitForIdle();
+ return mDevice.wait(Until.findObject(By.res(RECENTS)), TIMEOUT);
+ }
+
+ /*
+ * Populates recents by launching six apps
+ */
+ public void populateRecents() {
+ // We launch six apps, since five is the maximum number
+ // of apps under Recents
+ String[] appPackages = {"com.google.android.gm",
+ "com.google.android.deskclock", "com.android.settings",
+ "com.google.android.youtube", "com.google.android.contacts",
+ "com.google.android.apps.maps"};
+ for (String appPackage : appPackages) {
+ launchAppWithIntent(appPackage);
+ }
+ }
+
+ /*
+ * Scrolls through given recents object to the top.
+ * @param recents Recents object
+ */
+ public void scrollToTopOfRecents(UiObject2 recents) {
+ Rect r = recents.getVisibleBounds();
+ // decide the top & bottom edges for scroll gesture
+ int top = r.top + r.height() / 4; // top edge = top + 25% height
+ int bottom = r.bottom - 200; // bottom edge = bottom & shift up 200px
+ mDevice.swipe(r.width() / 2, top, r.width() / 2, bottom, 5);
+ mDevice.waitForIdle();
+ }
+
+ /*
+ * Docks an app to the top half of the multiwindow screen
+ * @param appPackageName name of app package
+ * @param appName Name of app to verify on screen
+ * @throws UiObjectNotFoundException, InterruptedException
+ */
+ public void dockAppToTopMultiwindowSlot(String appPackageName, String appName)
+ throws Exception {
+ mDevice.pressRecentApps();
+ mDevice.waitForIdle();
+ UiObject2 recentsView = mDevice.wait(Until.findObject
+ (By.res("com.android.systemui:id/recents_view")),TIMEOUT);
+ // Check if recents isn't already empty, if not, clear it.
+ if (!mDevice.wait(Until.hasObject(By.text("No recent items")),TIMEOUT)) {
+ scrollToTopOfRecents(recentsView);
+ // click clear all
+ UiObject2 clearAll = mDevice.wait(Until.findObject(By.text("CLEAR ALL")),TIMEOUT);
+ if (!clearAll.equals(null)) {
+ clearAll.click();
+ }
+ Thread.sleep(TIMEOUT);
+ }
+ // Open app
+ launchAppWithIntent(appPackageName);
+ // Go to overview
+ mDevice.pressRecentApps();
+ mDevice.waitForIdle();
+ // Long press on app
+ UiObject2 appObject = mDevice.wait(Until.findObject
+ (By.desc(appName)),TIMEOUT);
+ int yCoordinate = mDevice.getDisplayHeight() / 12;
+ int xCoordinate = mDevice.getDisplayWidth() / 2;
+ // Drag and drop the app object to the multiwindow area
+ appObject.drag(new Point(xCoordinate, yCoordinate), 1000);
+ // Adding a sleep to allow the drag and drop animation to finish.
+ Thread.sleep(TIMEOUT);
+ mDevice.click(mDevice.getDisplayHeight() / 4, mDevice.getDisplayWidth() / 2);
+ Assert.assertTrue("App not correctly docked to top multiwindow slot",
+ mDevice.wait(Until.hasObject(By.pkg(appPackageName)
+ .res("android:id/content")), TIMEOUT));
+ }
+
+ /*
+ * Docks two apps, one to the each half of the multiwindow screen
+ * @param topAppPackageName name of app package for top half
+ * @param topAppName Name of top app to verify on screen
+ * @param bottomAppPackageName name of app package for bottom half
+ * @throws UiObjectNotFoundException, InterruptedException
+ */
+ public void dockAppsToBothMultiwindowAreas(String topAppPackageName,
+ String topAppName, String bottomAppPackageName) throws Exception {
+ dockAppToTopMultiwindowSlot(topAppPackageName, topAppName);
+ mDevice.pressHome();
+ mDevice.waitForIdle();
+ // After docking the top app, simply launching another app
+ // will launch it in the bottom half in docked mode. This
+ // results in two apps being docked to multiwindow.
+ launchAppWithIntent(bottomAppPackageName);
+ }
+
+ /*
+ * Undocks apps from multiwindow. Only the package for the upper app
+ * is needed.
+ * @param topAppPackageName name of app package for top half
+ * @throws UiObjectNotFoundException, InterruptedException
+ */
+ public void undockAppFromMultiwindow(String topAppPackageName) throws Exception {
+ mDevice.click(mDevice.getDisplayHeight() / 4, mDevice.getDisplayWidth() / 2);
+ UiObject2 appArea = mDevice.wait(Until.findObject(By.pkg(topAppPackageName)
+ .res("android:id/content")), TIMEOUT);
+ Rect appBounds = appArea.getVisibleBounds();
+ int xCoordinate = mDevice.getDisplayWidth() / 2;
+ mDevice.drag(xCoordinate, appBounds.bottom, xCoordinate,
+ mDevice.getDisplayHeight() - 120, 4);
+ // Adding a sleep to allow the drag and drop animation to finish.
+ Thread.sleep(TIMEOUT);
+ }
+
+}
diff --git a/tests/functional/overviewtests/src/com/android/overview/functional/RecentsTests.java b/tests/functional/overviewtests/src/com/android/overview/functional/RecentsTests.java
new file mode 100644
index 0000000..9a3ba3d
--- /dev/null
+++ b/tests/functional/overviewtests/src/com/android/overview/functional/RecentsTests.java
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2016 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 android.overview.functional;
+
+import java.io.File;
+import java.io.IOException;
+
+import android.app.UiAutomation;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.Context;
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.os.PowerManager;
+import android.os.RemoteException;
+import android.os.SystemClock;
+import android.support.test.launcherhelper.ILauncherStrategy;
+import android.support.test.launcherhelper.LauncherStrategyFactory;
+import android.support.test.uiautomator.By;
+import android.support.test.uiautomator.Direction;
+import android.support.test.uiautomator.UiDevice;
+import android.support.test.uiautomator.UiObject2;
+import android.support.test.uiautomator.UiObjectNotFoundException;
+import android.support.test.uiautomator.Until;
+import android.test.InstrumentationTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.util.Log;
+import android.view.KeyEvent;
+
+public class RecentsTests extends InstrumentationTestCase {
+
+ private static final int TIMEOUT = 3000;
+ private static final String RECENTS = "com.android.systemui:id/recents_view";
+ private UiDevice mDevice;
+ private PackageManager mPackageManager;
+ private ILauncherStrategy mLauncherStrategy = null;
+ private OverviewHelper mOverviewHelper;
+
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+ mDevice = UiDevice.getInstance(getInstrumentation());
+ mPackageManager = getInstrumentation().getContext().getPackageManager();
+ mDevice.setOrientationNatural();
+ mLauncherStrategy = LauncherStrategyFactory.getInstance(mDevice).getLauncherStrategy();
+ mOverviewHelper = new OverviewHelper(mDevice, getInstrumentation());
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ mDevice.pressHome();
+ mDevice.unfreezeRotation();
+ mDevice.waitForIdle();
+ super.tearDown();
+ }
+
+ @MediumTest
+ public void testNavigateToRecents() throws Exception {
+ UiObject2 recents = mOverviewHelper.navigateToRecents();
+ assertNotNull("Recents view not reached on tapping recents", recents);
+ }
+
+ @MediumTest
+ public void testAddAndDismissItemInRecents() throws Exception {
+ mOverviewHelper.launchAppWithIntent("com.google.android.calculator");
+ mOverviewHelper.navigateToRecents();
+ UiObject2 dismissCalculator = mDevice.wait(Until.findObject
+ (By.desc("Dismiss Calculator.")),TIMEOUT);
+ assertNotNull("Calculator not found in Recents", dismissCalculator);
+ dismissCalculator.click();
+ mDevice.waitForIdle();
+ // Adding an extra sleep here so UiAutomator picks up
+ // the refreshed UI and not the old one, otherwise the
+ // test fails because it thinks the 'Dismiss Calculator'
+ // button is still present.
+ Thread.sleep(TIMEOUT);
+ UiObject2 afterDismissCalculator = mDevice.wait(Until.findObject
+ (By.desc("Dismiss Calculator.")),TIMEOUT);
+ assertNull("Calculator not dismissed from Recents", afterDismissCalculator);
+ }
+
+ @MediumTest
+ public void testScrollThroughRecents() throws Exception {
+ mOverviewHelper.populateRecents();
+ mOverviewHelper.navigateToRecents();
+ UiObject2 recentsView = mDevice.wait(Until.findObject
+ (By.res(RECENTS)),TIMEOUT);
+ mOverviewHelper.scrollToTopOfRecents(recentsView);
+ // After scrolling we look for the 'Clear All' button on the top
+ // right. This ensures a successful scroll.
+ UiObject2 clearAll = mDevice.wait(Until.findObject
+ (By.text("CLEAR ALL")),TIMEOUT);
+ assertNotNull("Unable to scroll to top of recents", clearAll);
+ clearAll.click();
+ Thread.sleep(TIMEOUT);
+ }
+
+ @MediumTest
+ public void testSwipeItemAwayFromRecents() throws Exception {
+ mOverviewHelper.launchAppWithIntent("com.google.android.calculator");
+ Thread.sleep(TIMEOUT);
+ mOverviewHelper.navigateToRecents();
+ UiObject2 calculatorText = mDevice.wait(Until.findObject
+ (By.desc("Calculator")),TIMEOUT);
+ // Get the bounds of the text 'Calculator' which is
+ // easily identifiable and swipe all the way from the
+ // left to the right to dismiss.
+ Rect calcBounds = calculatorText.getVisibleBounds();
+ mDevice.swipe(calcBounds.left, calcBounds.top + calcBounds.height() / 2,
+ calcBounds.right, calcBounds.top + calcBounds.height() / 2, 5);
+ // Try to refetch Calculator text
+ calculatorText = mDevice.wait(Until.findObject
+ (By.desc("Calculator")),TIMEOUT);
+ assertNull("Calculator app still present after swiping away",
+ calculatorText);
+ }
+
+ @MediumTest
+ public void testClearAllFromRecents() throws Exception {
+ mOverviewHelper.populateRecents();
+ mOverviewHelper.navigateToRecents();
+ UiObject2 recentsView = mDevice.wait(Until.findObject
+ (By.res(RECENTS)),TIMEOUT);
+ // fling to top
+ mOverviewHelper.scrollToTopOfRecents(recentsView);
+ // click clear all
+ UiObject2 clearAll = mDevice.wait(Until.findObject
+ (By.text("CLEAR ALL")),TIMEOUT);
+ clearAll.click();
+ Thread.sleep(TIMEOUT);
+ mOverviewHelper.navigateToRecents();
+ // verify empty recents list
+ assertTrue("Recent items not empty", mDevice.wait
+ (Until.hasObject(By.text("No recent items")), TIMEOUT));
+ }
+
+ @MediumTest
+ public void testDoubleTapToSwitchRecents() throws Exception {
+ mOverviewHelper.launchAppWithIntent("com.google.android.calculator");
+ mOverviewHelper.launchAppWithIntent("com.google.android.gm");
+ // Literally tapping twice as there's no 'double tap'
+ // method.
+ mDevice.pressRecentApps();
+ mDevice.pressRecentApps();
+ mDevice.waitForIdle();
+ // Verify that the app has switched to calculator after
+ // the double tap
+ UiObject2 calculatorText = mDevice.wait(Until.findObject
+ (By.desc("Calculator")),TIMEOUT);
+ }
+}