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);
+    }
+}