blob: e00a2474556cedc877d61ea9b7c0e8268bf89559 [file] [log] [blame]
Vishnu Nair8248b7c2018-08-01 10:13:36 -07001/*
2 * Copyright (C) 2018 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
17package com.android.server.wm.flicker;
18
19import static android.os.SystemClock.sleep;
20import static android.system.helpers.OverviewHelper.isRecentsInLauncher;
21import static android.view.Surface.ROTATION_0;
22
23import static com.android.compatibility.common.util.SystemUtil.runShellCommand;
24
25import static org.junit.Assert.assertNotNull;
26import static org.junit.Assert.fail;
27
28import android.content.Context;
29import android.content.pm.PackageManager;
30import android.graphics.Point;
31import android.graphics.Rect;
32import android.os.RemoteException;
Vishnu Nair8248b7c2018-08-01 10:13:36 -070033import android.support.test.launcherhelper.LauncherStrategyFactory;
34import android.support.test.uiautomator.By;
35import android.support.test.uiautomator.BySelector;
36import android.support.test.uiautomator.Configurator;
37import android.support.test.uiautomator.UiDevice;
38import android.support.test.uiautomator.UiObject2;
39import android.support.test.uiautomator.Until;
40import android.util.Log;
41import android.util.Rational;
42import android.view.View;
43import android.view.ViewConfiguration;
44
Brett Chabot502ec7a2019-03-01 14:43:20 -080045import androidx.test.InstrumentationRegistry;
46
Vishnu Nair8248b7c2018-08-01 10:13:36 -070047/**
48 * Collection of UI Automation helper functions.
49 */
50public class AutomationUtils {
51 private static final String SYSTEMUI_PACKAGE = "com.android.systemui";
52 private static final long FIND_TIMEOUT = 10000;
53 private static final long LONG_PRESS_TIMEOUT = ViewConfiguration.getLongPressTimeout() * 2L;
54 private static final String TAG = "FLICKER";
55
56 public static void wakeUpAndGoToHomeScreen() {
57 UiDevice device = UiDevice.getInstance(InstrumentationRegistry
58 .getInstrumentation());
59 try {
60 device.wakeUp();
61 } catch (RemoteException e) {
62 throw new RuntimeException(e);
63 }
64 device.pressHome();
65 }
66
67 /**
68 * Sets {@link android.app.UiAutomation#waitForIdle(long, long)} global timeout to 0 causing
69 * the {@link android.app.UiAutomation#waitForIdle(long, long)} function to timeout instantly.
70 * This removes some delays when using the UIAutomator library required to create fast UI
71 * transitions.
72 */
73 static void setFastWait() {
74 Configurator.getInstance().setWaitForIdleTimeout(0);
75 }
76
77 /**
78 * Reverts {@link android.app.UiAutomation#waitForIdle(long, long)} to default behavior.
79 */
80 static void setDefaultWait() {
81 Configurator.getInstance().setWaitForIdleTimeout(10000);
82 }
83
84 public static boolean isQuickstepEnabled(UiDevice device) {
85 return device.findObject(By.res(SYSTEMUI_PACKAGE, "recent_apps")) == null;
86 }
87
88 public static void openQuickstep(UiDevice device) {
89 if (isQuickstepEnabled(device)) {
90 int height = device.getDisplayHeight();
91 UiObject2 navBar = device.findObject(By.res(SYSTEMUI_PACKAGE, "navigation_bar_frame"));
92
93 Rect navBarVisibleBounds;
94
95 // TODO(vishnun) investigate why this object cannot be found.
96 if (navBar != null) {
97 navBarVisibleBounds = navBar.getVisibleBounds();
98 } else {
99 Log.e(TAG, "Could not find nav bar, infer location");
100 navBarVisibleBounds = WindowUtils.getNavigationBarPosition(ROTATION_0);
101 }
102
103 // Swipe from nav bar to 2/3rd down the screen.
104 device.swipe(
105 navBarVisibleBounds.centerX(), navBarVisibleBounds.centerY(),
106 navBarVisibleBounds.centerX(), height * 2 / 3,
107 (navBarVisibleBounds.centerY() - height * 2 / 3) / 100); // 100 px/step
108 } else {
109 try {
110 device.pressRecentApps();
111 } catch (RemoteException e) {
112 throw new RuntimeException(e);
113 }
114 }
115 BySelector RECENTS = By.res(SYSTEMUI_PACKAGE, "recents_view");
116
117 // use a long timeout to wait until recents populated
118 if (device.wait(
119 Until.findObject(isRecentsInLauncher()
120 ? getLauncherOverviewSelector(device) : RECENTS),
121 10000) == null) {
122 fail("Recents didn't appear");
123 }
124 device.waitForIdle();
125 }
126
127 static void clearRecents(UiDevice device) {
128 if (isQuickstepEnabled(device)) {
129 openQuickstep(device);
130
131 for (int i = 0; i < 5; i++) {
132 device.swipe(device.getDisplayWidth() / 2,
133 device.getDisplayHeight() / 2, device.getDisplayWidth(),
134 device.getDisplayHeight() / 2,
135 5);
136
137 BySelector clearAllSelector = By.res("com.google.android.apps.nexuslauncher",
138 "clear_all_button");
139 UiObject2 clearAllButton = device.wait(Until.findObject(clearAllSelector), 100);
140 if (clearAllButton != null) {
141 clearAllButton.click();
142 return;
143 }
144 }
145 }
146 }
147
148 private static BySelector getLauncherOverviewSelector(UiDevice device) {
149 return By.res(device.getLauncherPackageName(), "overview_panel");
150 }
151
152 private static void longPressRecents(UiDevice device) {
153 BySelector recentsSelector = By.res(SYSTEMUI_PACKAGE, "recent_apps");
154 UiObject2 recentsButton = device.wait(Until.findObject(recentsSelector), FIND_TIMEOUT);
155 assertNotNull("Unable to find recents button", recentsButton);
156 recentsButton.click(LONG_PRESS_TIMEOUT);
157 }
158
159 public static void launchSplitScreen(UiDevice device) {
160 String mLauncherPackage = LauncherStrategyFactory.getInstance(device)
161 .getLauncherStrategy().getSupportedLauncherPackage();
162
163 if (isQuickstepEnabled(device)) {
164 // Quickstep enabled
165 openQuickstep(device);
166
167 BySelector overviewIconSelector = By.res(mLauncherPackage, "icon")
168 .clazz(View.class);
169 UiObject2 overviewIcon = device.wait(Until.findObject(overviewIconSelector),
170 FIND_TIMEOUT);
171 assertNotNull("Unable to find app icon in Overview", overviewIcon);
172 overviewIcon.click();
173
174 BySelector splitscreenButtonSelector = By.text("Split screen");
175 UiObject2 splitscreenButton = device.wait(Until.findObject(splitscreenButtonSelector),
176 FIND_TIMEOUT);
Nataniel Borges7b3ec112019-01-30 17:29:13 -0800177 assertNotNull("Unable to find Split screen button in Overview", splitscreenButton);
Vishnu Nair8248b7c2018-08-01 10:13:36 -0700178 splitscreenButton.click();
179 } else {
180 // Classic long press recents
181 longPressRecents(device);
182 }
183 // Wait for animation to complete.
184 sleep(2000);
185 }
186
187 public static void exitSplitScreen(UiDevice device) {
188 if (isQuickstepEnabled(device)) {
189 // Quickstep enabled
190 BySelector dividerSelector = By.res(SYSTEMUI_PACKAGE, "docked_divider_handle");
191 UiObject2 divider = device.wait(Until.findObject(dividerSelector), FIND_TIMEOUT);
192 assertNotNull("Unable to find Split screen divider", divider);
193
194 // Drag the split screen divider to the top of the screen
195 divider.drag(new Point(device.getDisplayWidth() / 2, 0), 400);
196 } else {
197 // Classic long press recents
198 longPressRecents(device);
199 }
200 // Wait for animation to complete.
201 sleep(2000);
202 }
203
204 static void resizeSplitScreen(UiDevice device, Rational windowHeightRatio) {
205 BySelector dividerSelector = By.res(SYSTEMUI_PACKAGE, "docked_divider_handle");
206 UiObject2 divider = device.wait(Until.findObject(dividerSelector), FIND_TIMEOUT);
207 assertNotNull("Unable to find Split screen divider", divider);
208 int destHeight =
209 (int) (WindowUtils.getDisplayBounds().height() * windowHeightRatio.floatValue());
210 // Drag the split screen divider to so that the ratio of top window height and bottom
211 // window height is windowHeightRatio
212 device.drag(divider.getVisibleBounds().centerX(), divider.getVisibleBounds().centerY(),
213 device.getDisplayWidth() / 2, destHeight, 10);
214 //divider.drag(new Point(device.getDisplayWidth() / 2, destHeight), 400)
215 divider = device.wait(Until.findObject(dividerSelector), FIND_TIMEOUT);
216
217 // Wait for animation to complete.
218 sleep(2000);
219 }
220
221 static void closePipWindow(UiDevice device) {
222 UiObject2 pipWindow = device.findObject(
223 By.res(SYSTEMUI_PACKAGE, "background"));
224 pipWindow.click();
225 UiObject2 exitPipObject = device.findObject(
226 By.res(SYSTEMUI_PACKAGE, "dismiss"));
227 exitPipObject.click();
228 // Wait for animation to complete.
229 sleep(2000);
230 }
231
232 static void expandPipWindow(UiDevice device) {
233 UiObject2 pipWindow = device.findObject(
234 By.res(SYSTEMUI_PACKAGE, "background"));
235 pipWindow.click();
236 pipWindow.click();
237 }
238
239 public static void stopPackage(Context context, String packageName) {
240 runShellCommand("am force-stop " + packageName);
241 int packageUid;
242 try {
243 packageUid = context.getPackageManager().getPackageUid(packageName, /* flags= */0);
244 } catch (PackageManager.NameNotFoundException e) {
245 return;
246 }
247 while (targetPackageIsRunning(packageUid)) {
248 try {
249 Thread.sleep(100);
250 } catch (InterruptedException e) {
251 //ignore
252 }
253 }
254 }
255
256 private static boolean targetPackageIsRunning(int uid) {
257 final String result = runShellCommand(
258 String.format("cmd activity get-uid-state %d", uid));
259 return !result.contains("(NONEXISTENT)");
260 }
261}