1e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu/* 2e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * Copyright (C) 2012 The Android Open Source Project 3e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * 4e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * Licensed under the Apache License, Version 2.0 (the "License"); 5e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * you may not use this file except in compliance with the License. 6e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * You may obtain a copy of the License at 7e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * 8e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * http://www.apache.org/licenses/LICENSE-2.0 9e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * 10e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * Unless required by applicable law or agreed to in writing, software 11e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * distributed under the License is distributed on an "AS IS" BASIS, 12e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * See the License for the specific language governing permissions and 14e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * limitations under the License. 15e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 16e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 17e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhupackage com.android.uiautomator.core; 18e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 19e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhuimport android.graphics.Rect; 20e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhuimport android.os.SystemClock; 21e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhuimport android.util.Log; 22e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhuimport android.view.KeyEvent; 236088c8f9e34e34a4958b1601ed7c1bb34c95da21Adam Momtazimport android.view.accessibility.AccessibilityEvent; 24e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhuimport android.view.accessibility.AccessibilityNodeInfo; 25e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 26e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu/** 2746d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * A UiObject is a representation of a UI element. It is not in any way directly bound to a 2846d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * UI element as an object reference. A UiObject holds information to help it 2946d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * locate a matching UI element at runtime based on the {@link UiSelector} properties specified in 3046d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * its constructor. Since a UiObject is a representative for a UI element, it can 3146d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * be reused for different views with matching UI elements. 32dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 33e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 34e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhupublic class UiObject { 35e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu private static final String LOG_TAG = UiObject.class.getSimpleName(); 36dbba713661688a285e701a006ce2d199296ac328Guang Zhu /** 37dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 38dbba713661688a285e701a006ce2d199296ac328Guang Zhu **/ 39e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu protected static final long WAIT_FOR_SELECTOR_TIMEOUT = 10 * 1000; 40dbba713661688a285e701a006ce2d199296ac328Guang Zhu /** 41dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 42dbba713661688a285e701a006ce2d199296ac328Guang Zhu **/ 43e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu protected static final long WAIT_FOR_SELECTOR_POLL = 1000; 44e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // set a default timeout to 5.5s, since ANR threshold is 5s 45dbba713661688a285e701a006ce2d199296ac328Guang Zhu /** 46dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 47dbba713661688a285e701a006ce2d199296ac328Guang Zhu **/ 48e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu protected static final long WAIT_FOR_WINDOW_TMEOUT = 5500; 49dbba713661688a285e701a006ce2d199296ac328Guang Zhu /** 50dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 17 51dbba713661688a285e701a006ce2d199296ac328Guang Zhu **/ 526088c8f9e34e34a4958b1601ed7c1bb34c95da21Adam Momtaz protected static final long WAIT_FOR_EVENT_TMEOUT = 3 * 1000; 53dbba713661688a285e701a006ce2d199296ac328Guang Zhu /** 54dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 55dbba713661688a285e701a006ce2d199296ac328Guang Zhu **/ 56e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu protected static final int SWIPE_MARGIN_LIMIT = 5; 57e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 587f38ef08d07295967b905a61b2356ff6cdf31159Adam Momtaz private final UiSelector mSelector; 59ddc1008f06fd2a875037026490ce1f848a442572Guang Zhu private final UiAutomatorBridge mUiAutomationBridge; 60e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 61e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 623d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Constructs a UiObject to represent a specific UI element matched by the specified 633d50587be8ff021369c90554d814839335b445b0Adam Momtaz * {@link UiSelector} selector properties. 64e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @param selector 65dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 66e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 674ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz public UiObject(UiSelector selector) { 68e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu mUiAutomationBridge = UiDevice.getInstance().getAutomatorBridge(); 69e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu mSelector = selector; 70e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 71e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 72e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 733d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Debugging helper. A test can dump the properties of a selector as a string 743d50587be8ff021369c90554d814839335b445b0Adam Momtaz * to its logs if needed. <code>getSelector().toString();</code> 753d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 764ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz * @return {@link UiSelector} 77dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 78e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 794ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz public final UiSelector getSelector() { 80f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(); 814ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz return new UiSelector(mSelector); 82e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 83e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 84e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 853d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Retrieves the {@link QueryController} to translate a {@link UiSelector} selector 863d50587be8ff021369c90554d814839335b445b0Adam Momtaz * into an {@link AccessibilityNodeInfo}. 873d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 88e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return {@link QueryController} 89e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 90ddc1008f06fd2a875037026490ce1f848a442572Guang Zhu QueryController getQueryController() { 91e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return mUiAutomationBridge.getQueryController(); 92e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 93e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 94e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 953d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Retrieves the {@link InteractionController} to perform finger actions such as tapping, 963d50587be8ff021369c90554d814839335b445b0Adam Momtaz * swiping or entering text. 973d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 98e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return {@link InteractionController} 99e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 100ddc1008f06fd2a875037026490ce1f848a442572Guang Zhu InteractionController getInteractionController() { 101e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return mUiAutomationBridge.getInteractionController(); 102e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 103e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 104e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 1053d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Creates a new UiObject representing a child UI element of the element currently represented 1063d50587be8ff021369c90554d814839335b445b0Adam Momtaz * by this UiObject. 1073d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 1083d50587be8ff021369c90554d814839335b445b0Adam Momtaz * @param selector for UI element to match 1093d50587be8ff021369c90554d814839335b445b0Adam Momtaz * @return a new UiObject representing the matched UI element 110dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 111e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 1124ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz public UiObject getChild(UiSelector selector) throws UiObjectNotFoundException { 113f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(selector); 1144ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz return new UiObject(getSelector().childSelector(selector)); 115e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 116e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 117e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 1183d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Creates a new UiObject representing a child UI element from the parent element currently 1193d50587be8ff021369c90554d814839335b445b0Adam Momtaz * represented by this object. Essentially this is starting the search from the parent 1203d50587be8ff021369c90554d814839335b445b0Adam Momtaz * element and can also be used to find sibling UI elements to the one currently represented 1213d50587be8ff021369c90554d814839335b445b0Adam Momtaz * by this UiObject. 1223d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 1233d50587be8ff021369c90554d814839335b445b0Adam Momtaz * @param selector for the UI element to match 1243d50587be8ff021369c90554d814839335b445b0Adam Momtaz * @return a new UiObject representing the matched UI element 125e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 126dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 127e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 1284ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz public UiObject getFromParent(UiSelector selector) throws UiObjectNotFoundException { 129f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(selector); 1304ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz return new UiObject(getSelector().fromParent(selector)); 131e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 132e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 133e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 1343d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Counts the child UI elements immediately under the UI element currently represented by 135e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * this UiObject. 1363d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 137e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return the count of child UI elements. 138e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 139dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 140e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 141e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public int getChildCount() throws UiObjectNotFoundException { 142f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(); 143e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT); 144e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 145e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 146e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 147e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return node.getChildCount(); 148e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 149e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 150e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 1513d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Uses the member UiSelector properties to find a matching UI element reported in 1523d50587be8ff021369c90554d814839335b445b0Adam Momtaz * the accessibility hierarchy. 1533d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 154e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @param timeout in milliseconds 155e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return AccessibilityNodeInfo if found else null 156dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 157e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 158e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu protected AccessibilityNodeInfo findAccessibilityNodeInfo(long timeout) { 159e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo node = null; 160e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(UiDevice.getInstance().isInWatcherContext()) { 161e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // we will NOT run watchers or do any sort of polling if the 162e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // reason we're here is because of a watcher is executing. Watchers 163e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // will not have other watchers run for them so they should not block 164e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // while they poll for items to become present. We disable polling for them. 165e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu node = getQueryController().findAccessibilityNodeInfo(getSelector()); 166e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } else { 167e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu long startMills = SystemClock.uptimeMillis(); 168e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu long currentMills = 0; 169e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu while (currentMills <= timeout) { 170e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu node = getQueryController().findAccessibilityNodeInfo(getSelector()); 171e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if (node != null) { 172e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu break; 173e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } else { 174e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu UiDevice.getInstance().runWatchers(); 175e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 176e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu currentMills = SystemClock.uptimeMillis() - startMills; 177e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(timeout > 0) { 178e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu SystemClock.sleep(WAIT_FOR_SELECTOR_POLL); 179e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 180e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 181e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 182e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return node; 183e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 184e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 185e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 1863d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Perform the action on the UI element that is represented by this UiObject. Also see 1871893caed0ad4e73b0676f206282d490c2d345316Thanh Le * {@link UiScrollable#scrollToBeginning(int)}, {@link UiScrollable#scrollToEnd(int)}, 1881893caed0ad4e73b0676f206282d490c2d345316Thanh Le * {@link UiScrollable#scrollBackward()}, {@link UiScrollable#scrollForward()}. 1893d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 190467cca7d25dbbf13c14cfd8c2ad38ab8eaf56bdaAdam Momtaz * @param steps indicates the number of injected move steps into the system. Steps are 191467cca7d25dbbf13c14cfd8c2ad38ab8eaf56bdaAdam Momtaz * injected about 5ms apart. So a 100 steps may take about 1/2 second to complete. 1923d50587be8ff021369c90554d814839335b445b0Adam Momtaz * @return true of successful 193e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 194dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 195e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 196e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean swipeUp(int steps) throws UiObjectNotFoundException { 197f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(steps); 1983d50587be8ff021369c90554d814839335b445b0Adam Momtaz Rect rect = getVisibleBounds(); 199e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(rect.height() <= SWIPE_MARGIN_LIMIT * 2) 200e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return false; // too small to swipe 201e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return getInteractionController().swipe(rect.centerX(), 202e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu rect.bottom - SWIPE_MARGIN_LIMIT, rect.centerX(), rect.top + SWIPE_MARGIN_LIMIT, 203e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu steps); 204e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 205e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 206e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 207e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * Perform the action on the UI element that is represented by this object, Also see 2081893caed0ad4e73b0676f206282d490c2d345316Thanh Le * {@link UiScrollable#scrollToBeginning(int)}, {@link UiScrollable#scrollToEnd(int)}, 2091893caed0ad4e73b0676f206282d490c2d345316Thanh Le * {@link UiScrollable#scrollBackward()}, {@link UiScrollable#scrollForward()}. This method will 2101893caed0ad4e73b0676f206282d490c2d345316Thanh Le * perform the swipe gesture over any surface. The targeted UI element does not need to have 2111893caed0ad4e73b0676f206282d490c2d345316Thanh Le * the attribute <code>scrollable</code> set to <code>true</code> for this operation to be 2121893caed0ad4e73b0676f206282d490c2d345316Thanh Le * performed. 2133d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 2143d50587be8ff021369c90554d814839335b445b0Adam Momtaz * @param steps indicates the number of injected move steps into the system. Steps are 215467cca7d25dbbf13c14cfd8c2ad38ab8eaf56bdaAdam Momtaz * injected about 5ms apart. So a 100 steps may take about 1/2 second to complete. 2163d50587be8ff021369c90554d814839335b445b0Adam Momtaz * @return true if successful 217e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 218dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 219e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 220e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean swipeDown(int steps) throws UiObjectNotFoundException { 221f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(steps); 2223d50587be8ff021369c90554d814839335b445b0Adam Momtaz Rect rect = getVisibleBounds(); 223e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(rect.height() <= SWIPE_MARGIN_LIMIT * 2) 224e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return false; // too small to swipe 225e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return getInteractionController().swipe(rect.centerX(), 226e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu rect.top + SWIPE_MARGIN_LIMIT, rect.centerX(), 227e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu rect.bottom - SWIPE_MARGIN_LIMIT, steps); 228e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 229e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 230e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 231e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * Perform the action on the UI element that is represented by this object. Also see 2321893caed0ad4e73b0676f206282d490c2d345316Thanh Le * {@link UiScrollable#scrollToBeginning(int)}, {@link UiScrollable#scrollToEnd(int)}, 2331893caed0ad4e73b0676f206282d490c2d345316Thanh Le * {@link UiScrollable#scrollBackward()}, {@link UiScrollable#scrollForward()}. This method will 2341893caed0ad4e73b0676f206282d490c2d345316Thanh Le * perform the swipe gesture over any surface. The targeted UI element does not need to have the 2351893caed0ad4e73b0676f206282d490c2d345316Thanh Le * attribute <code>scrollable</code> set to <code>true</code> for this operation to be 2361893caed0ad4e73b0676f206282d490c2d345316Thanh Le * performed. 2373d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 2383d50587be8ff021369c90554d814839335b445b0Adam Momtaz * @param steps indicates the number of injected move steps into the system. Steps are 239467cca7d25dbbf13c14cfd8c2ad38ab8eaf56bdaAdam Momtaz * injected about 5ms apart. So a 100 steps may take about 1/2 second to complete. 2403d50587be8ff021369c90554d814839335b445b0Adam Momtaz * @return true if successful 241e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 242dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 243e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 244e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean swipeLeft(int steps) throws UiObjectNotFoundException { 245f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(steps); 2463d50587be8ff021369c90554d814839335b445b0Adam Momtaz Rect rect = getVisibleBounds(); 247e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(rect.width() <= SWIPE_MARGIN_LIMIT * 2) 248e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return false; // too small to swipe 249e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return getInteractionController().swipe(rect.right - SWIPE_MARGIN_LIMIT, 250e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu rect.centerY(), rect.left + SWIPE_MARGIN_LIMIT, rect.centerY(), steps); 251e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 252e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 253e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 254e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * Perform the action on the UI element that is represented by this object. Also see 2551893caed0ad4e73b0676f206282d490c2d345316Thanh Le * {@link UiScrollable#scrollToBeginning(int)}, {@link UiScrollable#scrollToEnd(int)}, 2561893caed0ad4e73b0676f206282d490c2d345316Thanh Le * {@link UiScrollable#scrollBackward()}, {@link UiScrollable#scrollForward()}. This method will 2571893caed0ad4e73b0676f206282d490c2d345316Thanh Le * perform the swipe gesture over any surface. The targeted UI element does not need to have the 2581893caed0ad4e73b0676f206282d490c2d345316Thanh Le * attribute <code>scrollable</code> set to <code>true</code> for this operation to be 2591893caed0ad4e73b0676f206282d490c2d345316Thanh Le * performed. 2603d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 2613d50587be8ff021369c90554d814839335b445b0Adam Momtaz * @param steps indicates the number of injected move steps into the system. Steps are 262467cca7d25dbbf13c14cfd8c2ad38ab8eaf56bdaAdam Momtaz * injected about 5ms apart. So a 100 steps may take about 1/2 second to complete. 2633d50587be8ff021369c90554d814839335b445b0Adam Momtaz * @return true if successful 264e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 265dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 266e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 267e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean swipeRight(int steps) throws UiObjectNotFoundException { 268f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(steps); 2693d50587be8ff021369c90554d814839335b445b0Adam Momtaz Rect rect = getVisibleBounds(); 270e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(rect.width() <= SWIPE_MARGIN_LIMIT * 2) 271e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return false; // too small to swipe 272e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return getInteractionController().swipe(rect.left + SWIPE_MARGIN_LIMIT, 273e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu rect.centerY(), rect.right - SWIPE_MARGIN_LIMIT, rect.centerY(), steps); 274e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 275e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 276e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 2773d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Finds the visible bounds of a partially visible UI element 2783d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 279e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @param node 2807f38ef08d07295967b905a61b2356ff6cdf31159Adam Momtaz * @return null if node is null, else a Rect containing visible bounds 281e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 282e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu private Rect getVisibleBounds(AccessibilityNodeInfo node) { 283e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if (node == null) { 284e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return null; 285e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 286e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 287e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // targeted node's bounds 2887f38ef08d07295967b905a61b2356ff6cdf31159Adam Momtaz Rect nodeRect = AccessibilityNodeInfoHelper.getVisibleBoundsInScreen(node); 289e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 290e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // is the targeted node within a scrollable container? 291e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo scrollableParentNode = getScrollableParent(node); 292e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(scrollableParentNode == null) { 293e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // nothing to adjust for so return the node's Rect as is 294e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return nodeRect; 295e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 296e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 297e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // Scrollable parent's visible bounds 2987f38ef08d07295967b905a61b2356ff6cdf31159Adam Momtaz Rect parentRect = AccessibilityNodeInfoHelper 2997f38ef08d07295967b905a61b2356ff6cdf31159Adam Momtaz .getVisibleBoundsInScreen(scrollableParentNode); 300e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // adjust for partial clipping of targeted by parent node if required 301e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu nodeRect.intersect(parentRect); 302e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return nodeRect; 303e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 304e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 305e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 3067f38ef08d07295967b905a61b2356ff6cdf31159Adam Momtaz * Walk the hierarchy up to find a scrollable parent. A scrollable parent 3077f38ef08d07295967b905a61b2356ff6cdf31159Adam Momtaz * indicates that this node may be in a content where it is partially 3087f38ef08d07295967b905a61b2356ff6cdf31159Adam Momtaz * visible due to scrolling. its clickable center maybe invisible and 3097f38ef08d07295967b905a61b2356ff6cdf31159Adam Momtaz * adjustments should be made to the click coordinates. 3103d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 311e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @param node 3121893caed0ad4e73b0676f206282d490c2d345316Thanh Le * @return The accessibility node info. 313e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 314e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu private AccessibilityNodeInfo getScrollableParent(AccessibilityNodeInfo node) { 315e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo parent = node; 316e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu while(parent != null) { 317e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu parent = parent.getParent(); 318e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if (parent != null && parent.isScrollable()) { 319e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return parent; 320e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 321e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 322e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return null; 323e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 324e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 325e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 3263d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Performs a click at the center of the visible bounds of the UI element represented 32746d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * by this UiObject. 3283d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 329e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true id successful else false 330e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 331dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 332e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 333e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean click() throws UiObjectNotFoundException { 334f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(); 335e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT); 336e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 337e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 338e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 339e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu Rect rect = getVisibleBounds(node); 34008f500a92397522c48bcdad58d37ec1be95956d1Adam Momtaz return getInteractionController().clickAndWaitForEvents(rect.centerX(), rect.centerY(), 34108f500a92397522c48bcdad58d37ec1be95956d1Adam Momtaz WAIT_FOR_EVENT_TMEOUT, false, AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED + 34208f500a92397522c48bcdad58d37ec1be95956d1Adam Momtaz AccessibilityEvent.TYPE_VIEW_SELECTED); 343e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 344e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 345e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 3463d50587be8ff021369c90554d814839335b445b0Adam Momtaz * See {@link #clickAndWaitForNewWindow(long)} 347a46ac3504426564954292b13380120e8cc6b1527Adam Momtaz * This method is intended to reliably wait for window transitions that would typically take 348a46ac3504426564954292b13380120e8cc6b1527Adam Momtaz * longer than the usual default timeouts. 3493d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 3503d50587be8ff021369c90554d814839335b445b0Adam Momtaz * @return true if the event was triggered, else false 3513d50587be8ff021369c90554d814839335b445b0Adam Momtaz * @throws UiObjectNotFoundException 352dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 3533d50587be8ff021369c90554d814839335b445b0Adam Momtaz */ 354e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean clickAndWaitForNewWindow() throws UiObjectNotFoundException { 355f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(); 356e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return clickAndWaitForNewWindow(WAIT_FOR_WINDOW_TMEOUT); 357e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 358e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 359e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 36046d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * Performs a click at the center of the visible bounds of the UI element represented 36146d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * by this UiObject and waits for window transitions. 36246d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * 3633d50587be8ff021369c90554d814839335b445b0Adam Momtaz * This method differ from {@link UiObject#click()} only in that this method waits for a 36446d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * a new window transition as a result of the click. Some examples of a window transition: 365e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * <li>launching a new activity</li> 366e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * <li>bringing up a pop-up menu</li> 367e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * <li>bringing up a dialog</li> 368e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * 3693d50587be8ff021369c90554d814839335b445b0Adam Momtaz * @param timeout timeout before giving up on waiting for a new window 370e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if the event was triggered, else false 371e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 372dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 373e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 374e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean clickAndWaitForNewWindow(long timeout) throws UiObjectNotFoundException { 375f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(timeout); 376e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT); 377e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 378e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 379e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 380e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu Rect rect = getVisibleBounds(node); 3814ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz return getInteractionController().clickAndWaitForNewWindow( 382e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu rect.centerX(), rect.centerY(), timeout); 383e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 384e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 385e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 3863d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Clicks the top and left corner of the UI element 3873d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 388e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true on success 3891893caed0ad4e73b0676f206282d490c2d345316Thanh Le * @throws UiObjectNotFoundException 390dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 391e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 392e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean clickTopLeft() throws UiObjectNotFoundException { 393f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(); 394e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT); 395e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 396e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 397e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 398e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu Rect rect = getVisibleBounds(node); 3994ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz return getInteractionController().click(rect.left + 5, rect.top + 5); 400e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 401e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 402e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 4033d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Long clicks bottom and right corner of the UI element 4043d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 405e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if operation was successful 406e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 407dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 408e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 409e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean longClickBottomRight() throws UiObjectNotFoundException { 410f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(); 411e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT); 412e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 413e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 414e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 415e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu Rect rect = getVisibleBounds(node); 416e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return getInteractionController().longTap(rect.right - 5, rect.bottom - 5); 417e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 418e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 419e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 4203d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Clicks the bottom and right corner of the UI element 4213d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 422e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true on success 4231893caed0ad4e73b0676f206282d490c2d345316Thanh Le * @throws UiObjectNotFoundException 424dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 425e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 426e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean clickBottomRight() throws UiObjectNotFoundException { 427f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(); 428e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT); 429e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 430e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 431e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 432e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu Rect rect = getVisibleBounds(node); 4334ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz return getInteractionController().click(rect.right - 5, rect.bottom - 5); 434e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 435e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 436e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 4373d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Long clicks the center of the visible bounds of the UI element 4383d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 439e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if operation was successful 440e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 441dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 442e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 443e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean longClick() throws UiObjectNotFoundException { 444f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(); 445e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT); 446e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 447e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 448e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 449e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu Rect rect = getVisibleBounds(node); 450e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return getInteractionController().longTap(rect.centerX(), rect.centerY()); 451e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 452e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 453e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 4543d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Long clicks on the top and left corner of the UI element 4553d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 456e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if operation was successful 457e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 458dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 459e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 460e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean longClickTopLeft() throws UiObjectNotFoundException { 461f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(); 462e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT); 463e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 464e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 465e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 466e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu Rect rect = getVisibleBounds(node); 467e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return getInteractionController().longTap(rect.left + 5, rect.top + 5); 468e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 469e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 470e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 4713d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Reads the <code>text</code> property of the UI element 4723d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 473e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return text value of the current node represented by this UiObject 474e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException if no match could be found 475dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 476e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 477e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public String getText() throws UiObjectNotFoundException { 478f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(); 479e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT); 480e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 481e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 482e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 483e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu String retVal = safeStringReturn(node.getText()); 484e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu Log.d(LOG_TAG, String.format("getText() = %s", retVal)); 485e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return retVal; 486e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 487e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 488e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 4893d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Reads the <code>content_desc</code> property of the UI element 4903d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 491e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return value of node attribute "content_desc" 492e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 493dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 494e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 495e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public String getContentDescription() throws UiObjectNotFoundException { 496f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(); 497e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT); 498e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 499e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 500e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 501e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return safeStringReturn(node.getContentDescription()); 502e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 503e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 504e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 50546d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * Sets the text in an editable field, after clearing the field's content. 50646d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * 50746d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * The {@link UiSelector} selector of this object must reference a UI element that is editable. 50846d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * 50946d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * When you call this method, the method first simulates a {@link #click()} on 51046d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * editable field to set focus. The method then clears the field's contents 51146d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * and injects your specified text into the field. 5123d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 51346d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * If you want to capture the original contents of the field, call {@link #getText()} first. 51446d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * You can then modify the text and use this method to update the field. 51546d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * 51646d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * @param text string to set 517e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if operation is successful 518e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 519dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 520e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 521e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean setText(String text) throws UiObjectNotFoundException { 522f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(text); 523e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu clearTextField(); 524e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return getInteractionController().sendText(text); 525e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 526e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 527e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 52846d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * Clears the existing text contents in an editable field. 52946d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * 53046d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * The {@link UiSelector} of this object must reference a UI element that is editable. 53146d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * 53246d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * When you call this method, the method first sets focus at the start edge of the field. 53346d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * The method then simulates a long-press to select the existing text, and deletes the 53446d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * selected text. 53546d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * 53646d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * If a "Select-All" option is displayed, the method will automatically attempt to use it 53746d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * to ensure full text selection. 53846d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * 53946d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * Note that it is possible that not all the text in the field is selected; for example, 54046d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * if the text contains separators such as spaces, slashes, at symbol etc. 54146d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * Also, not all editable fields support the long-press functionality. 54246d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * 543e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 544dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 545e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 546e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public void clearTextField() throws UiObjectNotFoundException { 547f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(); 548e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // long click left + center 549e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT); 550e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 551e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 552e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 553e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu Rect rect = getVisibleBounds(node); 554e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu getInteractionController().longTap(rect.left + 20, rect.centerY()); 555e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // check if the edit menu is open 5564ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz UiObject selectAll = new UiObject(new UiSelector().descriptionContains("Select all")); 557e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(selectAll.waitForExists(50)) 558e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu selectAll.click(); 559e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // wait for the selection 560e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu SystemClock.sleep(250); 561e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // delete it 562e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu getInteractionController().sendKey(KeyEvent.KEYCODE_DEL, 0); 563e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 564e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 565e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 5663d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Check if the UI element's <code>checked</code> property is currently true 5673d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 568e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if it is else false 569dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 570e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 571e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean isChecked() throws UiObjectNotFoundException { 572f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(); 573e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT); 574e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 575e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 576e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 577e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return node.isChecked(); 578e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 579e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 580e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 5813d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Check if the UI element's <code>selected</code> property is currently true 5823d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 583e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if it is else false 584e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 585dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 586e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 587e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean isSelected() throws UiObjectNotFoundException { 588f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(); 589e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT); 590e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 591e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 592e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 593e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return node.isSelected(); 594e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 595e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 596e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 5973d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Check if the UI element's <code>checkable</code> property is currently true 5983d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 599e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if it is else false 600e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 601dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 602e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 603e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean isCheckable() throws UiObjectNotFoundException { 604f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(); 605e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT); 606e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 607e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 608e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 609e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return node.isCheckable(); 610e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 611e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 612e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 6133d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Check if the UI element's <code>enabled</code> property is currently true 6143d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 615e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if it is else false 616e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 617dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 618e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 619e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean isEnabled() throws UiObjectNotFoundException { 620f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(); 621e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT); 622e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 623e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 624e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 625e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return node.isEnabled(); 626e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 627e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 628e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 6293d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Check if the UI element's <code>clickable</code> property is currently true 6303d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 631e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if it is else false 632e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 633dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 634e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 635e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean isClickable() throws UiObjectNotFoundException { 636f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(); 637e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT); 638e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 639e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 640e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 641e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return node.isClickable(); 642e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 643e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 644e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 6453d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Check if the UI element's <code>focused</code> property is currently true 6463d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 647e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if it is else false 648e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 649dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 650e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 651e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean isFocused() throws UiObjectNotFoundException { 652f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(); 653e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT); 654e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 655e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 656e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 657e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return node.isFocused(); 658e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 659e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 660e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 6613d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Check if the UI element's <code>focusable</code> property is currently true 6623d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 663e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if it is else false 664e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 665dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 666e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 667e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean isFocusable() throws UiObjectNotFoundException { 668f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(); 669e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT); 670e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 671e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 672e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 673e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return node.isFocusable(); 674e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 675e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 676e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 6773d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Check if the UI element's <code>scrollable</code> property is currently true 6783d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 679e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if it is else false 680e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 681dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 682e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 683e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean isScrollable() throws UiObjectNotFoundException { 684f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(); 685e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT); 686e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 687e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 688e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 689e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return node.isScrollable(); 690e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 691e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 692e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 6933d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Check if the UI element's <code>long-clickable</code> property is currently true 6943d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 695e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if it is else false 696e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 697dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 698e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 699e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean isLongClickable() throws UiObjectNotFoundException { 700f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(); 701e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT); 702e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 703e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 704e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 705e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return node.isLongClickable(); 706e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 707e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 708e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 7093d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Reads the UI element's <code>package</code> property 7103d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 7113d50587be8ff021369c90554d814839335b445b0Adam Momtaz * @return true if it is else false 712e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 713dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 714e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 715e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public String getPackageName() throws UiObjectNotFoundException { 716f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(); 717e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT); 718e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 719e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 720e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 721e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return safeStringReturn(node.getPackageName()); 722e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 723e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 724e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 72546d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * Returns the visible bounds of the UI element. 72646d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * 72746d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * If a portion of the UI element is visible, only the bounds of the visible portion are 72846d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * reported. 7293d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 730e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return Rect 731e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 7321893caed0ad4e73b0676f206282d490c2d345316Thanh Le * @see {@link #getBounds()} 73379693ede92636fe6f3a6ec4dc049a438fd9504ffGuang Zhu * @since API Level 17 734e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 7353d50587be8ff021369c90554d814839335b445b0Adam Momtaz public Rect getVisibleBounds() throws UiObjectNotFoundException { 736f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(); 737e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT); 738e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 739e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 740e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 741e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return getVisibleBounds(node); 742e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 743e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 744e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 74546d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * Returns the UI element's <code>bounds</code> property. See {@link #getVisibleBounds()} 7463d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 7473d50587be8ff021369c90554d814839335b445b0Adam Momtaz * @return Rect 7483d50587be8ff021369c90554d814839335b445b0Adam Momtaz * @throws UiObjectNotFoundException 749dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 7503d50587be8ff021369c90554d814839335b445b0Adam Momtaz */ 7513d50587be8ff021369c90554d814839335b445b0Adam Momtaz public Rect getBounds() throws UiObjectNotFoundException { 752f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(); 7533d50587be8ff021369c90554d814839335b445b0Adam Momtaz AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT); 7543d50587be8ff021369c90554d814839335b445b0Adam Momtaz if(node == null) { 7553d50587be8ff021369c90554d814839335b445b0Adam Momtaz throw new UiObjectNotFoundException(getSelector().toString()); 7563d50587be8ff021369c90554d814839335b445b0Adam Momtaz } 7573d50587be8ff021369c90554d814839335b445b0Adam Momtaz Rect nodeRect = new Rect(); 7583d50587be8ff021369c90554d814839335b445b0Adam Momtaz node.getBoundsInScreen(nodeRect); 7593d50587be8ff021369c90554d814839335b445b0Adam Momtaz 7603d50587be8ff021369c90554d814839335b445b0Adam Momtaz return nodeRect; 7613d50587be8ff021369c90554d814839335b445b0Adam Momtaz } 7623d50587be8ff021369c90554d814839335b445b0Adam Momtaz 7633d50587be8ff021369c90554d814839335b445b0Adam Momtaz /** 76446d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * Waits a specified length of time for a UI element to become visible. 76546d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * 76646d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * This method waits until the UI element becomes visible on the display, or 76746d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * until the timeout has elapsed. You can use this method in situations where 76846d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * the content that you want to select is not immediately displayed. 7693d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 77046d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * @param timeout the amount of time to wait (in milliseconds) 77146d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * @return true if the UI element is displayed, else false if timeout elapsed while waiting 772dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 773e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 774e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean waitForExists(long timeout) { 775f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(timeout); 776e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(findAccessibilityNodeInfo(timeout) != null) { 777e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return true; 778e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 779e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return false; 780e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 781e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 782e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 78346d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * Waits a specified length of time for a UI element to become undetectable. 7843d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 78546d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * This method waits until a UI element is no longer matchable, or until the 78646d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * timeout has elapsed. 78746d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * 78846d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * A UI element becomes undetectable when the {@link UiSelector} of the object is 78946d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * unable to find a match because the element has either changed its state or is no 79046d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * longer displayed. 79146d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * 79246d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * You can use this method when attempting to wait for some long operation 79346d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * to compete, such as downloading a large file or connecting to a remote server. 79446d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * 79546d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * @param timeout time to wait (in milliseconds) 79646d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * @return true if the element is gone before timeout elapsed, else false if timeout elapsed 79746d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * but a matching element is still found. 798dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 799e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 800e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean waitUntilGone(long timeout) { 801f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(timeout); 802e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu long startMills = SystemClock.uptimeMillis(); 803e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu long currentMills = 0; 804e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu while (currentMills <= timeout) { 805e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(findAccessibilityNodeInfo(0) == null) 806e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return true; 807e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu currentMills = SystemClock.uptimeMillis() - startMills; 808e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(timeout > 0) 809e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu SystemClock.sleep(WAIT_FOR_SELECTOR_POLL); 810e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 811e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return false; 812e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 813e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 814e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 81546d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * Check if UI element exists. 81646d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * 817e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * This methods performs a {@link #waitForExists(long)} with zero timeout. This 818e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * basically returns immediately whether the UI element represented by this UiObject 819e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * exists or not. If you need to wait longer for this UI element, then see 820e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * {@link #waitForExists(long)}. 8213d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 822e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if the UI element represented by this UiObject does exist 823dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 824e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 825e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean exists() { 826f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(); 827e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return waitForExists(0); 828e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 829e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 830e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu private String safeStringReturn(CharSequence cs) { 831e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(cs == null) 832e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return ""; 833e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return cs.toString(); 834e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 835e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu} 836