UiObject.java revision e54d649fb83a0a44516e5c25a9ac1992c8950e59
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/** 26e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * UiObject is designed to be a representation of displayed UI element. It is not in any way 27e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * directly bound to a specific UI element. It holds information to find any displayed UI element 28e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * that matches its selectors. This means it can be reused on any screen where a UI element 29e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * exists to match its selector criteria. This help tests define a single UiObject say for 30e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * an "OK" or tool-bar button and use it across many activities. 31e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 32e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhupublic class UiObject { 33e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu private static final String LOG_TAG = UiObject.class.getSimpleName(); 34e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu protected static final long WAIT_FOR_SELECTOR_TIMEOUT = 10 * 1000; 35e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu protected static final long WAIT_FOR_SELECTOR_POLL = 1000; 36e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // set a default timeout to 5.5s, since ANR threshold is 5s 37e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu protected static final long WAIT_FOR_WINDOW_TMEOUT = 5500; 38e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu protected static final int SWIPE_MARGIN_LIMIT = 5; 39e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 40e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu protected By mSelector; 41e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu protected final UiDevice mDevice; 42e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu protected final UiAutomatorBridge mUiAutomationBridge; 43e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 44e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 45e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * Constructs a UiObject that references any UI element that may match the specified 46e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * {@link By} selector. UiObject can be pre-constructed and reused across an application 47e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * where applicable. A good example is a tool bar and its buttons. A tool bar may remain 48e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * visible on the various views the application is displaying but may have different 49e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * contextual buttons displayed for each. The same UiObject that describes the tool bar 50e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * can be reused.<p/> 51e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * It is a good idea in certain cases before using any operations of this UiObject is to 52e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * call {@link #exists()} to verify if the UI element matching this object is actually 53e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * visible on the screen. This way the test can gracefully handle this situation else 54e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * a {@link UiObjectNotFoundException} will be thrown when using this object. 55e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @param selector 56e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 57e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public UiObject(By selector) { 58e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu mUiAutomationBridge = UiDevice.getInstance().getAutomatorBridge(); 59e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu mDevice = UiDevice.getInstance(); 60e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu mSelector = selector; 61e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 62e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 63e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 64e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * Helper for debugging. During testing a test can dump the selector of the object into 65e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * its logs of needed. <code>getSelector().toString();</code> 66e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return {@link By} 67e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 68e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public final By getSelector() { 69e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return By.selector(mSelector); 70e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 71e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 72e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 73e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * Used in test operations to retrieve the {@link QueryController} to translate 74e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * a {@link By} selector into an {@link AccessibilityNodeInfo}. 75e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return {@link QueryController} 76e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 77e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu protected QueryController getQueryController() { 78e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return mUiAutomationBridge.getQueryController(); 79e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 80e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 81e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 82e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * Used in test operations to retrieve the {@link InteractionController} to perform 83e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * finger actions such as tapping, swiping or entering text. 84e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return {@link InteractionController} 85e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 86e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu protected InteractionController getInteractionController() { 87e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return mUiAutomationBridge.getInteractionController(); 88e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 89e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 90e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 91e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * Creates a new UiObject that points at a child UI element of the currently pointed 92e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * to element by this object. UI element are considered layout elements as well as UI 93e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * widgets. A layout element could have child widgets like buttons and text labels. 94e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @param selector 95e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return a new UiObject with a new selector. It doesn't test if the object exists. 96e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 97e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public UiObject getChild(By selector) throws UiObjectNotFoundException { 98e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return new UiObject(By.selector(getSelector().childSelector(selector))); 99e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 100e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 101e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 102e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * Creates a new UiObject that points at a child UI element of the parent of this object. 103e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * Essentially this is starting the search from any one of the siblings UI element of this 104e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * element. 105e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @param selector 106e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return 107e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 108e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 109e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public UiObject getFromParent(By selector) throws UiObjectNotFoundException { 110e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return new UiObject(By.selector(getSelector().fromParent(selector))); 111e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 112e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 113e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 114e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * Counts the child UI elements immediately under the UI element currently referenced by 115e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * this UiObject. 116e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return the count of child UI elements. 117e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 118e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 119e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public int getChildCount() throws UiObjectNotFoundException { 120e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT); 121e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 122e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 123e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 124e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return node.getChildCount(); 125e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 126e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 127e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 128e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * Helper method to allow for a specific content to become present on the 129e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * screen before moving on to do other operations. 130e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @param selector {@link By} 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 /** 162e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * Perform the action on the UI element that is represented by this object. Also see 163e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * {@link #scrollToBeginning(int)}, {@link #scrollToEnd(int)}, {@link #scrollBackward()}, 164e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * {@link #scrollForward()}. This method will perform the swipe gesture over any 165e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * surface. The targeted UI element does not need to have the attribute 166e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * <code>scrollable</code> set to <code>true</code> for this operation to be performed. 167e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @param steps indicates the number of injected move steps into the system. More steps 168e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * injected the smoother the motion and slower. 169e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return 170e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 171e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 172e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean swipeUp(int steps) throws UiObjectNotFoundException { 173e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu Rect rect = getBounds(); 174e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(rect.height() <= SWIPE_MARGIN_LIMIT * 2) 175e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return false; // too small to swipe 176e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return getInteractionController().swipe(rect.centerX(), 177e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu rect.bottom - SWIPE_MARGIN_LIMIT, rect.centerX(), rect.top + SWIPE_MARGIN_LIMIT, 178e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu steps); 179e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 180e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 181e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 182e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * Perform the action on the UI element that is represented by this object, Also see 183e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * {@link #scrollToBeginning(int)}, {@link #scrollToEnd(int)}, {@link #scrollBackward()}, 184e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * {@link #scrollForward()}. This method will perform the swipe gesture over any 185e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * surface. The targeted UI element does not need to have the attribute 186e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * <code>scrollable</code> set to <code>true</code> for this operation to be performed. 187e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @param steps indicates the number of injected move steps into the system. More steps 188e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * injected the smoother the motion and slower. 189e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return 190e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 191e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 192e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean swipeDown(int steps) throws UiObjectNotFoundException { 193e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu Rect rect = getBounds(); 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. 207e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @param steps indicates the number of injected move steps into the system. More steps 208e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * injected the smoother the motion and slower. 209e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return 210e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 211e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 212e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean swipeLeft(int steps) throws UiObjectNotFoundException { 213e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu Rect rect = getBounds(); 214e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(rect.width() <= SWIPE_MARGIN_LIMIT * 2) 215e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return false; // too small to swipe 216e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return getInteractionController().swipe(rect.right - SWIPE_MARGIN_LIMIT, 217e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu rect.centerY(), rect.left + SWIPE_MARGIN_LIMIT, rect.centerY(), steps); 218e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 219e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 220e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 221e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * Perform the action on the UI element that is represented by this object. Also see 222e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * {@link #scrollToBeginning(int)}, {@link #scrollToEnd(int)}, {@link #scrollBackward()}, 223e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * {@link #scrollForward()}. This method will perform the swipe gesture over any 224e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * surface. The targeted UI element does not need to have the attribute 225e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * <code>scrollable</code> set to <code>true</code> for this operation to be performed. 226e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @param steps indicates the number of injected move steps into the system. More steps 227e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * injected the smoother the motion and slower. 228e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return 229e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 230e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 231e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean swipeRight(int steps) throws UiObjectNotFoundException { 232e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu Rect rect = getBounds(); 233e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(rect.width() <= SWIPE_MARGIN_LIMIT * 2) 234e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return false; // too small to swipe 235e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return getInteractionController().swipe(rect.left + SWIPE_MARGIN_LIMIT, 236e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu rect.centerY(), rect.right - SWIPE_MARGIN_LIMIT, rect.centerY(), steps); 237e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 238e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 239e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 240e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * In rare situations, the node hierarchy returned from accessibility will 241e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * return items that are slightly OFF the screen (list view contents). This method 242e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * validate that the item is visible to avoid click operation failures. It will adjust 243e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * the center of the click as much as possible to be within visible bounds to make 244e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * the click successful. 245e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @param node 246e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return the same AccessibilityNodeInfo passed in as argument 247e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 248e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu private Rect getVisibleBounds(AccessibilityNodeInfo node) { 249e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if (node == null) { 250e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return null; 251e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 252e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 253e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // targeted node's bounds 254e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu Rect nodeRect = new Rect(); 255e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu node.getBoundsInScreen(nodeRect); 256e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 257e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // is the targeted node within a scrollable container? 258e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo scrollableParentNode = getScrollableParent(node); 259e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(scrollableParentNode == null) { 260e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // nothing to adjust for so return the node's Rect as is 261e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return nodeRect; 262e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 263e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 264e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // Scrollable parent's visible bounds 265e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu Rect parentRect = new Rect(); 266e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu scrollableParentNode.getBoundsInScreen(parentRect); 267e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // adjust for partial clipping of targeted by parent node if required 268e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu nodeRect.intersect(parentRect); 269e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return nodeRect; 270e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 271e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 272e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 273e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * Walk the hierarchy up to find a scrollable parent. A scrollable parent indicates that 274e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * this node may be in a content where it is partially visible due to scrolling. its 275e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * clickable center maybe invisible and adjustments should be made to the click coordinates. 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 /** 291e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * Performs a tap over the UI element this object represents. </p> 292e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * Take note that the UI element directly represented by this UiObject may not have 293e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * its attribute <code>clickable</code> set to <code>true</code> and yet still perform 294e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * the click successfully. This is because all clicks are performed in the center of the 295e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * targeted UI element and if this element is a child or a parent that wraps the clickable 296e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * element the operation will still succeed. This is the reason this operation does not 297e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * not validate the targeted UI element is clickable or not before operating. 298e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true id successful else false 299e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 300e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 301e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean click() throws UiObjectNotFoundException { 302e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT); 303e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 304e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 305e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 306e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu Rect rect = getVisibleBounds(node); 307e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return getInteractionController().tap(rect.centerX(), rect.centerY()); 308e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 309e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 310e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 311e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * 312e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * Performs a tap over the represented UI element, and expect window transition as a result.</p> 313e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * 314e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * This method is similar to the plain {@link UiObject#click()}, with an important difference 315e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * that the method goes further to expect a window transition as a result of the tap. Some 316e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * examples of a window transition: 317e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * <li>launching a new activity</li> 318e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * <li>bringing up a pop-up menu</li> 319e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * <li>bringing up a dialog</li> 320e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * This method is intended for reliably handling window transitions that would typically lasts 321e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * longer than the usual preset timeouts. 322e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * 323e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if the event was triggered, else false 324e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 325e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 326e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean clickAndWaitForNewWindow() throws UiObjectNotFoundException { 327e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return clickAndWaitForNewWindow(WAIT_FOR_WINDOW_TMEOUT); 328e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 329e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 330e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 331e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * 332e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * Performs a tap over the represented UI element, and expect window transition as a result.</p> 333e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * 334e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * This method is similar to the plain {@link UiObject#click()}, with an important difference 335e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * that the method goes further to expect a window transition as a result of the tap. Some 336e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * examples of a window transition: 337e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * <li>launching a new activity</li> 338e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * <li>bringing up a pop-up menu</li> 339e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * <li>bringing up a dialog</li> 340e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * This method is intended for reliably handling window transitions that would typically lasts 341e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * longer than the usual preset timeouts. 342e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * 343e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @param timeout timeout before giving up on waiting for new window 344e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if the event was triggered, else false 345e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 346e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 347e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean clickAndWaitForNewWindow(long timeout) throws UiObjectNotFoundException { 348e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT); 349e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 350e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 351e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 352e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu Rect rect = getVisibleBounds(node); 353e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return getInteractionController().tapAndWaitForNewWindow( 354e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu rect.centerX(), rect.centerY(), timeout); 355e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 356e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 357e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 358e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * Click the top and left corner of the UI element. 359e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true on success 360e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws Exception 361e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 362e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean clickTopLeft() 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); 368e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return getInteractionController().tap(rect.left + 5, rect.top + 5); 369e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 370e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 371e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 372e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * Long clicks a UI element pointed to by the {@link By} selector of this object at the 373e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * bottom right corner. The duration of what will be considered as a long click is dynamically 374e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * retrieved from the system and used in the operation. 375e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if operation was successful 376e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 377e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 378e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean longClickBottomRight() throws UiObjectNotFoundException { 379e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT); 380e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 381e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 382e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 383e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu Rect rect = getVisibleBounds(node); 384e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return getInteractionController().longTap(rect.right - 5, rect.bottom - 5); 385e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 386e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 387e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 388e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * Click the bottom and right corner of the UI element. 389e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true on success 390e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws Exception 391e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 392e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean clickBottomRight() throws UiObjectNotFoundException { 393e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT); 394e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 395e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 396e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 397e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu Rect rect = getVisibleBounds(node); 398e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return getInteractionController().tap(rect.right - 5, rect.bottom - 5); 399e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 400e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 401e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 402e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * Long clicks a UI element pointed to by the {@link By} selector of this object. The 403e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * duration of what will be considered as a long click is dynamically retrieved from the 404e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * system and used in the operation. 405e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if operation was successful 406e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 407e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 408e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean longClick() throws UiObjectNotFoundException { 409e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT); 410e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 411e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 412e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 413e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu Rect rect = getVisibleBounds(node); 414e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return getInteractionController().longTap(rect.centerX(), rect.centerY()); 415e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 416e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 417e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 418e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * Long clicks a UI element pointed to by the {@link By} selector of this object at the 419e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * top left corner. The duration of what will be considered as a long click is dynamically 420e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * retrieved from the system and used in the operation. 421e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if operation was successful 422e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 423e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 424e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean longClickTopLeft() throws UiObjectNotFoundException { 425e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT); 426e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 427e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 428e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 429e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu Rect rect = getVisibleBounds(node); 430e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return getInteractionController().longTap(rect.left + 5, rect.top + 5); 431e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 432e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 433e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 434e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * This function can be used to return the UI element's displayed text. This applies to 435e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * UI element that are displaying labels or edit fields. 436e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return text value of the current node represented by this UiObject 437e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException if no match could be found 438e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 439e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public String getText() throws UiObjectNotFoundException { 440e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT); 441e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 442e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 443e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 444e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu String retVal = safeStringReturn(node.getText()); 445e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu Log.d(LOG_TAG, String.format("getText() = %s", retVal)); 446e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return retVal; 447e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 448e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 449e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 450e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * Retrieves the content-description value set for the UI element. In Accessibility, the 451e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * spoken text to speech is usually the <code>text</code> property of the UI element. If that 452e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * is not present, then the content-description is spoken. Many UI element such as buttons on 453e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * a toolbar may be too small to incorporate a visible text on their surfaces, so in such 454e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * cases, these UI elements must have their content-description fields populated to describe 455e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * them when accessibility is active. 456e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return value of node attribute "content_desc" 457e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 458e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 459e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public String getContentDescription() 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 return safeStringReturn(node.getContentDescription()); 465e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 466e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 467e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 468e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * First this function clears the existing text from the field. If this is not the intended 469e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * behavior, do a {@link #getText()} first, modify the text and then use this function. 470e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * The {@link By} selector of this object MUST be pointing directly at a UI element that 471e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * can accept edits. The way this method works is by first performing a {@link #click()} 472e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * on the edit field to set focus then it begins injecting the content of the text param 473e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * into the system. Since the targeted field is in focus, the text contents should be 474e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * inserted into the field.<p/> 475e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @param text 476e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if operation is successful 477e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 478e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 479e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean setText(String text) throws UiObjectNotFoundException { 480e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu clearTextField(); 481e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return getInteractionController().sendText(text); 482e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 483e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 484e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 485e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * The object targeted must be an edit field capable of performing text insert. This 486e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * method sets focus at the left edge of the field and long presses to select 487e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * existing text. It will then follow that with delete press. Note: It is possible 488e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * that not all the text is selected especially if the text contained separators 489e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * such as spaces, slashes, at signs etc... The function will attempt to use the 490e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * Select-All option if one is displayed to ensure full text selection. 491e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 492e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 493e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public void clearTextField() throws UiObjectNotFoundException { 494e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // long click left + center 495e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT); 496e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 497e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 498e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 499e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu Rect rect = getVisibleBounds(node); 500e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu getInteractionController().longTap(rect.left + 20, rect.centerY()); 501e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // check if the edit menu is open 502e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu UiObject selectAll = new UiObject(By.selector().descriptionContains("Select all")); 503e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(selectAll.waitForExists(50)) 504e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu selectAll.click(); 505e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // wait for the selection 506e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu SystemClock.sleep(250); 507e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // delete it 508e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu getInteractionController().sendKey(KeyEvent.KEYCODE_DEL, 0); 509e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 510e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 511e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 512e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * Check if item pointed to by this object's selector is currently checked. <p/> 513e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * Take note that the {@link By} selector specified for this UiObjecy must be pointing 514e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * directly at the element you wish to query for this attribute as this UiObject may be 515e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * using {@link By} selectors that may be pointing at a parent element of the element 516e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * you're querying while still providing the desired functionality in terms of coordinates 517e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * for taps and swipes. 518e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if it is else false 519e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 520e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean isChecked() throws UiObjectNotFoundException { 521e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT); 522e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 523e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 524e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 525e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return node.isChecked(); 526e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 527e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 528e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 529e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * Check if item pointed to by this object's selector is currently selected.<p/> 530e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * Take note that the {@link By} selector specified for this UiObjecy must be pointing 531e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * directly at the element you wish to query for this attribute as this UiObject may be 532e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * using {@link By} selectors that may be pointing at a parent element of the element 533e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * you're querying while still providing the desired functionality in terms of coordinates 534e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * for taps and swipes. 535e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if it is else false 536e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 537e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 538e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean isSelected() throws UiObjectNotFoundException { 539e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT); 540e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 541e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 542e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 543e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return node.isSelected(); 544e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 545e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 546e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 547e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * Check if item pointed to by this object's selector can be checked and unchecked. <p/> 548e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * Take note that the {@link By} selector specified for this UiObjecy must be pointing 549e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * directly at the element you wish to query for this attribute as this UiObject may be 550e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * using {@link By} selectors that may be pointing at a parent element of the element 551e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * you're querying while still providing the desired functionality in terms of coordinates 552e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * for taps and swipes. 553e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if it is else false 554e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 555e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 556e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean isCheckable() throws UiObjectNotFoundException { 557e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT); 558e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 559e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 560e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 561e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return node.isCheckable(); 562e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 563e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 564e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 565e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * Check if item pointed to by this object's selector with text is currently 566e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * not grayed out. <p/> 567e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * Take note that the {@link By} selector specified for this UiObjecy must be pointing 568e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * directly at the element you wish to query for this attribute as this UiObject may be 569e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * using {@link By} selectors that may be pointing at a parent element of the element 570e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * you're querying while still providing the desired functionality in terms of coordinates 571e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * for taps and swipes. 572e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if it is else false 573e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 574e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 575e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean isEnabled() throws UiObjectNotFoundException { 576e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT); 577e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 578e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 579e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 580e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return node.isEnabled(); 581e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 582e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 583e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 584e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * Check if item pointed to by this object's selector with text responds to 585e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * clicks <p/> 586e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * Take note that the {@link By} selector specified for this UiObjecy must be pointing 587e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * directly at the element you wish to query for this attribute as this UiObject may be 588e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * using {@link By} selectors that may be pointing at a parent element of the element 589e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * you're querying while still providing the desired functionality in terms of coordinates 590e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * for taps and swipes. 591e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if it is else false 592e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 593e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 594e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean isClickable() 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.isClickable(); 600e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 601e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 602e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 603e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * Check if item pointed to by this object's selector with text is currently 604e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * focused. Focused objects will receive key stroke events when key events 605e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * are fired 606e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if it is else false 607e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 608e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 609e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean isFocused() 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.isFocused(); 615e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 616e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 617e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 618e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * Check if item pointed to by this object's selector with text is capable of receiving 619e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * focus. <p/> 620e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * Take note that the {@link By} selector specified for this UiObjecy must be pointing 621e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * directly at the element you wish to query for this attribute as this UiObject may be 622e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * using {@link By} selectors that may be pointing at a parent element of the element 623e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * you're querying while still providing the desired functionality in terms of coordinates 624e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * for taps and swipes. 625e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if it is else false 626e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 627e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 628e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean isFocusable() throws UiObjectNotFoundException { 629e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT); 630e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 631e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 632e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 633e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return node.isFocusable(); 634e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 635e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 636e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 637e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * Check if item pointed to by this object's selector with text can be scrolled.<p/> 638e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * Take note that the {@link By} selector specified for this UiObjecy must be pointing 639e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * directly at the element you wish to query for this attribute as this UiObject may be 640e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * using {@link By} selectors that may be pointing at a parent element of the element 641e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * you're querying while still providing the desired functionality in terms of coordinates 642e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * for taps and swipes. 643e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if it is else false 644e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 645e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 646e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean isScrollable() throws UiObjectNotFoundException { 647e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT); 648e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 649e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 650e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 651e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return node.isScrollable(); 652e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 653e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 654e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 655e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * Check if item pointed to by this object's selector responds to long clicks.<p/> 656e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * Take note that the {@link By} selector specified for this UiObjecy must be pointing 657e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * directly at the element you wish to query for this attribute as this UiObject may be 658e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * using {@link By} selectors that may be pointing at a parent element of the element 659e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * you're querying while still providing the desired functionality in terms of coordinates 660e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * for taps and swipes. 661e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if it is else false 662e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 663e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 664e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean isLongClickable() throws UiObjectNotFoundException { 665e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT); 666e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 667e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 668e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 669e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return node.isLongClickable(); 670e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 671e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 672e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 673e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * This method retrieves the package name of the currently displayed content on the screen. 674e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * This can be helpful when verifying that the expected package is on the screen before 675e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * proceeding with further test operations. 676e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return String package name 677e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 678e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 679e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public String getPackageName() throws UiObjectNotFoundException { 680e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT); 681e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 682e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 683e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 684e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return safeStringReturn(node.getPackageName()); 685e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 686e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 687e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 688e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * Reports the absolute visible screen bounds of the object. If a portion of the UI element 689e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * is visible, only the bounds of the visible portion of the UI element are reported. This 690e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * becomes important when using bounds to calculate exact coordinates for tapping the element. 691e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return Rect 692e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 693e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 694e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public Rect getBounds() throws UiObjectNotFoundException { 695e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT); 696e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 697e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 698e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 699e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return getVisibleBounds(node); 700e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 701e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 702e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 703e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * This method will wait for a UI element to become visible on the display. It 704e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * can be used for situations where the content to be selected is not yet displayed 705e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * and the time it will be present is unknown. 706e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @param timeout 707e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if the UI element exists else false for timeout while waiting 708e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 709e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean waitForExists(long timeout) { 710e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(findAccessibilityNodeInfo(timeout) != null) { 711e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return true; 712e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 713e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return false; 714e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 715e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 716e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 717e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * Helper to wait for a specified object to no longer be detectable. This can be 718e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * useful when having to wait for a progress dialog to finish. 719e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @param timeout 720e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if gone before timeout else false for still present at timeout 721e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 722e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean waitUntilGone(long timeout) { 723e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu long startMills = SystemClock.uptimeMillis(); 724e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu long currentMills = 0; 725e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu while (currentMills <= timeout) { 726e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(findAccessibilityNodeInfo(0) == null) 727e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return true; 728e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu currentMills = SystemClock.uptimeMillis() - startMills; 729e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(timeout > 0) 730e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu SystemClock.sleep(WAIT_FOR_SELECTOR_POLL); 731e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 732e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return false; 733e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 734e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 735e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 736e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * This methods performs a {@link #waitForExists(long)} with zero timeout. This 737e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * basically returns immediately whether the UI element represented by this UiObject 738e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * exists or not. If you need to wait longer for this UI element, then see 739e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * {@link #waitForExists(long)}. 740e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if the UI element represented by this UiObject does exist 741e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 742e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean exists() { 743e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return waitForExists(0); 744e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 745e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 746e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu private String safeStringReturn(CharSequence cs) { 747e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(cs == null) 748e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return ""; 749e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return cs.toString(); 750e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 751e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu} 752