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.support.test.uiautomator.By;
22 import android.support.test.uiautomator.UiDevice;
23 import android.support.test.uiautomator.UiObject;
24 import android.support.test.uiautomator.UiObjectNotFoundException;
25 import android.support.test.uiautomator.UiSelector;
26 import android.support.test.uiautomator.Until;
27 import android.util.Log;
28 
29 import static junit.framework.Assert.assertFalse;
30 import static junit.framework.Assert.assertTrue;
31 
32 /**
33  * A helper class for UI-related testing tasks.
34  */
35 final class UiBot {
36 
37     private static final String TAG = "UiBot";
38     private static final String SYSTEMUI_PACKAGE = "com.android.systemui";
39 
40     private final Instrumentation mInstrumentation;
41     private final UiDevice mDevice;
42     private final int mTimeout;
43 
UiBot(Instrumentation instrumentation, int timeout)44     public UiBot(Instrumentation instrumentation, int timeout) {
45         mInstrumentation = instrumentation;
46         mDevice = UiDevice.getInstance(instrumentation);
47         mTimeout = timeout;
48     }
49 
50     /**
51      * Opens the system notification and gets a given notification.
52      *
53      * @param text Notificaton's text as displayed by the UI.
54      * @return notification object.
55      */
getNotification(String text)56     public UiObject getNotification(String text) {
57         boolean opened = mDevice.openNotification();
58         Log.v(TAG, "openNotification(): " + opened);
59         boolean gotIt = mDevice.wait(Until.hasObject(By.pkg(SYSTEMUI_PACKAGE)), mTimeout);
60         assertTrue("could not get system ui (" + SYSTEMUI_PACKAGE + ")", gotIt);
61 
62         return getObject(text);
63     }
64 
collapseStatusBar()65     public void collapseStatusBar() throws Exception {
66         // TODO: mDevice should provide such method..
67         StatusBarManager sbm =
68                 (StatusBarManager) mInstrumentation.getContext().getSystemService("statusbar");
69         sbm.collapsePanels();
70     }
71 
72     /**
73      * Opens the system notification and clicks a given notification.
74      *
75      * @param text Notificaton's text as displayed by the UI.
76      */
clickOnNotification(String text)77     public void clickOnNotification(String text) {
78         UiObject notification = getNotification(text);
79         click(notification, "bug report notification");
80     }
81 
82     /**
83      * Gets an object that might not yet be available in current UI.
84      *
85      * @param text Object's text as displayed by the UI.
86      */
getObject(String text)87     public UiObject getObject(String text) {
88         boolean gotIt = mDevice.wait(Until.hasObject(By.text(text)), mTimeout);
89         assertTrue("object with text '(" + text + "') not visible yet", gotIt);
90         return getVisibleObject(text);
91     }
92 
93     /**
94      * Gets an object that might not yet be available in current UI.
95      *
96      * @param id Object's fully-qualified resource id (like {@code android:id/button1})
97      */
getObjectById(String id)98     public UiObject getObjectById(String id) {
99         boolean gotIt = mDevice.wait(Until.hasObject(By.res(id)), mTimeout);
100         assertTrue("object with id '(" + id + "') not visible yet", gotIt);
101         return getVisibleObjectById(id);
102     }
103 
104     /**
105      * Gets an object which is guaranteed to be present in the current UI.
106      *
107      * @param text Object's text as displayed by the UI.
108      */
getVisibleObject(String text)109     public UiObject getVisibleObject(String text) {
110         UiObject uiObject = mDevice.findObject(new UiSelector().text(text));
111         assertTrue("could not find object with text '" + text + "'", uiObject.exists());
112         return uiObject;
113     }
114 
115     /**
116      * Gets an object which is guaranteed to be present in the current UI.
117      *
118      * @param text Object's text as displayed by the UI.
119      */
getVisibleObjectById(String id)120     public UiObject getVisibleObjectById(String id) {
121         UiObject uiObject = mDevice.findObject(new UiSelector().resourceId(id));
122         assertTrue("could not find object with id '" + id+ "'", uiObject.exists());
123         return uiObject;
124     }
125 
126     /**
127      * Asserts an object is not visible.
128      */
assertNotVisibleById(String id)129     public void assertNotVisibleById(String id) {
130         // TODO: not working when the bugreport dialog is shown, it hangs until the dialog is
131         // dismissed and hence always work.
132         boolean hasIt = mDevice.hasObject(By.res(id));
133         assertFalse("should not have found object with id '" + id+ "'", hasIt);
134     }
135 
136 
137     /**
138      * Clicks on a UI element.
139      *
140      * @param uiObject UI element to be clicked.
141      * @param description Elements's description used on logging statements.
142      */
click(UiObject uiObject, String description)143     public void click(UiObject uiObject, String description) {
144         try {
145             boolean clicked = uiObject.click();
146             // TODO: assertion below fails sometimes, even though the click succeeded,
147             // (specially when clicking the "Just Once" button), so it's currently just logged.
148             // assertTrue("could not click on object '" + description + "'", clicked);
149 
150             Log.v(TAG, "onClick for " + description + ": " + clicked);
151         } catch (UiObjectNotFoundException e) {
152             throw new IllegalStateException("exception when clicking on object '" + description
153                     + "'", e);
154         }
155     }
156 
157     /**
158      * Chooses a given activity to handle an Intent.
159      *
160      * @param name name of the activity as displayed in the UI (typically the value set by
161      *            {@code android:label} in the manifest).
162      */
chooseActivity(String name)163     public void chooseActivity(String name) {
164         // It uses an intent chooser now, so just getting the activity by text is enough...
165         UiObject activity = getObject(name);
166         click(activity, name);
167     }
168 
pressBack()169     public void pressBack() {
170         mDevice.pressBack();
171     }
172 
turnScreenOn()173     public void turnScreenOn() throws Exception {
174         mDevice.executeShellCommand("input keyevent KEYCODE_WAKEUP");
175         mDevice.executeShellCommand("wm dismiss-keyguard");
176     }
177 
178 }
179