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