1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.system.helpers; 18 19 import android.app.Instrumentation; 20 import android.content.Intent; 21 import android.content.pm.PackageInfo; 22 import android.content.pm.PackageManager; 23 import android.graphics.Point; 24 import android.graphics.Rect; 25 import android.os.SystemClock; 26 import android.support.test.InstrumentationRegistry; 27 import android.support.test.uiautomator.By; 28 import android.support.test.uiautomator.UiDevice; 29 import android.support.test.uiautomator.UiObject2; 30 import android.support.test.uiautomator.UiObjectNotFoundException; 31 import android.support.test.uiautomator.Until; 32 import android.system.helpers.ActivityHelper; 33 import android.util.Log; 34 35 import org.junit.Assert; 36 37 import java.io.IOException; 38 import java.util.ArrayList; 39 import java.util.List; 40 41 /** 42 * Implement common helper methods for Overview. 43 */ 44 public class OverviewHelper { 45 46 private static final String TAG = OverviewHelper.class.getSimpleName(); 47 private static final int TIMEOUT = 3000; 48 private static final String RECENTS = "com.android.systemui:id/recents_view"; 49 50 private UiDevice mDevice = null; 51 private Instrumentation mInstrumentation = null; 52 private ActivityHelper mActHelper = null; 53 private final CommandsHelper mCommandsHelper; 54 public static OverviewHelper sInstance = null; 55 OverviewHelper()56 public OverviewHelper() { 57 mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()); 58 mInstrumentation = InstrumentationRegistry.getInstrumentation(); 59 mActHelper = ActivityHelper.getInstance(); 60 mCommandsHelper = CommandsHelper.getInstance(mInstrumentation); 61 } 62 getInstance()63 public static OverviewHelper getInstance() { 64 if (sInstance == null) { 65 sInstance = new OverviewHelper(); 66 } 67 return sInstance; 68 } 69 70 /** 71 * Navigates to the recents screen 72 * @returns recents object 73 * @throws UiObjectNotFoundException 74 */ navigateToRecents()75 public UiObject2 navigateToRecents() throws Exception { 76 mDevice.pressRecentApps(); 77 mDevice.waitForIdle(); 78 return mDevice.wait(Until.findObject(By.res(RECENTS)), TIMEOUT); 79 } 80 81 /** 82 * Populates recents by launching six apps 83 * @throws InterruptedException 84 */ populateRecents()85 public void populateRecents() throws InterruptedException { 86 // We launch six apps, since five is the maximum number 87 // of apps under Recents 88 String[] appPackages = {"com.google.android.gm", 89 "com.google.android.deskclock", "com.android.settings", 90 "com.google.android.youtube", "com.google.android.contacts", 91 "com.google.android.apps.maps"}; 92 for (String appPackage : appPackages) { 93 mActHelper.launchPackage(appPackage); 94 } 95 } 96 populateManyRecentApps()97 public ArrayList<String> populateManyRecentApps() throws IOException { 98 PackageManager pm = mInstrumentation.getContext().getPackageManager(); 99 List<PackageInfo> packages = pm.getInstalledPackages(0); 100 ArrayList<String> launchedPackages = new ArrayList<>(); 101 for (PackageInfo pkg : packages) { 102 if (pkg.packageName.equals(mInstrumentation.getTargetContext().getPackageName())) { 103 continue; 104 } 105 Intent intent = pm.getLaunchIntentForPackage(pkg.packageName); 106 if (intent == null) { 107 continue; 108 } 109 intent.addCategory(Intent.CATEGORY_LAUNCHER); 110 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 111 try { 112 mInstrumentation.getTargetContext().startActivity(intent); 113 } catch (SecurityException e) { 114 Log.i(TAG, "Failed to start package " + pkg.packageName + ", exception: " + e); 115 } 116 117 // Don't overload the system 118 SystemClock.sleep(500); 119 launchedPackages.add(pkg.packageName); 120 } 121 122 // Give the apps some time to finish starting. Some apps start another activity while 123 // starting, and we don't want to happen when we are testing stuff. 124 SystemClock.sleep(3000); 125 126 // Close any crash dialogs 127 while (mDevice.hasObject(By.textContains("has stopped"))) { 128 UiObject2 crashDialog = mDevice.findObject(By.text("Close")); 129 if (crashDialog != null) { 130 crashDialog.clickAndWait(Until.newWindow(), 2000); 131 } 132 } 133 return launchedPackages; 134 } 135 forceStopPackages(ArrayList<String> packages)136 public void forceStopPackages(ArrayList<String> packages) { 137 for (String pkg : packages) { 138 mCommandsHelper.executeShellCommand("am force-stop " + pkg); 139 } 140 } 141 142 /** 143 * Scrolls through given recents object to the top 144 * @param recents Recents object 145 */ scrollToTopOfRecents(UiObject2 recents)146 public void scrollToTopOfRecents(UiObject2 recents) { 147 Rect r = recents.getVisibleBounds(); 148 // decide the top & bottom edges for scroll gesture 149 int top = r.top + r.height() / 4; // top edge = top + 25% height 150 int bottom = r.bottom - 200; // bottom edge = bottom & shift up 200px 151 mDevice.swipe(r.width() / 2, top, r.width() / 2, bottom, 5); 152 mDevice.waitForIdle(); 153 } 154 155 /** 156 * Docks an app to the top half of the multiwindow screen 157 * @param appPackageName name of app package 158 * @param appName Name of app to verify on screen 159 * @throws UiObjectNotFoundException, InterruptedException 160 */ dockAppToTopMultiwindowSlot(String appPackageName, String appName)161 public void dockAppToTopMultiwindowSlot(String appPackageName, String appName) 162 throws Exception { 163 mDevice.pressRecentApps(); 164 mDevice.waitForIdle(); 165 UiObject2 recentsView = mDevice.wait(Until.findObject 166 (By.res("com.android.systemui:id/recents_view")),TIMEOUT); 167 // Check if recents isn't already empty, if not, clear it. 168 if (!mDevice.wait(Until.hasObject(By.text("No recent items")),TIMEOUT)) { 169 scrollToTopOfRecents(recentsView); 170 // click clear all 171 UiObject2 clearAll = mDevice.wait(Until.findObject(By.text("CLEAR ALL")),TIMEOUT); 172 if (!clearAll.equals(null)) { 173 clearAll.click(); 174 } 175 Thread.sleep(TIMEOUT); 176 } 177 // Open app 178 mActHelper.launchPackage(appPackageName); 179 // Go to overview 180 mDevice.pressRecentApps(); 181 mDevice.waitForIdle(); 182 // Long press on app 183 UiObject2 appObject = mDevice.wait(Until.findObject 184 (By.desc(appName)),TIMEOUT); 185 int yCoordinate = mDevice.getDisplayHeight() / 12; 186 int xCoordinate = mDevice.getDisplayWidth() / 2; 187 // Drag and drop the app object to the multiwindow area 188 appObject.drag(new Point(xCoordinate, yCoordinate), 1000); 189 // Adding a sleep to allow the drag and drop animation to finish. 190 Thread.sleep(TIMEOUT); 191 mDevice.click(mDevice.getDisplayHeight() / 4, mDevice.getDisplayWidth() / 2); 192 Assert.assertTrue("App not correctly docked to top multiwindow slot", 193 mDevice.wait(Until.hasObject(By.pkg(appPackageName) 194 .res("android:id/content")), TIMEOUT)); 195 } 196 197 /** 198 * Docks two apps, one to the each half of the multiwindow screen 199 * @param topAppPackageName name of app package for top half 200 * @param topAppName Name of top app to verify on screen 201 * @param bottomAppPackageName name of app package for bottom half 202 * @throws UiObjectNotFoundException, InterruptedException 203 */ dockAppsToBothMultiwindowAreas(String topAppPackageName, String topAppName, String bottomAppPackageName)204 public void dockAppsToBothMultiwindowAreas(String topAppPackageName, 205 String topAppName, String bottomAppPackageName) throws Exception { 206 dockAppToTopMultiwindowSlot(topAppPackageName, topAppName); 207 mDevice.pressHome(); 208 mDevice.waitForIdle(); 209 // After docking the top app, simply launching another app 210 // will launch it in the bottom half in docked mode. This 211 // results in two apps being docked to multiwindow. 212 mActHelper.launchPackage(bottomAppPackageName); 213 } 214 215 /** 216 * Undocks apps from multiwindow. Only the package for the upper app is needed. 217 * @param topAppPackageName name of app package for top half 218 * @throws UiObjectNotFoundException, InterruptedException 219 */ undockAppFromMultiwindow(String topAppPackageName)220 public void undockAppFromMultiwindow(String topAppPackageName) throws Exception { 221 mDevice.click(mDevice.getDisplayHeight() / 4, mDevice.getDisplayWidth() / 2); 222 UiObject2 appArea = mDevice.wait(Until.findObject(By.pkg(topAppPackageName) 223 .res("android:id/content")), TIMEOUT); 224 Rect appBounds = appArea.getVisibleBounds(); 225 int xCoordinate = mDevice.getDisplayWidth() / 2; 226 mDevice.drag(xCoordinate, appBounds.bottom, xCoordinate, 227 mDevice.getDisplayHeight() - 120, 4); 228 // Adding a sleep to allow the drag and drop animation to finish. 229 Thread.sleep(TIMEOUT); 230 } 231 }