UiObject.java revision c344be11dbfd56e95d076f46b870108fdaa662f0
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 19c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtazimport android.graphics.Point; 20e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhuimport android.graphics.Rect; 21e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhuimport android.os.SystemClock; 22e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhuimport android.util.Log; 23e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhuimport android.view.KeyEvent; 24c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtazimport android.view.MotionEvent.PointerCoords; 256088c8f9e34e34a4958b1601ed7c1bb34c95da21Adam Momtazimport android.view.accessibility.AccessibilityEvent; 26e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhuimport android.view.accessibility.AccessibilityNodeInfo; 27e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 28e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu/** 2946d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * A UiObject is a representation of a UI element. It is not in any way directly bound to a 3046d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * UI element as an object reference. A UiObject holds information to help it 3146d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * locate a matching UI element at runtime based on the {@link UiSelector} properties specified in 3246d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * its constructor. Since a UiObject is a representative for a UI element, it can 3346d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * be reused for different views with matching UI elements. 34dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 35e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 36e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhupublic class UiObject { 37e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu private static final String LOG_TAG = UiObject.class.getSimpleName(); 38dbba713661688a285e701a006ce2d199296ac328Guang Zhu /** 39dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 40dbba713661688a285e701a006ce2d199296ac328Guang Zhu **/ 41e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu protected static final long WAIT_FOR_SELECTOR_TIMEOUT = 10 * 1000; 42dbba713661688a285e701a006ce2d199296ac328Guang Zhu /** 43dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 44dbba713661688a285e701a006ce2d199296ac328Guang Zhu **/ 45e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu protected static final long WAIT_FOR_SELECTOR_POLL = 1000; 46e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // set a default timeout to 5.5s, since ANR threshold is 5s 47dbba713661688a285e701a006ce2d199296ac328Guang Zhu /** 48dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 49dbba713661688a285e701a006ce2d199296ac328Guang Zhu **/ 50e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu protected static final long WAIT_FOR_WINDOW_TMEOUT = 5500; 51dbba713661688a285e701a006ce2d199296ac328Guang Zhu /** 52c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * @since API Level 16 53c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz **/ 54c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz protected static final int SWIPE_MARGIN_LIMIT = 5; 55c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz /** 56dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 17 57dbba713661688a285e701a006ce2d199296ac328Guang Zhu **/ 586088c8f9e34e34a4958b1601ed7c1bb34c95da21Adam Momtaz protected static final long WAIT_FOR_EVENT_TMEOUT = 3 * 1000; 59dbba713661688a285e701a006ce2d199296ac328Guang Zhu /** 60c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * @since API Level 18 61dbba713661688a285e701a006ce2d199296ac328Guang Zhu **/ 62c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz protected static final int FINGER_TOUCH_HALF_WIDTH = 20; 63e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 647f38ef08d07295967b905a61b2356ff6cdf31159Adam Momtaz private final UiSelector mSelector; 65ddc1008f06fd2a875037026490ce1f848a442572Guang Zhu private final UiAutomatorBridge mUiAutomationBridge; 66e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 67e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 683d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Constructs a UiObject to represent a specific UI element matched by the specified 693d50587be8ff021369c90554d814839335b445b0Adam Momtaz * {@link UiSelector} selector properties. 70e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @param selector 71dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 72e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 734ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz public UiObject(UiSelector selector) { 74e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu mUiAutomationBridge = UiDevice.getInstance().getAutomatorBridge(); 75e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu mSelector = selector; 76e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 77e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 78e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 793d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Debugging helper. A test can dump the properties of a selector as a string 803d50587be8ff021369c90554d814839335b445b0Adam Momtaz * to its logs if needed. <code>getSelector().toString();</code> 813d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 824ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz * @return {@link UiSelector} 83dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 84e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 854ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz public final UiSelector getSelector() { 86f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(); 874ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz return new UiSelector(mSelector); 88e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 89e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 90e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 913d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Retrieves the {@link QueryController} to translate a {@link UiSelector} selector 923d50587be8ff021369c90554d814839335b445b0Adam Momtaz * into an {@link AccessibilityNodeInfo}. 933d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 94e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return {@link QueryController} 95e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 96ddc1008f06fd2a875037026490ce1f848a442572Guang Zhu QueryController getQueryController() { 97e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return mUiAutomationBridge.getQueryController(); 98e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 99e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 100e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 1013d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Retrieves the {@link InteractionController} to perform finger actions such as tapping, 1023d50587be8ff021369c90554d814839335b445b0Adam Momtaz * swiping or entering text. 1033d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 104e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return {@link InteractionController} 105e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 106ddc1008f06fd2a875037026490ce1f848a442572Guang Zhu InteractionController getInteractionController() { 107e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return mUiAutomationBridge.getInteractionController(); 108e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 109e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 110e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 1113d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Creates a new UiObject representing a child UI element of the element currently represented 1123d50587be8ff021369c90554d814839335b445b0Adam Momtaz * by this UiObject. 1133d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 1143d50587be8ff021369c90554d814839335b445b0Adam Momtaz * @param selector for UI element to match 1153d50587be8ff021369c90554d814839335b445b0Adam Momtaz * @return a new UiObject representing the matched UI element 116dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 117e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 1184ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz public UiObject getChild(UiSelector selector) throws UiObjectNotFoundException { 119f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(selector); 1204ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz return new UiObject(getSelector().childSelector(selector)); 121e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 122e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 123e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 1243d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Creates a new UiObject representing a child UI element from the parent element currently 1253d50587be8ff021369c90554d814839335b445b0Adam Momtaz * represented by this object. Essentially this is starting the search from the parent 1263d50587be8ff021369c90554d814839335b445b0Adam Momtaz * element and can also be used to find sibling UI elements to the one currently represented 1273d50587be8ff021369c90554d814839335b445b0Adam Momtaz * by this UiObject. 1283d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 1293d50587be8ff021369c90554d814839335b445b0Adam Momtaz * @param selector for the UI element to match 1303d50587be8ff021369c90554d814839335b445b0Adam Momtaz * @return a new UiObject representing the matched UI element 131e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 132dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 133e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 1344ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz public UiObject getFromParent(UiSelector selector) throws UiObjectNotFoundException { 135f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(selector); 1364ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz return new UiObject(getSelector().fromParent(selector)); 137e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 138e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 139e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 1403d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Counts the child UI elements immediately under the UI element currently represented by 141e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * this UiObject. 1423d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 143e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return the count of child UI elements. 144e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 145dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 146e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 147e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public int getChildCount() throws UiObjectNotFoundException { 148f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(); 149e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT); 150e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 151e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 152e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 153e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return node.getChildCount(); 154e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 155e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 156e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 1573d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Uses the member UiSelector properties to find a matching UI element reported in 1583d50587be8ff021369c90554d814839335b445b0Adam Momtaz * the accessibility hierarchy. 1593d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 160e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @param timeout in milliseconds 161e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return AccessibilityNodeInfo if found else null 162dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 163e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 164e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu protected AccessibilityNodeInfo findAccessibilityNodeInfo(long timeout) { 165e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo node = null; 166e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(UiDevice.getInstance().isInWatcherContext()) { 167e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // we will NOT run watchers or do any sort of polling if the 168e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // reason we're here is because of a watcher is executing. Watchers 169e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // will not have other watchers run for them so they should not block 170e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // while they poll for items to become present. We disable polling for them. 171e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu node = getQueryController().findAccessibilityNodeInfo(getSelector()); 172e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } else { 173e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu long startMills = SystemClock.uptimeMillis(); 174e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu long currentMills = 0; 175e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu while (currentMills <= timeout) { 176e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu node = getQueryController().findAccessibilityNodeInfo(getSelector()); 177e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if (node != null) { 178e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu break; 179e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } else { 180e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu UiDevice.getInstance().runWatchers(); 181e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 182e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu currentMills = SystemClock.uptimeMillis() - startMills; 183e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(timeout > 0) { 184e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu SystemClock.sleep(WAIT_FOR_SELECTOR_POLL); 185e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 186e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 187e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 188e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return node; 189e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 190e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 191e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 1923d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Perform the action on the UI element that is represented by this UiObject. Also see 1931893caed0ad4e73b0676f206282d490c2d345316Thanh Le * {@link UiScrollable#scrollToBeginning(int)}, {@link UiScrollable#scrollToEnd(int)}, 1941893caed0ad4e73b0676f206282d490c2d345316Thanh Le * {@link UiScrollable#scrollBackward()}, {@link UiScrollable#scrollForward()}. 1953d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 196467cca7d25dbbf13c14cfd8c2ad38ab8eaf56bdaAdam Momtaz * @param steps indicates the number of injected move steps into the system. Steps are 197467cca7d25dbbf13c14cfd8c2ad38ab8eaf56bdaAdam Momtaz * injected about 5ms apart. So a 100 steps may take about 1/2 second to complete. 1983d50587be8ff021369c90554d814839335b445b0Adam Momtaz * @return true of successful 199e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 200dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 201e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 202e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean swipeUp(int steps) throws UiObjectNotFoundException { 203f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(steps); 2043d50587be8ff021369c90554d814839335b445b0Adam Momtaz Rect rect = getVisibleBounds(); 205e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(rect.height() <= SWIPE_MARGIN_LIMIT * 2) 206e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return false; // too small to swipe 207e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return getInteractionController().swipe(rect.centerX(), 208e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu rect.bottom - SWIPE_MARGIN_LIMIT, rect.centerX(), rect.top + SWIPE_MARGIN_LIMIT, 209e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu steps); 210e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 211e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 212e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 213e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * Perform the action on the UI element that is represented by this object, Also see 2141893caed0ad4e73b0676f206282d490c2d345316Thanh Le * {@link UiScrollable#scrollToBeginning(int)}, {@link UiScrollable#scrollToEnd(int)}, 2151893caed0ad4e73b0676f206282d490c2d345316Thanh Le * {@link UiScrollable#scrollBackward()}, {@link UiScrollable#scrollForward()}. This method will 2161893caed0ad4e73b0676f206282d490c2d345316Thanh Le * perform the swipe gesture over any surface. The targeted UI element does not need to have 2171893caed0ad4e73b0676f206282d490c2d345316Thanh Le * the attribute <code>scrollable</code> set to <code>true</code> for this operation to be 2181893caed0ad4e73b0676f206282d490c2d345316Thanh Le * performed. 2193d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 2203d50587be8ff021369c90554d814839335b445b0Adam Momtaz * @param steps indicates the number of injected move steps into the system. Steps are 221467cca7d25dbbf13c14cfd8c2ad38ab8eaf56bdaAdam Momtaz * injected about 5ms apart. So a 100 steps may take about 1/2 second to complete. 2223d50587be8ff021369c90554d814839335b445b0Adam Momtaz * @return true if successful 223e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 224dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 225e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 226e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean swipeDown(int steps) throws UiObjectNotFoundException { 227f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(steps); 2283d50587be8ff021369c90554d814839335b445b0Adam Momtaz Rect rect = getVisibleBounds(); 229e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(rect.height() <= SWIPE_MARGIN_LIMIT * 2) 230e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return false; // too small to swipe 231e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return getInteractionController().swipe(rect.centerX(), 232e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu rect.top + SWIPE_MARGIN_LIMIT, rect.centerX(), 233e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu rect.bottom - SWIPE_MARGIN_LIMIT, steps); 234e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 235e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 236e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 237e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * Perform the action on the UI element that is represented by this object. Also see 2381893caed0ad4e73b0676f206282d490c2d345316Thanh Le * {@link UiScrollable#scrollToBeginning(int)}, {@link UiScrollable#scrollToEnd(int)}, 2391893caed0ad4e73b0676f206282d490c2d345316Thanh Le * {@link UiScrollable#scrollBackward()}, {@link UiScrollable#scrollForward()}. This method will 2401893caed0ad4e73b0676f206282d490c2d345316Thanh Le * perform the swipe gesture over any surface. The targeted UI element does not need to have the 2411893caed0ad4e73b0676f206282d490c2d345316Thanh Le * attribute <code>scrollable</code> set to <code>true</code> for this operation to be 2421893caed0ad4e73b0676f206282d490c2d345316Thanh Le * performed. 2433d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 2443d50587be8ff021369c90554d814839335b445b0Adam Momtaz * @param steps indicates the number of injected move steps into the system. Steps are 245467cca7d25dbbf13c14cfd8c2ad38ab8eaf56bdaAdam Momtaz * injected about 5ms apart. So a 100 steps may take about 1/2 second to complete. 2463d50587be8ff021369c90554d814839335b445b0Adam Momtaz * @return true if successful 247e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 248dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 249e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 250e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean swipeLeft(int steps) throws UiObjectNotFoundException { 251f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(steps); 2523d50587be8ff021369c90554d814839335b445b0Adam Momtaz Rect rect = getVisibleBounds(); 253e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(rect.width() <= SWIPE_MARGIN_LIMIT * 2) 254e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return false; // too small to swipe 255e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return getInteractionController().swipe(rect.right - SWIPE_MARGIN_LIMIT, 256e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu rect.centerY(), rect.left + SWIPE_MARGIN_LIMIT, rect.centerY(), steps); 257e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 258e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 259e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 260e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * Perform the action on the UI element that is represented by this object. Also see 2611893caed0ad4e73b0676f206282d490c2d345316Thanh Le * {@link UiScrollable#scrollToBeginning(int)}, {@link UiScrollable#scrollToEnd(int)}, 2621893caed0ad4e73b0676f206282d490c2d345316Thanh Le * {@link UiScrollable#scrollBackward()}, {@link UiScrollable#scrollForward()}. This method will 2631893caed0ad4e73b0676f206282d490c2d345316Thanh Le * perform the swipe gesture over any surface. The targeted UI element does not need to have the 2641893caed0ad4e73b0676f206282d490c2d345316Thanh Le * attribute <code>scrollable</code> set to <code>true</code> for this operation to be 2651893caed0ad4e73b0676f206282d490c2d345316Thanh Le * performed. 2663d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 2673d50587be8ff021369c90554d814839335b445b0Adam Momtaz * @param steps indicates the number of injected move steps into the system. Steps are 268467cca7d25dbbf13c14cfd8c2ad38ab8eaf56bdaAdam Momtaz * injected about 5ms apart. So a 100 steps may take about 1/2 second to complete. 2693d50587be8ff021369c90554d814839335b445b0Adam Momtaz * @return true if successful 270e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 271dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 272e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 273e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean swipeRight(int steps) throws UiObjectNotFoundException { 274f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(steps); 2753d50587be8ff021369c90554d814839335b445b0Adam Momtaz Rect rect = getVisibleBounds(); 276e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(rect.width() <= SWIPE_MARGIN_LIMIT * 2) 277e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return false; // too small to swipe 278e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return getInteractionController().swipe(rect.left + SWIPE_MARGIN_LIMIT, 279e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu rect.centerY(), rect.right - SWIPE_MARGIN_LIMIT, rect.centerY(), steps); 280e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 281e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 282e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 2833d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Finds the visible bounds of a partially visible UI element 2843d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 285e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @param node 2867f38ef08d07295967b905a61b2356ff6cdf31159Adam Momtaz * @return null if node is null, else a Rect containing visible bounds 287e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 288e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu private Rect getVisibleBounds(AccessibilityNodeInfo node) { 289e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if (node == null) { 290e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return null; 291e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 292e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 293e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // targeted node's bounds 2947f38ef08d07295967b905a61b2356ff6cdf31159Adam Momtaz Rect nodeRect = AccessibilityNodeInfoHelper.getVisibleBoundsInScreen(node); 295e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 296e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // is the targeted node within a scrollable container? 297e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo scrollableParentNode = getScrollableParent(node); 298e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(scrollableParentNode == null) { 299e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // nothing to adjust for so return the node's Rect as is 300e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return nodeRect; 301e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 302e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 303e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // Scrollable parent's visible bounds 3047f38ef08d07295967b905a61b2356ff6cdf31159Adam Momtaz Rect parentRect = AccessibilityNodeInfoHelper 3057f38ef08d07295967b905a61b2356ff6cdf31159Adam Momtaz .getVisibleBoundsInScreen(scrollableParentNode); 306e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // adjust for partial clipping of targeted by parent node if required 307e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu nodeRect.intersect(parentRect); 308e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return nodeRect; 309e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 310e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 311e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 3127f38ef08d07295967b905a61b2356ff6cdf31159Adam Momtaz * Walk the hierarchy up to find a scrollable parent. A scrollable parent 3137f38ef08d07295967b905a61b2356ff6cdf31159Adam Momtaz * indicates that this node may be in a content where it is partially 3147f38ef08d07295967b905a61b2356ff6cdf31159Adam Momtaz * visible due to scrolling. its clickable center maybe invisible and 3157f38ef08d07295967b905a61b2356ff6cdf31159Adam Momtaz * adjustments should be made to the click coordinates. 3163d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 317e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @param node 3181893caed0ad4e73b0676f206282d490c2d345316Thanh Le * @return The accessibility node info. 319e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 320e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu private AccessibilityNodeInfo getScrollableParent(AccessibilityNodeInfo node) { 321e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo parent = node; 322e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu while(parent != null) { 323e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu parent = parent.getParent(); 324e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if (parent != null && parent.isScrollable()) { 325e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return parent; 326e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 327e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 328e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return null; 329e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 330e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 331e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 3323d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Performs a click at the center of the visible bounds of the UI element represented 33346d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * by this UiObject. 3343d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 335e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true id successful else false 336e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 337dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 338e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 339e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean click() throws UiObjectNotFoundException { 340f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(); 341e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT); 342e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 343e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 344e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 345e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu Rect rect = getVisibleBounds(node); 34608f500a92397522c48bcdad58d37ec1be95956d1Adam Momtaz return getInteractionController().clickAndWaitForEvents(rect.centerX(), rect.centerY(), 347c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz WAIT_FOR_EVENT_TMEOUT, false, AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED | 34808f500a92397522c48bcdad58d37ec1be95956d1Adam Momtaz AccessibilityEvent.TYPE_VIEW_SELECTED); 349e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 350e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 351e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 3523d50587be8ff021369c90554d814839335b445b0Adam Momtaz * See {@link #clickAndWaitForNewWindow(long)} 353a46ac3504426564954292b13380120e8cc6b1527Adam Momtaz * This method is intended to reliably wait for window transitions that would typically take 354a46ac3504426564954292b13380120e8cc6b1527Adam Momtaz * longer than the usual default timeouts. 3553d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 3563d50587be8ff021369c90554d814839335b445b0Adam Momtaz * @return true if the event was triggered, else false 3573d50587be8ff021369c90554d814839335b445b0Adam Momtaz * @throws UiObjectNotFoundException 358dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 3593d50587be8ff021369c90554d814839335b445b0Adam Momtaz */ 360e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean clickAndWaitForNewWindow() throws UiObjectNotFoundException { 361f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(); 362e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return clickAndWaitForNewWindow(WAIT_FOR_WINDOW_TMEOUT); 363e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 364e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 365e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 36646d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * Performs a click at the center of the visible bounds of the UI element represented 36746d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * by this UiObject and waits for window transitions. 36846d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * 3693d50587be8ff021369c90554d814839335b445b0Adam Momtaz * This method differ from {@link UiObject#click()} only in that this method waits for a 37046d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * a new window transition as a result of the click. Some examples of a window transition: 371e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * <li>launching a new activity</li> 372e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * <li>bringing up a pop-up menu</li> 373e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * <li>bringing up a dialog</li> 374e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * 3753d50587be8ff021369c90554d814839335b445b0Adam Momtaz * @param timeout timeout before giving up on waiting for a new window 376e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if the event was triggered, else false 377e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 378dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 379e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 380e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean clickAndWaitForNewWindow(long timeout) throws UiObjectNotFoundException { 381f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(timeout); 382e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT); 383e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 384e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 385e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 386e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu Rect rect = getVisibleBounds(node); 3874ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz return getInteractionController().clickAndWaitForNewWindow( 388e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu rect.centerX(), rect.centerY(), timeout); 389e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 390e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 391e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 3923d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Clicks the top and left corner of the UI element 3933d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 394e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true on success 3951893caed0ad4e73b0676f206282d490c2d345316Thanh Le * @throws UiObjectNotFoundException 396dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 397e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 398e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean clickTopLeft() throws UiObjectNotFoundException { 399f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(); 400e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT); 401e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 402e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 403e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 404e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu Rect rect = getVisibleBounds(node); 4054ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz return getInteractionController().click(rect.left + 5, rect.top + 5); 406e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 407e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 408e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 4093d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Long clicks bottom and right corner of the UI element 4103d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 411e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if operation was successful 412e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 413dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 414e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 415e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean longClickBottomRight() throws UiObjectNotFoundException { 416f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(); 417e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT); 418e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 419e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 420e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 421e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu Rect rect = getVisibleBounds(node); 422e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return getInteractionController().longTap(rect.right - 5, rect.bottom - 5); 423e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 424e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 425e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 4263d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Clicks the bottom and right corner of the UI element 4273d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 428e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true on success 4291893caed0ad4e73b0676f206282d490c2d345316Thanh Le * @throws UiObjectNotFoundException 430dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 431e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 432e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean clickBottomRight() throws UiObjectNotFoundException { 433f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(); 434e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT); 435e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 436e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 437e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 438e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu Rect rect = getVisibleBounds(node); 4394ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz return getInteractionController().click(rect.right - 5, rect.bottom - 5); 440e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 441e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 442e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 4433d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Long clicks the center of the visible bounds of the UI element 4443d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 445e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if operation was successful 446e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 447dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 448e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 449e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean longClick() throws UiObjectNotFoundException { 450f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(); 451e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT); 452e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 453e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 454e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 455e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu Rect rect = getVisibleBounds(node); 456e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return getInteractionController().longTap(rect.centerX(), rect.centerY()); 457e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 458e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 459e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 4603d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Long clicks on the top and left corner of the UI element 4613d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 462e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if operation was successful 463e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 464dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 465e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 466e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean longClickTopLeft() throws UiObjectNotFoundException { 467f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(); 468e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT); 469e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 470e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 471e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 472e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu Rect rect = getVisibleBounds(node); 473e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return getInteractionController().longTap(rect.left + 5, rect.top + 5); 474e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 475e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 476e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 4773d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Reads the <code>text</code> property of the UI element 4783d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 479e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return text value of the current node represented by this UiObject 480e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException if no match could be found 481dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 482e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 483e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public String getText() throws UiObjectNotFoundException { 484f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(); 485e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT); 486e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 487e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 488e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 489e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu String retVal = safeStringReturn(node.getText()); 490e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu Log.d(LOG_TAG, String.format("getText() = %s", retVal)); 491e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return retVal; 492e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 493e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 494e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 4953d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Reads the <code>content_desc</code> property of the UI element 4963d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 497e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return value of node attribute "content_desc" 498e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 499dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 500e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 501e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public String getContentDescription() throws UiObjectNotFoundException { 502f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(); 503e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT); 504e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 505e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 506e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 507e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return safeStringReturn(node.getContentDescription()); 508e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 509e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 510e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 51146d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * Sets the text in an editable field, after clearing the field's content. 51246d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * 51346d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * The {@link UiSelector} selector of this object must reference a UI element that is editable. 51446d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * 51546d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * When you call this method, the method first simulates a {@link #click()} on 51646d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * editable field to set focus. The method then clears the field's contents 51746d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * and injects your specified text into the field. 5183d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 51946d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * If you want to capture the original contents of the field, call {@link #getText()} first. 52046d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * You can then modify the text and use this method to update the field. 52146d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * 52246d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * @param text string to set 523e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if operation is successful 524e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 525dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 526e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 527e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean setText(String text) throws UiObjectNotFoundException { 528f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(text); 529e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu clearTextField(); 530e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return getInteractionController().sendText(text); 531e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 532e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 533e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 53446d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * Clears the existing text contents in an editable field. 53546d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * 53646d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * The {@link UiSelector} of this object must reference a UI element that is editable. 53746d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * 53846d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * When you call this method, the method first sets focus at the start edge of the field. 53946d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * The method then simulates a long-press to select the existing text, and deletes the 54046d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * selected text. 54146d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * 54246d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * If a "Select-All" option is displayed, the method will automatically attempt to use it 54346d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * to ensure full text selection. 54446d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * 54546d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * Note that it is possible that not all the text in the field is selected; for example, 54646d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * if the text contains separators such as spaces, slashes, at symbol etc. 54746d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * Also, not all editable fields support the long-press functionality. 54846d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * 549e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 550dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 551e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 552e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public void clearTextField() throws UiObjectNotFoundException { 553f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(); 554e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // long click left + center 555e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT); 556e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 557e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 558e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 559e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu Rect rect = getVisibleBounds(node); 560e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu getInteractionController().longTap(rect.left + 20, rect.centerY()); 561e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // check if the edit menu is open 5624ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz UiObject selectAll = new UiObject(new UiSelector().descriptionContains("Select all")); 563e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(selectAll.waitForExists(50)) 564e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu selectAll.click(); 565e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // wait for the selection 566e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu SystemClock.sleep(250); 567e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // delete it 568e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu getInteractionController().sendKey(KeyEvent.KEYCODE_DEL, 0); 569e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 570e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 571e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 5723d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Check if the UI element's <code>checked</code> property is currently true 5733d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 574e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if it is else false 575dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 576e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 577e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean isChecked() throws UiObjectNotFoundException { 578f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(); 579e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT); 580e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 581e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 582e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 583e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return node.isChecked(); 584e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 585e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 586e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 5873d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Check if the UI element's <code>selected</code> property is currently true 5883d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 589e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if it is else false 590e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 591dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 592e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 593e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean isSelected() throws UiObjectNotFoundException { 594f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(); 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.isSelected(); 600e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 601e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 602e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 6033d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Check if the UI element's <code>checkable</code> property is currently true 6043d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 605e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if it is else false 606e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 607dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 608e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 609e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean isCheckable() throws UiObjectNotFoundException { 610f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(); 611e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT); 612e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 613e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 614e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 615e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return node.isCheckable(); 616e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 617e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 618e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 6193d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Check if the UI element's <code>enabled</code> property is currently true 6203d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 621e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if it is else false 622e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 623dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 624e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 625e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean isEnabled() throws UiObjectNotFoundException { 626f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(); 627e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT); 628e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 629e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 630e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 631e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return node.isEnabled(); 632e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 633e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 634e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 6353d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Check if the UI element's <code>clickable</code> property is currently true 6363d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 637e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if it is else false 638e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 639dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 640e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 641e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean isClickable() throws UiObjectNotFoundException { 642f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(); 643e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT); 644e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 645e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 646e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 647e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return node.isClickable(); 648e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 649e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 650e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 6513d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Check if the UI element's <code>focused</code> property is currently true 6523d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 653e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if it is else false 654e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 655dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 656e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 657e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean isFocused() throws UiObjectNotFoundException { 658f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(); 659e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT); 660e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 661e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 662e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 663e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return node.isFocused(); 664e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 665e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 666e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 6673d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Check if the UI element's <code>focusable</code> property is currently true 6683d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 669e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if it is else false 670e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 671dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 672e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 673e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean isFocusable() throws UiObjectNotFoundException { 674f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(); 675e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT); 676e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 677e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 678e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 679e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return node.isFocusable(); 680e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 681e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 682e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 6833d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Check if the UI element's <code>scrollable</code> property is currently true 6843d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 685e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if it is else false 686e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 687dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 688e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 689e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean isScrollable() throws UiObjectNotFoundException { 690f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(); 691e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT); 692e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 693e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 694e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 695e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return node.isScrollable(); 696e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 697e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 698e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 6993d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Check if the UI element's <code>long-clickable</code> property is currently true 7003d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 701e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if it is else false 702e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 703dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 704e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 705e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean isLongClickable() throws UiObjectNotFoundException { 706f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(); 707e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT); 708e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 709e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 710e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 711e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return node.isLongClickable(); 712e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 713e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 714e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 7153d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Reads the UI element's <code>package</code> property 7163d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 7173d50587be8ff021369c90554d814839335b445b0Adam Momtaz * @return true if it is else false 718e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 719dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 720e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 721e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public String getPackageName() throws UiObjectNotFoundException { 722f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(); 723e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT); 724e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 725e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 726e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 727e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return safeStringReturn(node.getPackageName()); 728e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 729e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 730e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 73146d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * Returns the visible bounds of the UI element. 73246d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * 73346d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * If a portion of the UI element is visible, only the bounds of the visible portion are 73446d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * reported. 7353d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 736e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return Rect 737e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 7381893caed0ad4e73b0676f206282d490c2d345316Thanh Le * @see {@link #getBounds()} 73979693ede92636fe6f3a6ec4dc049a438fd9504ffGuang Zhu * @since API Level 17 740e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 7413d50587be8ff021369c90554d814839335b445b0Adam Momtaz public Rect getVisibleBounds() throws UiObjectNotFoundException { 742f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(); 743e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT); 744e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 745e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 746e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 747e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return getVisibleBounds(node); 748e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 749e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 750e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 75146d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * Returns the UI element's <code>bounds</code> property. See {@link #getVisibleBounds()} 7523d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 7533d50587be8ff021369c90554d814839335b445b0Adam Momtaz * @return Rect 7543d50587be8ff021369c90554d814839335b445b0Adam Momtaz * @throws UiObjectNotFoundException 755dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 7563d50587be8ff021369c90554d814839335b445b0Adam Momtaz */ 7573d50587be8ff021369c90554d814839335b445b0Adam Momtaz public Rect getBounds() throws UiObjectNotFoundException { 758f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(); 7593d50587be8ff021369c90554d814839335b445b0Adam Momtaz AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT); 7603d50587be8ff021369c90554d814839335b445b0Adam Momtaz if(node == null) { 7613d50587be8ff021369c90554d814839335b445b0Adam Momtaz throw new UiObjectNotFoundException(getSelector().toString()); 7623d50587be8ff021369c90554d814839335b445b0Adam Momtaz } 7633d50587be8ff021369c90554d814839335b445b0Adam Momtaz Rect nodeRect = new Rect(); 7643d50587be8ff021369c90554d814839335b445b0Adam Momtaz node.getBoundsInScreen(nodeRect); 7653d50587be8ff021369c90554d814839335b445b0Adam Momtaz 7663d50587be8ff021369c90554d814839335b445b0Adam Momtaz return nodeRect; 7673d50587be8ff021369c90554d814839335b445b0Adam Momtaz } 7683d50587be8ff021369c90554d814839335b445b0Adam Momtaz 7693d50587be8ff021369c90554d814839335b445b0Adam Momtaz /** 77046d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * Waits a specified length of time for a UI element to become visible. 77146d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * 77246d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * This method waits until the UI element becomes visible on the display, or 77346d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * until the timeout has elapsed. You can use this method in situations where 77446d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * the content that you want to select is not immediately displayed. 7753d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 77646d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * @param timeout the amount of time to wait (in milliseconds) 77746d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * @return true if the UI element is displayed, else false if timeout elapsed while waiting 778dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 779e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 780e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean waitForExists(long timeout) { 781f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(timeout); 782e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(findAccessibilityNodeInfo(timeout) != null) { 783e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return true; 784e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 785e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return false; 786e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 787e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 788e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 78946d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * Waits a specified length of time for a UI element to become undetectable. 7903d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 79146d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * This method waits until a UI element is no longer matchable, or until the 79246d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * timeout has elapsed. 79346d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * 79446d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * A UI element becomes undetectable when the {@link UiSelector} of the object is 79546d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * unable to find a match because the element has either changed its state or is no 79646d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * longer displayed. 79746d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * 79846d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * You can use this method when attempting to wait for some long operation 79946d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * to compete, such as downloading a large file or connecting to a remote server. 80046d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * 80146d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * @param timeout time to wait (in milliseconds) 80246d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * @return true if the element is gone before timeout elapsed, else false if timeout elapsed 80346d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * but a matching element is still found. 804dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 805e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 806e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean waitUntilGone(long timeout) { 807f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(timeout); 808e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu long startMills = SystemClock.uptimeMillis(); 809e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu long currentMills = 0; 810e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu while (currentMills <= timeout) { 811e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(findAccessibilityNodeInfo(0) == null) 812e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return true; 813e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu currentMills = SystemClock.uptimeMillis() - startMills; 814e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(timeout > 0) 815e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu SystemClock.sleep(WAIT_FOR_SELECTOR_POLL); 816e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 817e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return false; 818e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 819e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 820e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 82146d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * Check if UI element exists. 82246d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * 823e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * This methods performs a {@link #waitForExists(long)} with zero timeout. This 824e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * basically returns immediately whether the UI element represented by this UiObject 825e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * exists or not. If you need to wait longer for this UI element, then see 826e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * {@link #waitForExists(long)}. 8273d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 828e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if the UI element represented by this UiObject does exist 829dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 830e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 831e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean exists() { 832f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(); 833e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return waitForExists(0); 834e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 835e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 836e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu private String safeStringReturn(CharSequence cs) { 837e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(cs == null) 838e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return ""; 839e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return cs.toString(); 840e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 841c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz 842c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz /** 843c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * PinchOut generates a 2 pointer gesture where each pointer is moving from the center out 844c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * away from each other diagonally towards the edges of the current UI element represented by 845c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * this UiObject. 846c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * @param percent of the object's diagonal length to use for the pinch 847c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * @param steps indicates the number of injected move steps into the system. Steps are 848c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * injected about 5ms apart. So a 100 steps may take about 1/2 second to complete. 849c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * @throws UiObjectNotFoundException 850c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * @since API Level 18 851c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz */ 852c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz public void pinchOut(int percent, int steps) throws UiObjectNotFoundException { 853c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz // make value between 1 and 100 854c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz percent = (percent < 0) ? 1 : (percent > 100) ? 100 : percent; 855c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz float percentage = percent / 100f; 856c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz 857c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT); 858c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz if (node == null) { 859c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz throw new UiObjectNotFoundException(getSelector().toString()); 860c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz } 861c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz 862c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz Rect rect = getVisibleBounds(node); 863c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz if (rect.width() <= FINGER_TOUCH_HALF_WIDTH * 2) 864c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz throw new IllegalStateException("Object width is too small for operation"); 865c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz 866c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz // start from the same point at the center of the control 867c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz Point startPoint1 = new Point(rect.centerX() - FINGER_TOUCH_HALF_WIDTH, rect.centerY()); 868c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz Point startPoint2 = new Point(rect.centerX() + FINGER_TOUCH_HALF_WIDTH, rect.centerY()); 869c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz 870c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz // End at the top-left and bottom-right corners of the control 871c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz Point endPoint1 = new Point(rect.centerX() - (int)((rect.width()/2) * percentage), 872c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz rect.centerY()); 873c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz Point endPoint2 = new Point(rect.centerX() + (int)((rect.width()/2) * percentage), 874c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz rect.centerY()); 875c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz 876c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz twoPointerGesture(startPoint1, startPoint2, endPoint1, endPoint2, steps); 877c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz } 878c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz 879c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz /** 880c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * PinchIn generates a 2 pointer gesture where each pointer is moving towards the other 881c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * diagonally from the edges of the current UI element represented by this UiObject, until the 882c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * center. 883c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * @param percent of the object's diagonal length to use for the pinch 884c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * @param steps indicates the number of injected move steps into the system. Steps are 885c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * injected about 5ms apart. So a 100 steps may take about 1/2 second to complete. 886c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * @throws UiObjectNotFoundException 887c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * @since API Level 18 888c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz */ 889c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz public void pinchIn(int percent, int steps) throws UiObjectNotFoundException { 890c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz // make value between 1 and 100 891c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz percent = (percent < 0) ? 0 : (percent > 100) ? 100 : percent; 892c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz float percentage = percent / 100f; 893c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz 894c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT); 895c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz if (node == null) { 896c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz throw new UiObjectNotFoundException(getSelector().toString()); 897c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz } 898c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz 899c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz Rect rect = getVisibleBounds(node); 900c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz if (rect.width() <= FINGER_TOUCH_HALF_WIDTH * 2) 901c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz throw new IllegalStateException("Object width is too small for operation"); 902c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz 903c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz Point startPoint1 = new Point(rect.centerX() - (int)((rect.width()/2) * percentage), 904c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz rect.centerY()); 905c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz Point startPoint2 = new Point(rect.centerX() + (int)((rect.width()/2) * percentage), 906c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz rect.centerY()); 907c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz 908c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz Point endPoint1 = new Point(rect.centerX() - FINGER_TOUCH_HALF_WIDTH, rect.centerY()); 909c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz Point endPoint2 = new Point(rect.centerX() + FINGER_TOUCH_HALF_WIDTH, rect.centerY()); 910c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz 911c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz twoPointerGesture(startPoint1, startPoint2, endPoint1, endPoint2, steps); 912c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz } 913c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz 914c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz /** 915c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * Generates a 2 pointer gesture from an arbitrary starting and ending points. 916c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * 917c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * @param startPoint1 start point of pointer 1 918c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * @param startPoint2 start point of pointer 2 919c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * @param endPoint1 end point of pointer 1 920c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * @param endPoint2 end point of pointer 2 921c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * @param steps indicates the number of injected move steps into the system. Steps are 922c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * injected about 5ms apart. So a 100 steps may take about 1/2 second to complete. 923c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * @since API Level 18 924c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz */ 925c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz public void twoPointerGesture(Point startPoint1, Point startPoint2, Point endPoint1, 926c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz Point endPoint2, int steps) { 927c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz 928c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz // avoid a divide by zero 929c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz if(steps == 0) 930c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz steps = 1; 931c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz 932c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz final float stepX1 = (endPoint1.x - startPoint1.x) / steps; 933c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz final float stepY1 = (endPoint1.y - startPoint1.y) / steps; 934c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz final float stepX2 = (endPoint2.x - startPoint2.x) / steps; 935c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz final float stepY2 = (endPoint2.y - startPoint2.y) / steps; 936c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz 937c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz int eventX1, eventY1, eventX2, eventY2; 938c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz eventX1 = startPoint1.x; 939c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz eventY1 = startPoint1.y; 940c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz eventX2 = startPoint2.x; 941c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz eventY2 = startPoint2.y; 942c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz 943c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz // allocate for steps plus first down and last up 944c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz PointerCoords[] points1 = new PointerCoords[steps + 2]; 945c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz PointerCoords[] points2 = new PointerCoords[steps + 2]; 946c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz 947c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz // Include the first and last touch downs in the arrays of steps 948c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz for (int i = 0; i < steps + 1; i++) { 949c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz PointerCoords p1 = new PointerCoords(); 950c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz p1.x = eventX1; 951c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz p1.y = eventY1; 952c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz p1.pressure = 1; 953c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz p1.size = 1; 954c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz points1[i] = p1; 955c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz 956c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz PointerCoords p2 = new PointerCoords(); 957c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz p2.x = eventX2; 958c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz p2.y = eventY2; 959c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz p2.pressure = 1; 960c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz p2.size = 1; 961c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz points2[i] = p2; 962c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz 963c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz eventX1 += stepX1; 964c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz eventY1 += stepY1; 965c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz eventX2 += stepX2; 966c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz eventY2 += stepY2; 967c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz } 968c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz 969c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz // ending pointers coordinates 970c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz PointerCoords p1 = new PointerCoords(); 971c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz p1.x = endPoint1.x; 972c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz p1.y = endPoint1.y; 973c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz p1.pressure = 1; 974c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz p1.size = 1; 975c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz points1[steps + 1] = p1; 976c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz 977c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz PointerCoords p2 = new PointerCoords(); 978c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz p2.x = endPoint2.x; 979c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz p2.y = endPoint2.y; 980c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz p2.pressure = 1; 981c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz p2.size = 1; 982c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz points2[steps + 1] = p2; 983c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz 984c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz multiPointerGesture(points1, points2); 985c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz } 986c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz 987c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz /** 988c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * Performs a multi-touch gesture 989c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * 990c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * Takes a series of touch coordinates for at least 2 pointers. Each pointer must have 991c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * all of its touch steps defined in an array of {@link PointerCoords}. By having the ability 992c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * to specify the touch points along the path of a pointer, the caller is able to specify 993c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * complex gestures like circles, irregular shapes etc, where each pointer may take a 994c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * different path. 995c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * 996c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * To create a single point on a pointer's touch path 997c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * <code> 998c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * PointerCoords p = new PointerCoords(); 999c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * p.x = stepX; 1000c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * p.y = stepY; 1001c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * p.pressure = 1; 1002c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * p.size = 1; 1003c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * </code> 1004c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * @param touches each array of {@link PointerCoords} constitute a single pointer's touch path. 1005c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * Multiple {@link PointerCoords} arrays constitute multiple pointers, each with its own 1006c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * path. Each {@link PointerCoords} in an array constitute a point on a pointer's path. 1007c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * @since API Level 18 1008c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz */ 1009c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz public void multiPointerGesture(PointerCoords[] ...touches) { 1010c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz getInteractionController().generateMultiPointerGesture(touches); 1011c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz } 1012c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz}