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.support.test.uiautomator.By; 20 import android.support.test.uiautomator.UiDevice; 21 import android.support.test.uiautomator.UiObject; 22 import android.support.test.uiautomator.UiObjectNotFoundException; 23 import android.support.test.uiautomator.UiScrollable; 24 import android.support.test.uiautomator.UiSelector; 25 import android.support.test.uiautomator.Until; 26 import android.util.Log; 27 import static junit.framework.Assert.assertTrue; 28 29 /** 30 * A helper class for UI-related testing tasks. 31 */ 32 final class UiBot { 33 34 private static final String TAG = "UiBot"; 35 private static final String SYSTEMUI_PACKAGE = "com.android.systemui"; 36 37 private final UiDevice mDevice; 38 private final int mTimeout; 39 UiBot(UiDevice device, int timeout)40 public UiBot(UiDevice device, int timeout) { 41 mDevice = device; 42 mTimeout = timeout; 43 } 44 45 /** 46 * Opens the system notification and gets a given notification. 47 * 48 * @param text Notificaton's text as displayed by the UI. 49 * @return notification object. 50 */ getNotification(String text)51 public UiObject getNotification(String text) { 52 boolean opened = mDevice.openNotification(); 53 Log.v(TAG, "openNotification(): " + opened); 54 boolean gotIt = mDevice.wait(Until.hasObject(By.pkg(SYSTEMUI_PACKAGE)), mTimeout); 55 assertTrue("could not get system ui (" + SYSTEMUI_PACKAGE + ")", gotIt); 56 57 return getObject(text); 58 } 59 60 /** 61 * Opens the system notification and clicks a given notification. 62 * 63 * @param text Notificaton's text as displayed by the UI. 64 */ clickOnNotification(String text)65 public void clickOnNotification(String text) { 66 UiObject notification = getNotification(text); 67 click(notification, "bug report notification"); 68 } 69 70 /** 71 * Gets an object that might not yet be available in current UI. 72 * 73 * @param text Object's text as displayed by the UI. 74 */ getObject(String text)75 public UiObject getObject(String text) { 76 boolean gotIt = mDevice.wait(Until.hasObject(By.text(text)), mTimeout); 77 assertTrue("object with text '(" + text + "') not visible yet", gotIt); 78 return getVisibleObject(text); 79 } 80 81 /** 82 * Gets an object that might not yet be available in current UI. 83 * 84 * @param id Object's fully-qualified resource id (like {@code android:id/button1}) 85 */ getObjectById(String id)86 public UiObject getObjectById(String id) { 87 boolean gotIt = mDevice.wait(Until.hasObject(By.res(id)), mTimeout); 88 assertTrue("object with id '(" + id + "') not visible yet", gotIt); 89 return getVisibleObjectById(id); 90 } 91 92 /** 93 * Gets an object which is guaranteed to be present in the current UI. 94 * 95 * @param text Object's text as displayed by the UI. 96 */ getVisibleObject(String text)97 public UiObject getVisibleObject(String text) { 98 UiObject uiObject = mDevice.findObject(new UiSelector().text(text)); 99 assertTrue("could not find object with text '" + text + "'", uiObject.exists()); 100 return uiObject; 101 } 102 103 /** 104 * Gets an object which is guaranteed to be present in the current UI. 105 * 106 * @param text Object's text as displayed by the UI. 107 */ getVisibleObjectById(String id)108 public UiObject getVisibleObjectById(String id) { 109 UiObject uiObject = mDevice.findObject(new UiSelector().resourceId(id)); 110 assertTrue("could not find object with id '" + id+ "'", uiObject.exists()); 111 return uiObject; 112 } 113 114 115 /** 116 * Clicks on a UI element. 117 * 118 * @param uiObject UI element to be clicked. 119 * @param description Elements's description used on logging statements. 120 */ click(UiObject uiObject, String description)121 public void click(UiObject uiObject, String description) { 122 try { 123 boolean clicked = uiObject.click(); 124 // TODO: assertion below fails sometimes, even though the click succeeded, 125 // (specially when clicking the "Just Once" button), so it's currently just logged. 126 // assertTrue("could not click on object '" + description + "'", clicked); 127 128 Log.v(TAG, "onClick for " + description + ": " + clicked); 129 } catch (UiObjectNotFoundException e) { 130 throw new IllegalStateException("exception when clicking on object '" + description 131 + "'", e); 132 } 133 } 134 135 /** 136 * Chooses a given activity to handle an Intent, using the "Just Once" button. 137 * 138 * @param name name of the activity as displayed in the UI (typically the value set by 139 * {@code android:label} in the manifest). 140 */ 141 // TODO: UI Automator should provide such logic. chooseActivity(String name)142 public void chooseActivity(String name) { 143 // First check if the activity is the default option. 144 String shareText = "Share with " + name; 145 Log.v(TAG, "Waiting for ActivityChooser text: '" + shareText + "'"); 146 boolean gotIt = mDevice.wait(Until.hasObject(By.text(shareText)), mTimeout); 147 boolean justOnceHack = false; 148 149 if (gotIt) { 150 Log.v(TAG, "Found activity " + name + ", it's the default action"); 151 clickJustOnce(); 152 } else { 153 // Since it's not, need to find it in the scrollable list... 154 Log.v(TAG, "Activity " + name + " is not default action"); 155 UiScrollable activitiesList = new UiScrollable(new UiSelector().scrollable(true)); 156 try { 157 activitiesList.scrollForward(); 158 } catch (UiObjectNotFoundException e) { 159 // TODO: for some paranormal issue, the first time a test is run the scrollable 160 // activity list is displayed but calling scrollForwad() (or even isScrollable()) 161 // throws a "UiObjectNotFoundException: UiSelector[SCROLLABLE=true]" exception 162 justOnceHack = true; 163 Log.d(TAG, "could not scroll forward", e); 164 } 165 UiObject activity = getVisibleObject(name); 166 // ... then select it. 167 click(activity, name); 168 if (justOnceHack) { 169 clickJustOnce(); 170 } 171 } 172 } 173 clickJustOnce()174 private void clickJustOnce() { 175 boolean gotIt = mDevice.wait(Until.hasObject(By.res("android", "button_once")), mTimeout); 176 assertTrue("'Just Once' button not visible yet", gotIt); 177 178 UiObject justOnce = mDevice 179 .findObject(new UiSelector().resourceId("android:id/button_once")); 180 assertTrue("'Just Once' button not found", justOnce.exists()); 181 182 click(justOnce, "Just Once"); 183 } 184 pressBack()185 public void pressBack() { 186 mDevice.pressBack(); 187 } 188 } 189