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