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.content.Context;
20 import android.content.Intent;
21 import android.os.RemoteException;
22 import android.util.Log;
23 import android.view.KeyEvent;
24 
25 import androidx.test.InstrumentationRegistry;
26 import androidx.test.uiautomator.By;
27 import androidx.test.uiautomator.UiDevice;
28 import androidx.test.uiautomator.UiScrollable;
29 import androidx.test.uiautomator.UiSelector;
30 import androidx.test.uiautomator.Until;
31 
32 import junit.framework.Assert;
33 
34 import java.util.regex.Matcher;
35 import java.util.regex.Pattern;
36 
37 /**
38  * Implement common helper methods for activities.
39  */
40 public class ActivityHelper {
41     private static final String TAG = ActivityHelper.class.getSimpleName();
42 
43     public static final String SYSTEMUI_PACKAGE = "com.android.systemui";
44     public static final int FULLSCREEN = 1;
45     public static final int SPLITSCREEN = 3;
46     public static final int ONE_SECOND = 1000;
47     public static final int INVALID_TASK_ID = -1;
48     private static final String NEXUS_LAUNCHER = "com.google.android.apps.nexuslauncher";
49 
50     private static ActivityHelper sInstance = null;
51     private Context mContext = null;
52     private UiDevice mDevice = null;
53 
ActivityHelper()54     public ActivityHelper() {
55         mContext = InstrumentationRegistry.getTargetContext();
56         mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
57     }
58 
getInstance()59     public static ActivityHelper getInstance() {
60         if (sInstance == null) {
61             sInstance = new ActivityHelper();
62         }
63         return sInstance;
64     }
65 
66     /**
67      * Gets task id for an activity
68      *
69      * @param pkgName
70      * @param activityName
71      * @return taskId or -1 when no activity is found
72      */
getTaskIdForActivity(String pkgName, String activityName)73     public int getTaskIdForActivity(String pkgName, String activityName) {
74         int taskId = INVALID_TASK_ID;
75         // Find task id for given package and activity
76         final Pattern TASK_REGEX = Pattern.compile(
77                 String.format("taskId=(\\d+): %s/%s", pkgName, activityName));
78         Matcher matcher = TASK_REGEX.matcher(CommandsHelper.execute("am stack list"));
79         if (matcher.find()) {
80             taskId = Integer.parseInt(matcher.group(1));
81             Log.i(TAG, String.format("TaskId found: %d for %s/%s",
82                     taskId, pkgName, activityName));
83         }
84         Assert.assertTrue("Taskid hasn't been found", taskId != -1);
85         return taskId;
86     }
87 
88     /**
89      * Helper to change window mode between fullscreen and splitscreen for a given task
90      *
91      * @param taskId
92      * @param mode
93      * @throws InterruptedException
94      */
changeWindowMode(int taskId, int mode)95     public void changeWindowMode(int taskId, int mode) throws InterruptedException {
96         CommandsHelper.execute(
97                 String.format("am stack move-task %d %d true", taskId, mode));
98         Thread.sleep(ONE_SECOND);
99     }
100 
101     /**
102      * Clears apps in overview/recents
103      *
104      * @throws InterruptedException
105      * @throws RemoteException
106      */
clearRecents()107     public void clearRecents() throws InterruptedException, RemoteException {
108         // Launch recents if it's not already
109         int retry = 5;
110         while (!mDevice.wait(Until.hasObject(By.res(SYSTEMUI_PACKAGE, "recents_view")),
111                 ONE_SECOND * 5) && --retry > 0) {
112             mDevice.pressRecentApps();
113             Thread.sleep(ONE_SECOND);
114         }
115         // Return if there is no apps in recents
116         if (mDevice.wait(Until.hasObject(By.text("No recent items")), ONE_SECOND * 5)) {
117             return;
118         } else {
119             Assert.assertTrue("Device expects recent items", mDevice.wait(Until.hasObject(
120                     By.res(SYSTEMUI_PACKAGE, "recents_view")), ONE_SECOND * 5));
121         }
122         // Get recents items
123         int recents = mDevice.wait(Until.findObjects(
124                 By.res(SYSTEMUI_PACKAGE, "task_view_thumbnail")), ONE_SECOND * 5).size();
125         // Clear recents
126         for (int i = 0; i < recents; ++i) {
127             mDevice.pressKeyCode(KeyEvent.KEYCODE_APP_SWITCH);
128             Thread.sleep(ONE_SECOND);
129             mDevice.pressKeyCode(KeyEvent.KEYCODE_DEL);
130             Thread.sleep(ONE_SECOND);
131         }
132     }
133 
134     /**
135      * Clear recent apps by click 'CLEAR ALL' button in the recents view.
136      *
137      * @param maxScroll max number of scroll in recents view.
138      * @throws Exception
139      */
clearRecentsByClearAll(int maxScroll)140     public void clearRecentsByClearAll(int maxScroll) throws Exception {
141         int retry = 5;
142         while (!mDevice.wait(Until.hasObject(By.res(NEXUS_LAUNCHER, "overview_panel")),
143                 ONE_SECOND * 5) && --retry > 0) {
144             mDevice.pressRecentApps();
145             Thread.sleep(ONE_SECOND);
146         }
147         while (mDevice.findObject(By.res(NEXUS_LAUNCHER, "overview_panel"))
148                 .isScrollable() && maxScroll-- >= 0) {
149             UiScrollable thumbnailScrollable = new UiScrollable(new UiSelector().resourceId(
150                     NEXUS_LAUNCHER + ":id/overview_panel"));
151             thumbnailScrollable.setAsHorizontalList();
152             thumbnailScrollable.scrollBackward();
153             if (!mDevice.wait(Until.hasObject(By.text(
154                     Pattern.compile("CLEAR ALL", Pattern.CASE_INSENSITIVE))), ONE_SECOND * 2)) {
155                 continue;
156             } else {
157                 int tries = 3;
158                 while (mDevice.hasObject(By.text(
159                         Pattern.compile("CLEAR ALL", Pattern.CASE_INSENSITIVE))) && tries-- > 0) {
160                     mDevice.findObject(By.text(
161                             Pattern.compile("CLEAR ALL", Pattern.CASE_INSENSITIVE))).click();
162                     Thread.sleep(ONE_SECOND * 2);
163                 }
164                 break;
165             }
166         }
167     }
168 
169     /**
170      * Clear recents apps by click 'CLEAR ALL' button in recents view, default max scroll 20.
171      *
172      * @throws Exception
173      */
clearRecentsByClearAll()174     public void clearRecentsByClearAll() throws Exception {
175         clearRecentsByClearAll(20);
176     }
177 
178     /**
179      * Enable/disable bmgr service
180      *
181      * @param enable true to enable, false to disable
182      */
enableBmgr(boolean enable)183     public void enableBmgr(boolean enable) {
184         String output = CommandsHelper.execute("bmgr enable " + Boolean.toString(enable));
185         if (enable) {
186             Assert.assertTrue("Bmgr not enabled",
187                     output.indexOf("Backup Manager now enabled") >= 0);
188         } else {
189             Assert.assertTrue("Bmgr not disabled",
190                     output.indexOf("Backup Manager now disabled") >= 0);
191         }
192     }
193 
194     /**
195      * Launch an intent when intent is of string type
196      *
197      * @param intentName
198      * @throws InterruptedException
199      */
launchIntent(String intentName)200     public void launchIntent(String intentName) throws InterruptedException {
201         mDevice.pressHome();
202         Intent intent = new Intent(intentName);
203         launchIntent(intent);
204     }
205 
206     /**
207      * Find intent of a package and launch
208      *
209      * @param pkgName
210      * @throws InterruptedException
211      */
launchPackage(String pkgName)212     public void launchPackage(String pkgName) throws InterruptedException {
213         Intent pkgIntent = mContext.getPackageManager()
214                 .getLaunchIntentForPackage(pkgName);
215         launchIntent(pkgIntent);
216     }
217 
218     /**
219      * launch an intent when intent is of Intent type
220      *
221      * @param intent
222      * @throws InterruptedException
223      */
launchIntent(Intent intent)224     public void launchIntent(Intent intent) throws InterruptedException {
225         intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
226         mContext.startActivity(intent);
227         Thread.sleep(ONE_SECOND * 5);
228     }
229 }
230