UiObject.java revision ddc1008f06fd2a875037026490ce1f848a442572
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; 23e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhuimport android.view.accessibility.AccessibilityNodeInfo; 24e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 25e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu/** 263d50587be8ff021369c90554d814839335b445b0Adam Momtaz * UiObject is a representation of UI element. It is not in any way directly bound to a 273d50587be8ff021369c90554d814839335b445b0Adam Momtaz * UI element as an object reference. A UiObject holds information to help it locate 283d50587be8ff021369c90554d814839335b445b0Adam Momtaz * at runtime a matching UI element based on its {@UiSelector} properties specified in 293d50587be8ff021369c90554d814839335b445b0Adam Momtaz * its constructor. Since a UiObject is a representative for a matching UI element, it can 303d50587be8ff021369c90554d814839335b445b0Adam Momtaz * be reused on different screens and applications with matching UI elements. Using a 313d50587be8ff021369c90554d814839335b445b0Adam Momtaz * UiObject on a screen where none of the displayed UI elements match its UiSelector's 323d50587be8ff021369c90554d814839335b445b0Adam Momtaz * properties will result in a {@UiObjectNotFoundException} to be thrown. 33e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 34e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhupublic class UiObject { 35e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu private static final String LOG_TAG = UiObject.class.getSimpleName(); 36e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu protected static final long WAIT_FOR_SELECTOR_TIMEOUT = 10 * 1000; 37e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu protected static final long WAIT_FOR_SELECTOR_POLL = 1000; 38e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // set a default timeout to 5.5s, since ANR threshold is 5s 39e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu protected static final long WAIT_FOR_WINDOW_TMEOUT = 5500; 40e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu protected static final int SWIPE_MARGIN_LIMIT = 5; 41e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 42ddc1008f06fd2a875037026490ce1f848a442572Guang Zhu private UiSelector mSelector; 43ddc1008f06fd2a875037026490ce1f848a442572Guang Zhu private final UiAutomatorBridge mUiAutomationBridge; 44e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 45e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 463d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Constructs a UiObject to represent a specific UI element matched by the specified 473d50587be8ff021369c90554d814839335b445b0Adam Momtaz * {@link UiSelector} selector properties. 483d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 49e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @param selector 50e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 514ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz public UiObject(UiSelector selector) { 52e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu mUiAutomationBridge = UiDevice.getInstance().getAutomatorBridge(); 53e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu mSelector = selector; 54e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 55e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 56e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 573d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Debugging helper. A test can dump the properties of a selector as a string 583d50587be8ff021369c90554d814839335b445b0Adam Momtaz * to its logs if needed. <code>getSelector().toString();</code> 593d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 604ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz * @return {@link UiSelector} 61e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 624ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz public final UiSelector getSelector() { 634ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz return new UiSelector(mSelector); 64e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 65e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 66e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 673d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Retrieves the {@link QueryController} to translate a {@link UiSelector} selector 683d50587be8ff021369c90554d814839335b445b0Adam Momtaz * into an {@link AccessibilityNodeInfo}. 693d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 70e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return {@link QueryController} 71e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 72ddc1008f06fd2a875037026490ce1f848a442572Guang Zhu QueryController getQueryController() { 73e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return mUiAutomationBridge.getQueryController(); 74e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 75e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 76e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 773d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Retrieves the {@link InteractionController} to perform finger actions such as tapping, 783d50587be8ff021369c90554d814839335b445b0Adam Momtaz * swiping or entering text. 793d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 80e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return {@link InteractionController} 81e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 82ddc1008f06fd2a875037026490ce1f848a442572Guang Zhu InteractionController getInteractionController() { 83e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return mUiAutomationBridge.getInteractionController(); 84e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 85e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 86e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 873d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Creates a new UiObject representing a child UI element of the element currently represented 883d50587be8ff021369c90554d814839335b445b0Adam Momtaz * by this UiObject. 893d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 903d50587be8ff021369c90554d814839335b445b0Adam Momtaz * @param selector for UI element to match 913d50587be8ff021369c90554d814839335b445b0Adam Momtaz * @return a new UiObject representing the matched UI element 92e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 934ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz public UiObject getChild(UiSelector selector) throws UiObjectNotFoundException { 944ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz return new UiObject(getSelector().childSelector(selector)); 95e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 96e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 97e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 983d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Creates a new UiObject representing a child UI element from the parent element currently 993d50587be8ff021369c90554d814839335b445b0Adam Momtaz * represented by this object. Essentially this is starting the search from the parent 1003d50587be8ff021369c90554d814839335b445b0Adam Momtaz * element and can also be used to find sibling UI elements to the one currently represented 1013d50587be8ff021369c90554d814839335b445b0Adam Momtaz * by this UiObject. 1023d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 1033d50587be8ff021369c90554d814839335b445b0Adam Momtaz * @param selector for the UI element to match 1043d50587be8ff021369c90554d814839335b445b0Adam Momtaz * @return a new UiObject representing the matched UI element 105e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 106e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 1074ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz public UiObject getFromParent(UiSelector selector) throws UiObjectNotFoundException { 1084ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz return new UiObject(getSelector().fromParent(selector)); 109e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 110e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 111e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 1123d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Counts the child UI elements immediately under the UI element currently represented by 113e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * this UiObject. 1143d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 115e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return the count of child UI elements. 116e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 117e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 118e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public int getChildCount() throws UiObjectNotFoundException { 119e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT); 120e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 121e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 122e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 123e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return node.getChildCount(); 124e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 125e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 126e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 1273d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Uses the member UiSelector properties to find a matching UI element reported in 1283d50587be8ff021369c90554d814839335b445b0Adam Momtaz * the accessibility hierarchy. 1293d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 1304ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz * @param selector {@link UiSelector} 131e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @param timeout in milliseconds 132e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return AccessibilityNodeInfo if found else null 133e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 134e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu protected AccessibilityNodeInfo findAccessibilityNodeInfo(long timeout) { 135e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo node = null; 136e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(UiDevice.getInstance().isInWatcherContext()) { 137e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // we will NOT run watchers or do any sort of polling if the 138e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // reason we're here is because of a watcher is executing. Watchers 139e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // will not have other watchers run for them so they should not block 140e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // while they poll for items to become present. We disable polling for them. 141e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu node = getQueryController().findAccessibilityNodeInfo(getSelector()); 142e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } else { 143e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu long startMills = SystemClock.uptimeMillis(); 144e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu long currentMills = 0; 145e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu while (currentMills <= timeout) { 146e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu node = getQueryController().findAccessibilityNodeInfo(getSelector()); 147e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if (node != null) { 148e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu break; 149e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } else { 150e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu UiDevice.getInstance().runWatchers(); 151e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 152e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu currentMills = SystemClock.uptimeMillis() - startMills; 153e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(timeout > 0) { 154e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu SystemClock.sleep(WAIT_FOR_SELECTOR_POLL); 155e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 156e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 157e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 158e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return node; 159e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 160e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 161e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 1623d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Perform the action on the UI element that is represented by this UiObject. Also see 163e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * {@link #scrollToBeginning(int)}, {@link #scrollToEnd(int)}, {@link #scrollBackward()}, 1643d50587be8ff021369c90554d814839335b445b0Adam Momtaz * {@link #scrollForward()}. 1653d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 166467cca7d25dbbf13c14cfd8c2ad38ab8eaf56bdaAdam Momtaz * @param steps indicates the number of injected move steps into the system. Steps are 167467cca7d25dbbf13c14cfd8c2ad38ab8eaf56bdaAdam Momtaz * injected about 5ms apart. So a 100 steps may take about 1/2 second to complete. 1683d50587be8ff021369c90554d814839335b445b0Adam Momtaz * @return true of successful 169e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 170e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 171e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean swipeUp(int steps) throws UiObjectNotFoundException { 1723d50587be8ff021369c90554d814839335b445b0Adam Momtaz Rect rect = getVisibleBounds(); 173e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(rect.height() <= SWIPE_MARGIN_LIMIT * 2) 174e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return false; // too small to swipe 175e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return getInteractionController().swipe(rect.centerX(), 176e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu rect.bottom - SWIPE_MARGIN_LIMIT, rect.centerX(), rect.top + SWIPE_MARGIN_LIMIT, 177e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu steps); 178e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 179e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 180e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 181e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * Perform the action on the UI element that is represented by this object, Also see 182e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * {@link #scrollToBeginning(int)}, {@link #scrollToEnd(int)}, {@link #scrollBackward()}, 183e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * {@link #scrollForward()}. This method will perform the swipe gesture over any 184e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * surface. The targeted UI element does not need to have the attribute 185e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * <code>scrollable</code> set to <code>true</code> for this operation to be performed. 1863d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 1873d50587be8ff021369c90554d814839335b445b0Adam 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 if successful 190e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 191e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 192e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean swipeDown(int steps) throws UiObjectNotFoundException { 1933d50587be8ff021369c90554d814839335b445b0Adam Momtaz Rect rect = getVisibleBounds(); 194e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(rect.height() <= SWIPE_MARGIN_LIMIT * 2) 195e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return false; // too small to swipe 196e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return getInteractionController().swipe(rect.centerX(), 197e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu rect.top + SWIPE_MARGIN_LIMIT, rect.centerX(), 198e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu rect.bottom - SWIPE_MARGIN_LIMIT, steps); 199e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 200e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 201e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 202e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * Perform the action on the UI element that is represented by this object. Also see 203e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * {@link #scrollToBeginning(int)}, {@link #scrollToEnd(int)}, {@link #scrollBackward()}, 204e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * {@link #scrollForward()}. This method will perform the swipe gesture over any 205e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * surface. The targeted UI element does not need to have the attribute 206e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * <code>scrollable</code> set to <code>true</code> for this operation to be performed. 2073d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 2083d50587be8ff021369c90554d814839335b445b0Adam Momtaz * @param steps indicates the number of injected move steps into the system. Steps are 209467cca7d25dbbf13c14cfd8c2ad38ab8eaf56bdaAdam Momtaz * injected about 5ms apart. So a 100 steps may take about 1/2 second to complete. 2103d50587be8ff021369c90554d814839335b445b0Adam Momtaz * @return true if successful 211e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 212e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 213e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean swipeLeft(int steps) throws UiObjectNotFoundException { 2143d50587be8ff021369c90554d814839335b445b0Adam Momtaz Rect rect = getVisibleBounds(); 215e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(rect.width() <= SWIPE_MARGIN_LIMIT * 2) 216e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return false; // too small to swipe 217e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return getInteractionController().swipe(rect.right - SWIPE_MARGIN_LIMIT, 218e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu rect.centerY(), rect.left + SWIPE_MARGIN_LIMIT, rect.centerY(), steps); 219e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 220e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 221e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 222e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * Perform the action on the UI element that is represented by this object. Also see 223e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * {@link #scrollToBeginning(int)}, {@link #scrollToEnd(int)}, {@link #scrollBackward()}, 224e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * {@link #scrollForward()}. This method will perform the swipe gesture over any 225e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * surface. The targeted UI element does not need to have the attribute 226e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * <code>scrollable</code> set to <code>true</code> for this operation to be performed. 2273d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 2283d50587be8ff021369c90554d814839335b445b0Adam Momtaz * @param steps indicates the number of injected move steps into the system. Steps are 229467cca7d25dbbf13c14cfd8c2ad38ab8eaf56bdaAdam Momtaz * injected about 5ms apart. So a 100 steps may take about 1/2 second to complete. 2303d50587be8ff021369c90554d814839335b445b0Adam Momtaz * @return true if successful 231e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 232e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 233e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean swipeRight(int steps) throws UiObjectNotFoundException { 2343d50587be8ff021369c90554d814839335b445b0Adam Momtaz Rect rect = getVisibleBounds(); 235e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(rect.width() <= SWIPE_MARGIN_LIMIT * 2) 236e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return false; // too small to swipe 237e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return getInteractionController().swipe(rect.left + SWIPE_MARGIN_LIMIT, 238e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu rect.centerY(), rect.right - SWIPE_MARGIN_LIMIT, rect.centerY(), steps); 239e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 240e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 241e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 2423d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Finds the visible bounds of a partially visible UI element 2433d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 244e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @param node 245e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return the same AccessibilityNodeInfo passed in as argument 246e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 247e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu private Rect getVisibleBounds(AccessibilityNodeInfo node) { 248e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if (node == null) { 249e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return null; 250e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 251e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 252e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // targeted node's bounds 253e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu Rect nodeRect = new Rect(); 254e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu node.getBoundsInScreen(nodeRect); 255e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 256e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // is the targeted node within a scrollable container? 257e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo scrollableParentNode = getScrollableParent(node); 258e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(scrollableParentNode == null) { 259e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // nothing to adjust for so return the node's Rect as is 260e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return nodeRect; 261e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 262e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 263e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // Scrollable parent's visible bounds 264e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu Rect parentRect = new Rect(); 265e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu scrollableParentNode.getBoundsInScreen(parentRect); 266e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // adjust for partial clipping of targeted by parent node if required 267e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu nodeRect.intersect(parentRect); 268e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return nodeRect; 269e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 270e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 271e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 272e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * Walk the hierarchy up to find a scrollable parent. A scrollable parent indicates that 273e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * this node may be in a content where it is partially visible due to scrolling. its 274e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * clickable center maybe invisible and adjustments should be made to the click coordinates. 2753d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 276e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @param node 277e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return 278e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 279e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu private AccessibilityNodeInfo getScrollableParent(AccessibilityNodeInfo node) { 280e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo parent = node; 281e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu while(parent != null) { 282e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu parent = parent.getParent(); 283e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if (parent != null && parent.isScrollable()) { 284e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return parent; 285e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 286e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 287e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return null; 288e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 289e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 290e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 2913d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Performs a click at the center of the visible bounds of the UI element represented 2923d50587be8ff021369c90554d814839335b445b0Adam Momtaz * by this UiObject </p> 2933d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Take note that the UI element represented by this UiObject may not have its attribute 2943d50587be8ff021369c90554d814839335b445b0Adam Momtaz * <code>clickable</code> set to <code>true</code> however one of its ancestor elements 2953d50587be8ff021369c90554d814839335b445b0Adam Momtaz * may be clickable. This is the reason this method does not check the clickable attribute. 2963d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 297e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true id successful else false 298e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 299e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 300e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean click() throws UiObjectNotFoundException { 301e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT); 302e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 303e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 304e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 305e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu Rect rect = getVisibleBounds(node); 3064ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz return getInteractionController().click(rect.centerX(), rect.centerY()); 307e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 308e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 309e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 3103d50587be8ff021369c90554d814839335b445b0Adam Momtaz * See {@link #clickAndWaitForNewWindow(long)} 3113d50587be8ff021369c90554d814839335b445b0Adam Momtaz * This method is intended for reliably wait for window transitions that would typically take 3123d50587be8ff021369c90554d814839335b445b0Adam Momtaz * longer than the usual deault timeouts. 3133d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 3143d50587be8ff021369c90554d814839335b445b0Adam Momtaz * @return true if the event was triggered, else false 3153d50587be8ff021369c90554d814839335b445b0Adam Momtaz * @throws UiObjectNotFoundException 3163d50587be8ff021369c90554d814839335b445b0Adam Momtaz */ 317e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean clickAndWaitForNewWindow() throws UiObjectNotFoundException { 318e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return clickAndWaitForNewWindow(WAIT_FOR_WINDOW_TMEOUT); 319e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 320e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 321e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 3223d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Performs a click at the center of the visible bounds of the UI element UI element represented 3233d50587be8ff021369c90554d814839335b445b0Adam Momtaz * by this UiObject </p> 3243d50587be8ff021369c90554d814839335b445b0Adam Momtaz * This method differ from {@link UiObject#click()} only in that this method waits for a 3253d50587be8ff021369c90554d814839335b445b0Adam Momtaz * a new window transition as a result of the tap. Some examples of a window transition: 326e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * <li>launching a new activity</li> 327e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * <li>bringing up a pop-up menu</li> 328e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * <li>bringing up a dialog</li> 329e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * 3303d50587be8ff021369c90554d814839335b445b0Adam Momtaz * @param timeout timeout before giving up on waiting for a new window 331e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if the event was triggered, else false 332e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 333e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 334e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean clickAndWaitForNewWindow(long timeout) throws UiObjectNotFoundException { 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); 3404ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz return getInteractionController().clickAndWaitForNewWindow( 341e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu rect.centerX(), rect.centerY(), timeout); 342e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 343e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 344e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 3453d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Clicks the top and left corner of the UI element 3463d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 347e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true on success 348e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws Exception 349e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 350e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean clickTopLeft() throws UiObjectNotFoundException { 351e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT); 352e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 353e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 354e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 355e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu Rect rect = getVisibleBounds(node); 3564ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz return getInteractionController().click(rect.left + 5, rect.top + 5); 357e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 358e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 359e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 3603d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Long clicks bottom and right corner of the UI element 3613d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 362e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if operation was successful 363e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 364e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 365e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean longClickBottomRight() throws UiObjectNotFoundException { 366e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT); 367e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 368e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 369e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 370e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu Rect rect = getVisibleBounds(node); 371e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return getInteractionController().longTap(rect.right - 5, rect.bottom - 5); 372e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 373e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 374e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 3753d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Clicks the bottom and right corner of the UI element 3763d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 377e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true on success 378e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws Exception 379e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 380e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean clickBottomRight() throws UiObjectNotFoundException { 381e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT); 382e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 383e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 384e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 385e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu Rect rect = getVisibleBounds(node); 3864ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz return getInteractionController().click(rect.right - 5, rect.bottom - 5); 387e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 388e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 389e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 3903d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Long clicks the center of the visible bounds of the UI element 3913d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 392e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if operation was successful 393e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 394e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 395e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean longClick() 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.centerX(), rect.centerY()); 402e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 403e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 404e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 4053d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Long clicks on the top and left corner of the UI element 4063d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 407e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if operation was successful 408e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 409e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 410e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean longClickTopLeft() throws UiObjectNotFoundException { 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.left + 5, rect.top + 5); 417e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 418e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 419e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 4203d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Reads the <code>text</code> property of the UI element 4213d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 422e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return text value of the current node represented by this UiObject 423e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException if no match could be found 424e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 425e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public String getText() throws UiObjectNotFoundException { 426e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT); 427e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 428e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 429e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 430e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu String retVal = safeStringReturn(node.getText()); 431e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu Log.d(LOG_TAG, String.format("getText() = %s", retVal)); 432e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return retVal; 433e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 434e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 435e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 4363d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Reads the <code>content_desc</code> property of the UI element 4373d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 438e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return value of node attribute "content_desc" 439e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 440e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 441e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public String getContentDescription() throws UiObjectNotFoundException { 442e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT); 443e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 444e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 445e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 446e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return safeStringReturn(node.getContentDescription()); 447e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 448e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 449e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 450e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * First this function clears the existing text from the field. If this is not the intended 451e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * behavior, do a {@link #getText()} first, modify the text and then use this function. 4524ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz * The {@link UiSelector} selector of this object MUST be pointing directly at a UI element 4533d50587be8ff021369c90554d814839335b445b0Adam Momtaz * that accepts edits. The way this method works is by first performing a {@link #click()} 4543d50587be8ff021369c90554d814839335b445b0Adam Momtaz * on the edit field to set focus then it begins injecting the text 4553d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 456e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @param text 457e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if operation is successful 458e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 459e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 460e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean setText(String text) throws UiObjectNotFoundException { 461e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu clearTextField(); 462e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return getInteractionController().sendText(text); 463e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 464e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 465e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 466e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * The object targeted must be an edit field capable of performing text insert. This 4673d50587be8ff021369c90554d814839335b445b0Adam Momtaz * method sets focus at the start edge of the field and long presses to select 4683d50587be8ff021369c90554d814839335b445b0Adam Momtaz * existing text. Note: It is possible that not all the text is selected especially 4693d50587be8ff021369c90554d814839335b445b0Adam Momtaz * if the text contains separators such as spaces, slashes, at signs etc... The function 4703d50587be8ff021369c90554d814839335b445b0Adam Momtaz * will attempt to use the "Select-All" option if one is displayed to ensure full text 4713d50587be8ff021369c90554d814839335b445b0Adam Momtaz * selection. 472e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 473e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 474e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public void clearTextField() throws UiObjectNotFoundException { 475e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // long click left + center 476e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT); 477e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 478e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 479e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 480e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu Rect rect = getVisibleBounds(node); 481e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu getInteractionController().longTap(rect.left + 20, rect.centerY()); 482e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // check if the edit menu is open 4834ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz UiObject selectAll = new UiObject(new UiSelector().descriptionContains("Select all")); 484e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(selectAll.waitForExists(50)) 485e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu selectAll.click(); 486e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // wait for the selection 487e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu SystemClock.sleep(250); 488e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // delete it 489e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu getInteractionController().sendKey(KeyEvent.KEYCODE_DEL, 0); 490e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 491e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 492e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 4933d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Check if the UI element's <code>checked</code> property is currently true 4943d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 495e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if it is else false 496e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 497e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean isChecked() throws UiObjectNotFoundException { 498e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT); 499e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 500e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 501e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 502e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return node.isChecked(); 503e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 504e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 505e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 5063d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Check if the UI element's <code>selected</code> property is currently true 5073d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 508e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if it is else false 509e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 510e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 511e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean isSelected() throws UiObjectNotFoundException { 512e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT); 513e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 514e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 515e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 516e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return node.isSelected(); 517e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 518e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 519e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 5203d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Check if the UI element's <code>checkable</code> property is currently true 5213d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 522e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if it is else false 523e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 524e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 525e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean isCheckable() throws UiObjectNotFoundException { 526e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT); 527e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 528e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 529e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 530e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return node.isCheckable(); 531e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 532e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 533e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 5343d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Check if the UI element's <code>enabled</code> property is currently true 5353d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 536e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if it is else false 537e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 538e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 539e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean isEnabled() throws UiObjectNotFoundException { 540e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT); 541e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 542e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 543e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 544e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return node.isEnabled(); 545e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 546e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 547e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 5483d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Check if the UI element's <code>clickable</code> property is currently true 5493d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 550e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if it is else false 551e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 552e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 553e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean isClickable() throws UiObjectNotFoundException { 554e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT); 555e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 556e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 557e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 558e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return node.isClickable(); 559e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 560e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 561e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 5623d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Check if the UI element's <code>focused</code> property is currently true 5633d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 564e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if it is else false 565e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 566e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 567e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean isFocused() throws UiObjectNotFoundException { 568e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT); 569e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 570e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 571e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 572e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return node.isFocused(); 573e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 574e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 575e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 5763d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Check if the UI element's <code>focusable</code> property is currently true 5773d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 578e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if it is else false 579e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 580e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 581e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean isFocusable() throws UiObjectNotFoundException { 582e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT); 583e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 584e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 585e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 586e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return node.isFocusable(); 587e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 588e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 589e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 5903d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Check if the UI element's <code>scrollable</code> property is currently true 5913d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 592e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if it is else false 593e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 594e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 595e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean isScrollable() throws UiObjectNotFoundException { 596e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT); 597e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 598e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 599e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 600e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return node.isScrollable(); 601e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 602e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 603e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 6043d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Check if the UI element's <code>long-clickable</code> property is currently true 6053d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 606e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if it is else false 607e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 608e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 609e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean isLongClickable() 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.isLongClickable(); 615e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 616e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 617e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 6183d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Reads the UI element's <code>package</code> property 6193d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 6203d50587be8ff021369c90554d814839335b445b0Adam Momtaz * @return true if it is else false 621e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 622e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 623e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public String getPackageName() throws UiObjectNotFoundException { 624e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT); 625e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 626e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 627e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 628e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return safeStringReturn(node.getPackageName()); 629e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 630e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 631e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 6323d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Reports the visible bounds of the UI element. If a portion of the UI element is 6333d50587be8ff021369c90554d814839335b445b0Adam Momtaz * visible, only the bounds of the visible portion are reported. see {@link #getBound()} 6343d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 635e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return Rect 636e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 637e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 6383d50587be8ff021369c90554d814839335b445b0Adam Momtaz public Rect getVisibleBounds() throws UiObjectNotFoundException { 639e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT); 640e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 641e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 642e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 643e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return getVisibleBounds(node); 644e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 645e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 646e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 6473d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Reads the UI element's <code>bounds</code> property. See {@link #getVisibleBounds()} 6483d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 6493d50587be8ff021369c90554d814839335b445b0Adam Momtaz * @return Rect 6503d50587be8ff021369c90554d814839335b445b0Adam Momtaz * @throws UiObjectNotFoundException 6513d50587be8ff021369c90554d814839335b445b0Adam Momtaz */ 6523d50587be8ff021369c90554d814839335b445b0Adam Momtaz public Rect getBounds() throws UiObjectNotFoundException { 6533d50587be8ff021369c90554d814839335b445b0Adam Momtaz AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT); 6543d50587be8ff021369c90554d814839335b445b0Adam Momtaz if(node == null) { 6553d50587be8ff021369c90554d814839335b445b0Adam Momtaz throw new UiObjectNotFoundException(getSelector().toString()); 6563d50587be8ff021369c90554d814839335b445b0Adam Momtaz } 6573d50587be8ff021369c90554d814839335b445b0Adam Momtaz Rect nodeRect = new Rect(); 6583d50587be8ff021369c90554d814839335b445b0Adam Momtaz node.getBoundsInScreen(nodeRect); 6593d50587be8ff021369c90554d814839335b445b0Adam Momtaz 6603d50587be8ff021369c90554d814839335b445b0Adam Momtaz return nodeRect; 6613d50587be8ff021369c90554d814839335b445b0Adam Momtaz } 6623d50587be8ff021369c90554d814839335b445b0Adam Momtaz 6633d50587be8ff021369c90554d814839335b445b0Adam Momtaz /** 664e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * This method will wait for a UI element to become visible on the display. It 665e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * can be used for situations where the content to be selected is not yet displayed 6663d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 667e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @param timeout 668e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if the UI element exists else false for timeout while waiting 669e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 670e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean waitForExists(long timeout) { 671e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(findAccessibilityNodeInfo(timeout) != null) { 672e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return true; 673e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 674e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return false; 675e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 676e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 677e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 6783d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Helper to wait for a UI element to no longer be matchable. An element becomes 6793d50587be8ff021369c90554d814839335b445b0Adam Momtaz * un-matchable when this UiObject's {@link UiSelector} no longer matches the 6803d50587be8ff021369c90554d814839335b445b0Adam Momtaz * UI element because it has either changed its state or is no longer displayed. 6813d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 682e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @param timeout 6833d50587be8ff021369c90554d814839335b445b0Adam Momtaz * @return true if gone before timeout else false for still matching an element 684e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 685e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean waitUntilGone(long timeout) { 686e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu long startMills = SystemClock.uptimeMillis(); 687e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu long currentMills = 0; 688e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu while (currentMills <= timeout) { 689e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(findAccessibilityNodeInfo(0) == null) 690e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return true; 691e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu currentMills = SystemClock.uptimeMillis() - startMills; 692e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(timeout > 0) 693e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu SystemClock.sleep(WAIT_FOR_SELECTOR_POLL); 694e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 695e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return false; 696e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 697e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 698e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 699e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * This methods performs a {@link #waitForExists(long)} with zero timeout. This 700e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * basically returns immediately whether the UI element represented by this UiObject 701e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * exists or not. If you need to wait longer for this UI element, then see 702e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * {@link #waitForExists(long)}. 7033d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 704e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if the UI element represented by this UiObject does exist 705e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 706e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean exists() { 707e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return waitForExists(0); 708e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 709e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 710e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu private String safeStringReturn(CharSequence cs) { 711e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(cs == null) 712e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return ""; 713e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return cs.toString(); 714e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 715e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu} 716