• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2015 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 com.android.shell;
18 
19 import android.app.Instrumentation;
20 import android.app.StatusBarManager;
21 import android.os.SystemClock;
22 import android.support.test.uiautomator.By;
23 import android.support.test.uiautomator.UiDevice;
24 import android.support.test.uiautomator.UiObject;
25 import android.support.test.uiautomator.UiObject2;
26 import android.support.test.uiautomator.UiObjectNotFoundException;
27 import android.support.test.uiautomator.UiSelector;
28 import android.support.test.uiautomator.Until;
29 import android.text.format.DateUtils;
30 import android.util.Log;
31 
32 import static junit.framework.Assert.assertFalse;
33 import static junit.framework.Assert.assertNotNull;
34 import static junit.framework.Assert.assertTrue;
35 
36 import java.util.List;
37 
38 /**
39  * A helper class for UI-related testing tasks.
40  */
41 final class UiBot {
42 
43     private static final String TAG = "UiBot";
44     private static final String SYSTEMUI_PACKAGE = "com.android.systemui";
45     private static final String ANDROID_PACKAGE = "android";
46 
47     private static final long SHORT_UI_TIMEOUT_MS = (3 * DateUtils.SECOND_IN_MILLIS);
48 
49     private final Instrumentation mInstrumentation;
50     private final UiDevice mDevice;
51     private final int mTimeout;
52 
UiBot(Instrumentation instrumentation, int timeout)53     public UiBot(Instrumentation instrumentation, int timeout) {
54         mInstrumentation = instrumentation;
55         mDevice = UiDevice.getInstance(instrumentation);
56         mTimeout = timeout;
57     }
58 
59     /**
60      * Opens the system notification and gets a UiObject with the text.
61      *
62      * @param text Notification's text as displayed by the UI.
63      * @return notification object.
64      */
getNotification(String text)65     public UiObject getNotification(String text) {
66         boolean opened = mDevice.openNotification();
67         Log.v(TAG, "openNotification(): " + opened);
68         boolean gotIt = mDevice.wait(Until.hasObject(By.pkg(SYSTEMUI_PACKAGE)), mTimeout);
69         assertTrue("could not get system ui (" + SYSTEMUI_PACKAGE + ")", gotIt);
70 
71         return getObject(text);
72     }
73 
74     /**
75      * Opens the system notification and gets a notification containing the text.
76      *
77      * @param text Notification's text as displayed by the UI.
78      * @return notification object.
79      */
getNotification2(String text)80     public UiObject2 getNotification2(String text) {
81         boolean opened = mDevice.openNotification();
82         Log.v(TAG, "openNotification(): " + opened);
83         final UiObject2 notificationScroller = mDevice.wait(Until.findObject(
84                 By.res(SYSTEMUI_PACKAGE, "notification_stack_scroller")), mTimeout);
85         assertNotNull("could not get notification stack scroller", notificationScroller);
86         final List<UiObject2> notificationList = notificationScroller.getChildren();
87         for (UiObject2 notification: notificationList) {
88             final UiObject2 notificationText = notification.findObject(By.textContains(text));
89             if (notificationText != null) {
90                 return notification;
91             }
92         }
93         return null;
94     }
95 
96     /**
97      * Expands the notification.
98      *
99      * @param notification The notification object returned by {@link #getNotification2(String)}.
100      */
expandNotification(UiObject2 notification)101     public void expandNotification(UiObject2 notification) {
102         final UiObject2 expandBtn =  notification.findObject(
103                 By.res(ANDROID_PACKAGE, "expand_button"));
104         if (expandBtn.getContentDescription().equals("Collapse")) {
105             return;
106         }
107         expandBtn.click();
108         mDevice.waitForIdle();
109     }
110 
collapseStatusBar()111     public void collapseStatusBar() throws Exception {
112         // TODO: mDevice should provide such method..
113         StatusBarManager sbm =
114                 (StatusBarManager) mInstrumentation.getContext().getSystemService("statusbar");
115         sbm.collapsePanels();
116     }
117 
118     /**
119      * Opens the system notification and clicks a given notification.
120      *
121      * @param text Notificaton's text as displayed by the UI.
122      */
clickOnNotification(String text)123     public void clickOnNotification(String text) {
124         UiObject notification = getNotification(text);
125         click(notification, "bug report notification");
126     }
127 
128     /**
129      * Gets an object that might not yet be available in current UI.
130      *
131      * @param text Object's text as displayed by the UI.
132      */
getObject(String text)133     public UiObject getObject(String text) {
134         boolean gotIt = mDevice.wait(Until.hasObject(By.text(text)), mTimeout);
135         assertTrue("object with text '(" + text + "') not visible yet", gotIt);
136         return getVisibleObject(text);
137     }
138 
139     /**
140      * Gets an object that might not yet be available in current UI.
141      *
142      * @param id Object's fully-qualified resource id (like {@code android:id/button1})
143      */
getObjectById(String id)144     public UiObject getObjectById(String id) {
145         boolean gotIt = mDevice.wait(Until.hasObject(By.res(id)), mTimeout);
146         assertTrue("object with id '(" + id + "') not visible yet", gotIt);
147         return getVisibleObjectById(id);
148     }
149 
150     /**
151      * Gets an object which is guaranteed to be present in the current UI.
152      *
153      * @param text Object's text as displayed by the UI.
154      */
getVisibleObject(String text)155     public UiObject getVisibleObject(String text) {
156         UiObject uiObject = mDevice.findObject(new UiSelector().text(text));
157         assertTrue("could not find object with text '" + text + "'", uiObject.exists());
158         return uiObject;
159     }
160 
161     /**
162      * Gets an object which is guaranteed to be present in the current UI.
163      *
164      * @param text Object's text as displayed by the UI.
165      */
getVisibleObjectById(String id)166     public UiObject getVisibleObjectById(String id) {
167         UiObject uiObject = mDevice.findObject(new UiSelector().resourceId(id));
168         assertTrue("could not find object with id '" + id+ "'", uiObject.exists());
169         return uiObject;
170     }
171 
172     /**
173      * Asserts an object is not visible.
174      */
assertNotVisibleById(String id)175     public void assertNotVisibleById(String id) {
176         // TODO: not working when the bugreport dialog is shown, it hangs until the dialog is
177         // dismissed and hence always work.
178         boolean hasIt = mDevice.hasObject(By.res(id));
179         assertFalse("should not have found object with id '" + id+ "'", hasIt);
180     }
181 
182 
183     /**
184      * Clicks on a UI element.
185      *
186      * @param uiObject UI element to be clicked.
187      * @param description Elements's description used on logging statements.
188      */
click(UiObject uiObject, String description)189     public void click(UiObject uiObject, String description) {
190         try {
191             boolean clicked = uiObject.click();
192             // TODO: assertion below fails sometimes, even though the click succeeded,
193             // (specially when clicking the "Just Once" button), so it's currently just logged.
194             // assertTrue("could not click on object '" + description + "'", clicked);
195 
196             Log.v(TAG, "onClick for " + description + ": " + clicked);
197         } catch (UiObjectNotFoundException e) {
198             throw new IllegalStateException("exception when clicking on object '" + description
199                     + "'", e);
200         }
201     }
202 
203     /**
204      * Chooses a given activity to handle an Intent.
205      *
206      * @param name name of the activity as displayed in the UI (typically the value set by
207      *            {@code android:label} in the manifest).
208      */
chooseActivity(String name)209     public void chooseActivity(String name) {
210         // It uses an intent chooser now, so just getting the activity by text is enough...
211         final String share = mInstrumentation.getContext().getString(
212                 com.android.internal.R.string.share);
213         boolean gotIt = mDevice.wait(Until.hasObject(By.text(share)), mTimeout);
214         assertTrue("could not get share activity (" + share + ")", gotIt);
215         swipeUp();
216         SystemClock.sleep(SHORT_UI_TIMEOUT_MS);
217         UiObject activity = getObject(name);
218         click(activity, name);
219     }
220 
pressBack()221     public void pressBack() {
222         mDevice.pressBack();
223     }
224 
turnScreenOn()225     public void turnScreenOn() throws Exception {
226         mDevice.executeShellCommand("input keyevent KEYCODE_WAKEUP");
227         mDevice.executeShellCommand("wm dismiss-keyguard");
228         mDevice.waitForIdle();
229     }
230 
swipeUp()231     public void swipeUp() {
232         mDevice.swipe(mDevice.getDisplayWidth() / 2, mDevice.getDisplayHeight() * 3 / 4,
233                 mDevice.getDisplayWidth() / 2, 0, 30);
234     }
235 }
236