UiObject.java revision 79693ede92636fe6f3a6ec4dc049a438fd9504ff
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() { 804ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz return new UiSelector(mSelector); 81e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 82e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 83e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 843d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Retrieves the {@link QueryController} to translate a {@link UiSelector} selector 853d50587be8ff021369c90554d814839335b445b0Adam Momtaz * into an {@link AccessibilityNodeInfo}. 863d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 87e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return {@link QueryController} 88e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 89ddc1008f06fd2a875037026490ce1f848a442572Guang Zhu QueryController getQueryController() { 90e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return mUiAutomationBridge.getQueryController(); 91e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 92e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 93e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 943d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Retrieves the {@link InteractionController} to perform finger actions such as tapping, 953d50587be8ff021369c90554d814839335b445b0Adam Momtaz * swiping or entering text. 963d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 97e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return {@link InteractionController} 98e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 99ddc1008f06fd2a875037026490ce1f848a442572Guang Zhu InteractionController getInteractionController() { 100e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return mUiAutomationBridge.getInteractionController(); 101e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 102e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 103e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 1043d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Creates a new UiObject representing a child UI element of the element currently represented 1053d50587be8ff021369c90554d814839335b445b0Adam Momtaz * by this UiObject. 1063d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 1073d50587be8ff021369c90554d814839335b445b0Adam Momtaz * @param selector for UI element to match 1083d50587be8ff021369c90554d814839335b445b0Adam Momtaz * @return a new UiObject representing the matched UI element 109dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 110e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 1114ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz public UiObject getChild(UiSelector selector) throws UiObjectNotFoundException { 1124ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz return new UiObject(getSelector().childSelector(selector)); 113e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 114e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 115e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 1163d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Creates a new UiObject representing a child UI element from the parent element currently 1173d50587be8ff021369c90554d814839335b445b0Adam Momtaz * represented by this object. Essentially this is starting the search from the parent 1183d50587be8ff021369c90554d814839335b445b0Adam Momtaz * element and can also be used to find sibling UI elements to the one currently represented 1193d50587be8ff021369c90554d814839335b445b0Adam Momtaz * by this UiObject. 1203d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 1213d50587be8ff021369c90554d814839335b445b0Adam Momtaz * @param selector for the UI element to match 1223d50587be8ff021369c90554d814839335b445b0Adam Momtaz * @return a new UiObject representing the matched UI element 123e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 124dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 125e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 1264ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz public UiObject getFromParent(UiSelector selector) throws UiObjectNotFoundException { 1274ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz return new UiObject(getSelector().fromParent(selector)); 128e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 129e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 130e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 1313d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Counts the child UI elements immediately under the UI element currently represented by 132e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * this UiObject. 1333d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 134e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return the count of child UI elements. 135e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 136dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 137e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 138e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public int getChildCount() throws UiObjectNotFoundException { 139e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT); 140e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 141e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 142e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 143e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return node.getChildCount(); 144e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 145e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 146e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 1473d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Uses the member UiSelector properties to find a matching UI element reported in 1483d50587be8ff021369c90554d814839335b445b0Adam Momtaz * the accessibility hierarchy. 1493d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 1504ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz * @param selector {@link UiSelector} 151e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @param timeout in milliseconds 152e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return AccessibilityNodeInfo if found else null 153dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 154e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 155e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu protected AccessibilityNodeInfo findAccessibilityNodeInfo(long timeout) { 156e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo node = null; 157e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(UiDevice.getInstance().isInWatcherContext()) { 158e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // we will NOT run watchers or do any sort of polling if the 159e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // reason we're here is because of a watcher is executing. Watchers 160e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // will not have other watchers run for them so they should not block 161e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // while they poll for items to become present. We disable polling for them. 162e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu node = getQueryController().findAccessibilityNodeInfo(getSelector()); 163e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } else { 164e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu long startMills = SystemClock.uptimeMillis(); 165e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu long currentMills = 0; 166e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu while (currentMills <= timeout) { 167e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu node = getQueryController().findAccessibilityNodeInfo(getSelector()); 168e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if (node != null) { 169e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu break; 170e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } else { 171e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu UiDevice.getInstance().runWatchers(); 172e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 173e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu currentMills = SystemClock.uptimeMillis() - startMills; 174e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(timeout > 0) { 175e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu SystemClock.sleep(WAIT_FOR_SELECTOR_POLL); 176e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 177e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 178e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 179e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return node; 180e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 181e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 182e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 1833d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Perform the action on the UI element that is represented by this UiObject. Also see 184e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * {@link #scrollToBeginning(int)}, {@link #scrollToEnd(int)}, {@link #scrollBackward()}, 1853d50587be8ff021369c90554d814839335b445b0Adam Momtaz * {@link #scrollForward()}. 1863d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 187467cca7d25dbbf13c14cfd8c2ad38ab8eaf56bdaAdam Momtaz * @param steps indicates the number of injected move steps into the system. Steps are 188467cca7d25dbbf13c14cfd8c2ad38ab8eaf56bdaAdam Momtaz * injected about 5ms apart. So a 100 steps may take about 1/2 second to complete. 1893d50587be8ff021369c90554d814839335b445b0Adam Momtaz * @return true of successful 190e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 191dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 192e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 193e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean swipeUp(int steps) throws UiObjectNotFoundException { 1943d50587be8ff021369c90554d814839335b445b0Adam Momtaz Rect rect = getVisibleBounds(); 195e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(rect.height() <= SWIPE_MARGIN_LIMIT * 2) 196e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return false; // too small to swipe 197e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return getInteractionController().swipe(rect.centerX(), 198e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu rect.bottom - SWIPE_MARGIN_LIMIT, rect.centerX(), rect.top + SWIPE_MARGIN_LIMIT, 199e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu steps); 200e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 201e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 202e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 203e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * Perform the action on the UI element that is represented by this object, Also see 204e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * {@link #scrollToBeginning(int)}, {@link #scrollToEnd(int)}, {@link #scrollBackward()}, 205e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * {@link #scrollForward()}. This method will perform the swipe gesture over any 206e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * surface. The targeted UI element does not need to have the attribute 207e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * <code>scrollable</code> set to <code>true</code> for this operation to be performed. 2083d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 2093d50587be8ff021369c90554d814839335b445b0Adam Momtaz * @param steps indicates the number of injected move steps into the system. Steps are 210467cca7d25dbbf13c14cfd8c2ad38ab8eaf56bdaAdam Momtaz * injected about 5ms apart. So a 100 steps may take about 1/2 second to complete. 2113d50587be8ff021369c90554d814839335b445b0Adam Momtaz * @return true if successful 212e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 213dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 214e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 215e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean swipeDown(int steps) throws UiObjectNotFoundException { 2163d50587be8ff021369c90554d814839335b445b0Adam Momtaz Rect rect = getVisibleBounds(); 217e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(rect.height() <= SWIPE_MARGIN_LIMIT * 2) 218e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return false; // too small to swipe 219e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return getInteractionController().swipe(rect.centerX(), 220e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu rect.top + SWIPE_MARGIN_LIMIT, rect.centerX(), 221e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu rect.bottom - SWIPE_MARGIN_LIMIT, steps); 222e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 223e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 224e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 225e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * Perform the action on the UI element that is represented by this object. Also see 226e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * {@link #scrollToBeginning(int)}, {@link #scrollToEnd(int)}, {@link #scrollBackward()}, 227e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * {@link #scrollForward()}. This method will perform the swipe gesture over any 228e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * surface. The targeted UI element does not need to have the attribute 229e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * <code>scrollable</code> set to <code>true</code> for this operation to be performed. 2303d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 2313d50587be8ff021369c90554d814839335b445b0Adam Momtaz * @param steps indicates the number of injected move steps into the system. Steps are 232467cca7d25dbbf13c14cfd8c2ad38ab8eaf56bdaAdam Momtaz * injected about 5ms apart. So a 100 steps may take about 1/2 second to complete. 2333d50587be8ff021369c90554d814839335b445b0Adam Momtaz * @return true if successful 234e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 235dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 236e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 237e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean swipeLeft(int steps) throws UiObjectNotFoundException { 2383d50587be8ff021369c90554d814839335b445b0Adam Momtaz Rect rect = getVisibleBounds(); 239e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(rect.width() <= SWIPE_MARGIN_LIMIT * 2) 240e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return false; // too small to swipe 241e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return getInteractionController().swipe(rect.right - SWIPE_MARGIN_LIMIT, 242e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu rect.centerY(), rect.left + SWIPE_MARGIN_LIMIT, rect.centerY(), steps); 243e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 244e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 245e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 246e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * Perform the action on the UI element that is represented by this object. Also see 247e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * {@link #scrollToBeginning(int)}, {@link #scrollToEnd(int)}, {@link #scrollBackward()}, 248e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * {@link #scrollForward()}. This method will perform the swipe gesture over any 249e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * surface. The targeted UI element does not need to have the attribute 250e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * <code>scrollable</code> set to <code>true</code> for this operation to be performed. 2513d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 2523d50587be8ff021369c90554d814839335b445b0Adam Momtaz * @param steps indicates the number of injected move steps into the system. Steps are 253467cca7d25dbbf13c14cfd8c2ad38ab8eaf56bdaAdam Momtaz * injected about 5ms apart. So a 100 steps may take about 1/2 second to complete. 2543d50587be8ff021369c90554d814839335b445b0Adam Momtaz * @return true if successful 255e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 256dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 257e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 258e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean swipeRight(int steps) throws UiObjectNotFoundException { 2593d50587be8ff021369c90554d814839335b445b0Adam Momtaz Rect rect = getVisibleBounds(); 260e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(rect.width() <= SWIPE_MARGIN_LIMIT * 2) 261e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return false; // too small to swipe 262e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return getInteractionController().swipe(rect.left + SWIPE_MARGIN_LIMIT, 263e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu rect.centerY(), rect.right - SWIPE_MARGIN_LIMIT, rect.centerY(), steps); 264e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 265e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 266e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 2673d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Finds the visible bounds of a partially visible UI element 2683d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 269e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @param node 2707f38ef08d07295967b905a61b2356ff6cdf31159Adam Momtaz * @return null if node is null, else a Rect containing visible bounds 271e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 272e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu private Rect getVisibleBounds(AccessibilityNodeInfo node) { 273e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if (node == null) { 274e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return null; 275e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 276e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 277e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // targeted node's bounds 2787f38ef08d07295967b905a61b2356ff6cdf31159Adam Momtaz Rect nodeRect = AccessibilityNodeInfoHelper.getVisibleBoundsInScreen(node); 279e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 280e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // is the targeted node within a scrollable container? 281e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo scrollableParentNode = getScrollableParent(node); 282e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(scrollableParentNode == null) { 283e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // nothing to adjust for so return the node's Rect as is 284e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return nodeRect; 285e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 286e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 287e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // Scrollable parent's visible bounds 2887f38ef08d07295967b905a61b2356ff6cdf31159Adam Momtaz Rect parentRect = AccessibilityNodeInfoHelper 2897f38ef08d07295967b905a61b2356ff6cdf31159Adam Momtaz .getVisibleBoundsInScreen(scrollableParentNode); 290e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // adjust for partial clipping of targeted by parent node if required 291e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu nodeRect.intersect(parentRect); 292e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return nodeRect; 293e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 294e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 295e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 2967f38ef08d07295967b905a61b2356ff6cdf31159Adam Momtaz * Walk the hierarchy up to find a scrollable parent. A scrollable parent 2977f38ef08d07295967b905a61b2356ff6cdf31159Adam Momtaz * indicates that this node may be in a content where it is partially 2987f38ef08d07295967b905a61b2356ff6cdf31159Adam Momtaz * visible due to scrolling. its clickable center maybe invisible and 2997f38ef08d07295967b905a61b2356ff6cdf31159Adam Momtaz * adjustments should be made to the click coordinates. 3003d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 301e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @param node 302e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return 303e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 304e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu private AccessibilityNodeInfo getScrollableParent(AccessibilityNodeInfo node) { 305e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo parent = node; 306e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu while(parent != null) { 307e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu parent = parent.getParent(); 308e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if (parent != null && parent.isScrollable()) { 309e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return parent; 310e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 311e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 312e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return null; 313e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 314e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 315e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 3163d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Performs a click at the center of the visible bounds of the UI element represented 31746d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * by this UiObject. 3183d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 319e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true id successful else false 320e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 321dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 322e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 323e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean click() throws UiObjectNotFoundException { 324e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT); 325e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 326e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 327e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 328e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu Rect rect = getVisibleBounds(node); 32908f500a92397522c48bcdad58d37ec1be95956d1Adam Momtaz return getInteractionController().clickAndWaitForEvents(rect.centerX(), rect.centerY(), 33008f500a92397522c48bcdad58d37ec1be95956d1Adam Momtaz WAIT_FOR_EVENT_TMEOUT, false, AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED + 33108f500a92397522c48bcdad58d37ec1be95956d1Adam Momtaz AccessibilityEvent.TYPE_VIEW_SELECTED); 332e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 333e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 334e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 3353d50587be8ff021369c90554d814839335b445b0Adam Momtaz * See {@link #clickAndWaitForNewWindow(long)} 336a46ac3504426564954292b13380120e8cc6b1527Adam Momtaz * This method is intended to reliably wait for window transitions that would typically take 337a46ac3504426564954292b13380120e8cc6b1527Adam Momtaz * longer than the usual default timeouts. 3383d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 3393d50587be8ff021369c90554d814839335b445b0Adam Momtaz * @return true if the event was triggered, else false 3403d50587be8ff021369c90554d814839335b445b0Adam Momtaz * @throws UiObjectNotFoundException 341dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 3423d50587be8ff021369c90554d814839335b445b0Adam Momtaz */ 343e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean clickAndWaitForNewWindow() throws UiObjectNotFoundException { 344e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return clickAndWaitForNewWindow(WAIT_FOR_WINDOW_TMEOUT); 345e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 346e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 347e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 34846d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * Performs a click at the center of the visible bounds of the UI element represented 34946d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * by this UiObject and waits for window transitions. 35046d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * 3513d50587be8ff021369c90554d814839335b445b0Adam Momtaz * This method differ from {@link UiObject#click()} only in that this method waits for a 35246d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * a new window transition as a result of the click. Some examples of a window transition: 353e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * <li>launching a new activity</li> 354e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * <li>bringing up a pop-up menu</li> 355e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * <li>bringing up a dialog</li> 356e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * 3573d50587be8ff021369c90554d814839335b445b0Adam Momtaz * @param timeout timeout before giving up on waiting for a new window 358e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if the event was triggered, else false 359e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 360dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 361e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 362e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean clickAndWaitForNewWindow(long timeout) throws UiObjectNotFoundException { 363e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT); 364e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 365e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 366e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 367e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu Rect rect = getVisibleBounds(node); 3684ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz return getInteractionController().clickAndWaitForNewWindow( 369e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu rect.centerX(), rect.centerY(), timeout); 370e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 371e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 372e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 3733d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Clicks the top and left corner of the UI element 3743d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 375e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true on success 376e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws Exception 377dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 378e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 379e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean clickTopLeft() throws UiObjectNotFoundException { 380e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT); 381e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 382e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 383e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 384e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu Rect rect = getVisibleBounds(node); 3854ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz return getInteractionController().click(rect.left + 5, rect.top + 5); 386e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 387e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 388e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 3893d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Long clicks bottom and right corner of the UI element 3903d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 391e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if operation was successful 392e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 393dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 394e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 395e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean longClickBottomRight() throws UiObjectNotFoundException { 396e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT); 397e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 398e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 399e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 400e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu Rect rect = getVisibleBounds(node); 401e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return getInteractionController().longTap(rect.right - 5, rect.bottom - 5); 402e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 403e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 404e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 4053d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Clicks the bottom and right corner of the UI element 4063d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 407e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true on success 408e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws Exception 409dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 410e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 411e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean clickBottomRight() throws UiObjectNotFoundException { 412e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT); 413e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 414e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 415e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 416e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu Rect rect = getVisibleBounds(node); 4174ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz return getInteractionController().click(rect.right - 5, rect.bottom - 5); 418e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 419e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 420e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 4213d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Long clicks the center of the visible bounds of the UI element 4223d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 423e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if operation was successful 424e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 425dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 426e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 427e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean longClick() throws UiObjectNotFoundException { 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); 433e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return getInteractionController().longTap(rect.centerX(), rect.centerY()); 434e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 435e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 436e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 4373d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Long clicks on the top and left corner 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 longClickTopLeft() throws UiObjectNotFoundException { 444e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT); 445e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 446e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 447e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 448e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu Rect rect = getVisibleBounds(node); 449e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return getInteractionController().longTap(rect.left + 5, rect.top + 5); 450e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 451e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 452e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 4533d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Reads the <code>text</code> property of the UI element 4543d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 455e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return text value of the current node represented by this UiObject 456e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException if no match could be found 457dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 458e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 459e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public String getText() throws UiObjectNotFoundException { 460e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT); 461e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 462e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 463e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 464e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu String retVal = safeStringReturn(node.getText()); 465e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu Log.d(LOG_TAG, String.format("getText() = %s", retVal)); 466e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return retVal; 467e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 468e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 469e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 4703d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Reads the <code>content_desc</code> property of the UI element 4713d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 472e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return value of node attribute "content_desc" 473e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 474dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 475e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 476e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public String getContentDescription() throws UiObjectNotFoundException { 477e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT); 478e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 479e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 480e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 481e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return safeStringReturn(node.getContentDescription()); 482e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 483e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 484e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 48546d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * Sets the text in an editable field, after clearing the field's content. 48646d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * 48746d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * The {@link UiSelector} selector of this object must reference a UI element that is editable. 48846d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * 48946d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * When you call this method, the method first simulates a {@link #click()} on 49046d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * editable field to set focus. The method then clears the field's contents 49146d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * and injects your specified text into the field. 4923d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 49346d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * If you want to capture the original contents of the field, call {@link #getText()} first. 49446d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * You can then modify the text and use this method to update the field. 49546d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * 49646d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * @param text string to set 497e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if operation is successful 498e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 499dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 500e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 501e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean setText(String text) throws UiObjectNotFoundException { 502e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu clearTextField(); 503e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return getInteractionController().sendText(text); 504e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 505e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 506e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 50746d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * Clears the existing text contents in an editable field. 50846d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * 50946d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * The {@link UiSelector} of this object must reference a UI element that is editable. 51046d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * 51146d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * When you call this method, the method first sets focus at the start edge of the field. 51246d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * The method then simulates a long-press to select the existing text, and deletes the 51346d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * selected text. 51446d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * 51546d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * If a "Select-All" option is displayed, the method will automatically attempt to use it 51646d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * to ensure full text selection. 51746d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * 51846d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * Note that it is possible that not all the text in the field is selected; for example, 51946d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * if the text contains separators such as spaces, slashes, at symbol etc. 52046d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * Also, not all editable fields support the long-press functionality. 52146d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * 522e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 523dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 524e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 525e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public void clearTextField() throws UiObjectNotFoundException { 526e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // long click left + center 527e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT); 528e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 529e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 530e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 531e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu Rect rect = getVisibleBounds(node); 532e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu getInteractionController().longTap(rect.left + 20, rect.centerY()); 533e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // check if the edit menu is open 5344ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz UiObject selectAll = new UiObject(new UiSelector().descriptionContains("Select all")); 535e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(selectAll.waitForExists(50)) 536e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu selectAll.click(); 537e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // wait for the selection 538e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu SystemClock.sleep(250); 539e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // delete it 540e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu getInteractionController().sendKey(KeyEvent.KEYCODE_DEL, 0); 541e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 542e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 543e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 5443d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Check if the UI element's <code>checked</code> property is currently true 5453d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 546e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if it is else false 547dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 548e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 549e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean isChecked() throws UiObjectNotFoundException { 550e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT); 551e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 552e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 553e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 554e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return node.isChecked(); 555e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 556e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 557e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 5583d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Check if the UI element's <code>selected</code> property is currently true 5593d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 560e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if it is else false 561e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 562dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 563e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 564e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean isSelected() throws UiObjectNotFoundException { 565e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT); 566e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 567e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 568e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 569e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return node.isSelected(); 570e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 571e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 572e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 5733d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Check if the UI element's <code>checkable</code> property is currently true 5743d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 575e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if it is else false 576e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 577dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 578e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 579e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean isCheckable() throws UiObjectNotFoundException { 580e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT); 581e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 582e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 583e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 584e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return node.isCheckable(); 585e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 586e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 587e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 5883d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Check if the UI element's <code>enabled</code> property is currently true 5893d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 590e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if it is else false 591e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 592dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 593e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 594e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean isEnabled() throws UiObjectNotFoundException { 595e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT); 596e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 597e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 598e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 599e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return node.isEnabled(); 600e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 601e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 602e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 6033d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Check if the UI element's <code>clickable</code> property is currently true 6043d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 605e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if it is else false 606e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 607dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 608e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 609e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean isClickable() throws UiObjectNotFoundException { 610e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT); 611e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 612e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 613e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 614e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return node.isClickable(); 615e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 616e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 617e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 6183d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Check if the UI element's <code>focused</code> property is currently true 6193d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 620e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if it is else false 621e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 622dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 623e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 624e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean isFocused() throws UiObjectNotFoundException { 625e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT); 626e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 627e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 628e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 629e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return node.isFocused(); 630e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 631e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 632e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 6333d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Check if the UI element's <code>focusable</code> property is currently true 6343d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 635e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if it is else false 636e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 637dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 638e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 639e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean isFocusable() throws UiObjectNotFoundException { 640e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT); 641e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 642e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 643e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 644e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return node.isFocusable(); 645e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 646e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 647e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 6483d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Check if the UI element's <code>scrollable</code> property is currently true 6493d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 650e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if it is else false 651e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 652dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 653e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 654e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean isScrollable() throws UiObjectNotFoundException { 655e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT); 656e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 657e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 658e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 659e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return node.isScrollable(); 660e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 661e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 662e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 6633d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Check if the UI element's <code>long-clickable</code> property is currently true 6643d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 665e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if it is else false 666e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 667dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 668e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 669e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean isLongClickable() throws UiObjectNotFoundException { 670e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT); 671e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 672e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 673e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 674e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return node.isLongClickable(); 675e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 676e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 677e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 6783d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Reads the UI element's <code>package</code> property 6793d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 6803d50587be8ff021369c90554d814839335b445b0Adam Momtaz * @return true if it is else false 681e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 682dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 683e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 684e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public String getPackageName() throws UiObjectNotFoundException { 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 safeStringReturn(node.getPackageName()); 690e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 691e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 692e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 69346d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * Returns the visible bounds of the UI element. 69446d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * 69546d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * If a portion of the UI element is visible, only the bounds of the visible portion are 69646d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * reported. 6973d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 698e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return Rect 699e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 70046d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * @see {@link #getBound()} 70179693ede92636fe6f3a6ec4dc049a438fd9504ffGuang Zhu * @since API Level 17 702e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 7033d50587be8ff021369c90554d814839335b445b0Adam Momtaz public Rect getVisibleBounds() throws UiObjectNotFoundException { 704e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT); 705e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 706e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 707e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 708e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return getVisibleBounds(node); 709e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 710e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 711e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 71246d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * Returns the UI element's <code>bounds</code> property. See {@link #getVisibleBounds()} 7133d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 7143d50587be8ff021369c90554d814839335b445b0Adam Momtaz * @return Rect 7153d50587be8ff021369c90554d814839335b445b0Adam Momtaz * @throws UiObjectNotFoundException 716dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 7173d50587be8ff021369c90554d814839335b445b0Adam Momtaz */ 7183d50587be8ff021369c90554d814839335b445b0Adam Momtaz public Rect getBounds() throws UiObjectNotFoundException { 7193d50587be8ff021369c90554d814839335b445b0Adam Momtaz AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT); 7203d50587be8ff021369c90554d814839335b445b0Adam Momtaz if(node == null) { 7213d50587be8ff021369c90554d814839335b445b0Adam Momtaz throw new UiObjectNotFoundException(getSelector().toString()); 7223d50587be8ff021369c90554d814839335b445b0Adam Momtaz } 7233d50587be8ff021369c90554d814839335b445b0Adam Momtaz Rect nodeRect = new Rect(); 7243d50587be8ff021369c90554d814839335b445b0Adam Momtaz node.getBoundsInScreen(nodeRect); 7253d50587be8ff021369c90554d814839335b445b0Adam Momtaz 7263d50587be8ff021369c90554d814839335b445b0Adam Momtaz return nodeRect; 7273d50587be8ff021369c90554d814839335b445b0Adam Momtaz } 7283d50587be8ff021369c90554d814839335b445b0Adam Momtaz 7293d50587be8ff021369c90554d814839335b445b0Adam Momtaz /** 73046d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * Waits a specified length of time for a UI element to become visible. 73146d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * 73246d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * This method waits until the UI element becomes visible on the display, or 73346d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * until the timeout has elapsed. You can use this method in situations where 73446d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * the content that you want to select is not immediately displayed. 7353d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 73646d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * @param timeout the amount of time to wait (in milliseconds) 73746d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * @return true if the UI element is displayed, else false if timeout elapsed while waiting 738dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 739e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 740e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean waitForExists(long timeout) { 741e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(findAccessibilityNodeInfo(timeout) != null) { 742e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return true; 743e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 744e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return false; 745e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 746e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 747e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 74846d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * Waits a specified length of time for a UI element to become undetectable. 7493d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 75046d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * This method waits until a UI element is no longer matchable, or until the 75146d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * timeout has elapsed. 75246d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * 75346d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * A UI element becomes undetectable when the {@link UiSelector} of the object is 75446d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * unable to find a match because the element has either changed its state or is no 75546d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * longer displayed. 75646d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * 75746d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * You can use this method when attempting to wait for some long operation 75846d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * to compete, such as downloading a large file or connecting to a remote server. 75946d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * 76046d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * @param timeout time to wait (in milliseconds) 76146d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * @return true if the element is gone before timeout elapsed, else false if timeout elapsed 76246d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * but a matching element is still found. 763dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 764e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 765e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean waitUntilGone(long timeout) { 766e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu long startMills = SystemClock.uptimeMillis(); 767e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu long currentMills = 0; 768e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu while (currentMills <= timeout) { 769e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(findAccessibilityNodeInfo(0) == null) 770e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return true; 771e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu currentMills = SystemClock.uptimeMillis() - startMills; 772e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(timeout > 0) 773e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu SystemClock.sleep(WAIT_FOR_SELECTOR_POLL); 774e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 775e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return false; 776e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 777e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 778e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 77946d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * Check if UI element exists. 78046d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * 781e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * This methods performs a {@link #waitForExists(long)} with zero timeout. This 782e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * basically returns immediately whether the UI element represented by this UiObject 783e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * exists or not. If you need to wait longer for this UI element, then see 784e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * {@link #waitForExists(long)}. 7853d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 786e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if the UI element represented by this UiObject does exist 787dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 788e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 789e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean exists() { 790e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return waitForExists(0); 791e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 792e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 793e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu private String safeStringReturn(CharSequence cs) { 794e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(cs == null) 795e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return ""; 796e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return cs.toString(); 797e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 798e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu} 799