UiObject.java revision 1dc7d12406947faaee8454c6efb2a0631f5da573
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; 25e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhuimport android.view.accessibility.AccessibilityNodeInfo; 26e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 27e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu/** 2846d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * A UiObject is a representation of a UI element. It is not in any way directly bound to a 2946d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * UI element as an object reference. A UiObject holds information to help it 3046d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * locate a matching UI element at runtime based on the {@link UiSelector} properties specified in 3146d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * its constructor. Since a UiObject is a representative for a UI element, it can 3246d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * be reused for different views with matching UI elements. 33dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 34e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 35e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhupublic class UiObject { 36e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu private static final String LOG_TAG = UiObject.class.getSimpleName(); 37dbba713661688a285e701a006ce2d199296ac328Guang Zhu /** 38dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 39dbba713661688a285e701a006ce2d199296ac328Guang Zhu **/ 40e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu protected static final long WAIT_FOR_SELECTOR_TIMEOUT = 10 * 1000; 41dbba713661688a285e701a006ce2d199296ac328Guang Zhu /** 42dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 43dbba713661688a285e701a006ce2d199296ac328Guang Zhu **/ 44e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu protected static final long WAIT_FOR_SELECTOR_POLL = 1000; 45e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // set a default timeout to 5.5s, since ANR threshold is 5s 46dbba713661688a285e701a006ce2d199296ac328Guang Zhu /** 47dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 48dbba713661688a285e701a006ce2d199296ac328Guang Zhu **/ 49e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu protected static final long WAIT_FOR_WINDOW_TMEOUT = 5500; 50dbba713661688a285e701a006ce2d199296ac328Guang Zhu /** 51c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * @since API Level 16 52c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz **/ 53c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz protected static final int SWIPE_MARGIN_LIMIT = 5; 54c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz /** 55dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 17 56dbba713661688a285e701a006ce2d199296ac328Guang Zhu **/ 576088c8f9e34e34a4958b1601ed7c1bb34c95da21Adam Momtaz protected static final long WAIT_FOR_EVENT_TMEOUT = 3 * 1000; 58dbba713661688a285e701a006ce2d199296ac328Guang Zhu /** 59c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * @since API Level 18 60dbba713661688a285e701a006ce2d199296ac328Guang Zhu **/ 61c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz protected static final int FINGER_TOUCH_HALF_WIDTH = 20; 62e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 637f38ef08d07295967b905a61b2356ff6cdf31159Adam Momtaz private final UiSelector mSelector; 64ddc1008f06fd2a875037026490ce1f848a442572Guang Zhu private final UiAutomatorBridge mUiAutomationBridge; 65e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 66e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 673d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Constructs a UiObject to represent a specific UI element matched by the specified 683d50587be8ff021369c90554d814839335b445b0Adam Momtaz * {@link UiSelector} selector properties. 69e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @param selector 70dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 71e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 724ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz public UiObject(UiSelector selector) { 73e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu mUiAutomationBridge = UiDevice.getInstance().getAutomatorBridge(); 74e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu mSelector = selector; 75e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 76e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 77e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 783d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Debugging helper. A test can dump the properties of a selector as a string 793d50587be8ff021369c90554d814839335b445b0Adam Momtaz * to its logs if needed. <code>getSelector().toString();</code> 803d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 814ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz * @return {@link UiSelector} 82dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 83e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 844ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz public final UiSelector getSelector() { 85f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(); 864ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz return new UiSelector(mSelector); 87e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 88e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 89e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 903d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Retrieves the {@link QueryController} to translate a {@link UiSelector} selector 913d50587be8ff021369c90554d814839335b445b0Adam Momtaz * into an {@link AccessibilityNodeInfo}. 923d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 93e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return {@link QueryController} 94e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 95ddc1008f06fd2a875037026490ce1f848a442572Guang Zhu QueryController getQueryController() { 96e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return mUiAutomationBridge.getQueryController(); 97e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 98e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 99e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 1003d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Retrieves the {@link InteractionController} to perform finger actions such as tapping, 1013d50587be8ff021369c90554d814839335b445b0Adam Momtaz * swiping or entering text. 1023d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 103e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return {@link InteractionController} 104e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 105ddc1008f06fd2a875037026490ce1f848a442572Guang Zhu InteractionController getInteractionController() { 106e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return mUiAutomationBridge.getInteractionController(); 107e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 108e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 109e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 1103d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Creates a new UiObject representing a child UI element of the element currently represented 1113d50587be8ff021369c90554d814839335b445b0Adam Momtaz * by this UiObject. 1123d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 1133d50587be8ff021369c90554d814839335b445b0Adam Momtaz * @param selector for UI element to match 1143d50587be8ff021369c90554d814839335b445b0Adam Momtaz * @return a new UiObject representing the matched UI element 115dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 116e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 1174ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz public UiObject getChild(UiSelector selector) throws UiObjectNotFoundException { 118f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(selector); 1194ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz return new UiObject(getSelector().childSelector(selector)); 120e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 121e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 122e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 1233d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Creates a new UiObject representing a child UI element from the parent element currently 1243d50587be8ff021369c90554d814839335b445b0Adam Momtaz * represented by this object. Essentially this is starting the search from the parent 1253d50587be8ff021369c90554d814839335b445b0Adam Momtaz * element and can also be used to find sibling UI elements to the one currently represented 1263d50587be8ff021369c90554d814839335b445b0Adam Momtaz * by this UiObject. 1273d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 1283d50587be8ff021369c90554d814839335b445b0Adam Momtaz * @param selector for the UI element to match 1293d50587be8ff021369c90554d814839335b445b0Adam Momtaz * @return a new UiObject representing the matched UI element 130e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 131dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 132e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 1334ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz public UiObject getFromParent(UiSelector selector) throws UiObjectNotFoundException { 134f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(selector); 1354ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz return new UiObject(getSelector().fromParent(selector)); 136e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 137e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 138e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 1393d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Counts the child UI elements immediately under the UI element currently represented by 140e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * this UiObject. 1413d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 142e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return the count of child UI elements. 143e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 144dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 145e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 146e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public int getChildCount() throws UiObjectNotFoundException { 147f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(); 148e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT); 149e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 150e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 151e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 152e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return node.getChildCount(); 153e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 154e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 155e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 1563d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Uses the member UiSelector properties to find a matching UI element reported in 1573d50587be8ff021369c90554d814839335b445b0Adam Momtaz * the accessibility hierarchy. 1583d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 159e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @param timeout in milliseconds 160e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return AccessibilityNodeInfo if found else null 161dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 162e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 163e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu protected AccessibilityNodeInfo findAccessibilityNodeInfo(long timeout) { 164e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo node = null; 165e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(UiDevice.getInstance().isInWatcherContext()) { 166e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // we will NOT run watchers or do any sort of polling if the 167e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // reason we're here is because of a watcher is executing. Watchers 168e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // will not have other watchers run for them so they should not block 169e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // while they poll for items to become present. We disable polling for them. 170e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu node = getQueryController().findAccessibilityNodeInfo(getSelector()); 171e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } else { 172e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu long startMills = SystemClock.uptimeMillis(); 173e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu long currentMills = 0; 174e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu while (currentMills <= timeout) { 175e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu node = getQueryController().findAccessibilityNodeInfo(getSelector()); 176e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if (node != null) { 177e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu break; 178e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } else { 179e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu UiDevice.getInstance().runWatchers(); 180e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 181e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu currentMills = SystemClock.uptimeMillis() - startMills; 182e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(timeout > 0) { 183e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu SystemClock.sleep(WAIT_FOR_SELECTOR_POLL); 184e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 185e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 186e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 187e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return node; 188e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 189e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 190e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 1913d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Perform the action on the UI element that is represented by this UiObject. Also see 1921893caed0ad4e73b0676f206282d490c2d345316Thanh Le * {@link UiScrollable#scrollToBeginning(int)}, {@link UiScrollable#scrollToEnd(int)}, 1931893caed0ad4e73b0676f206282d490c2d345316Thanh Le * {@link UiScrollable#scrollBackward()}, {@link UiScrollable#scrollForward()}. 1943d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 195467cca7d25dbbf13c14cfd8c2ad38ab8eaf56bdaAdam Momtaz * @param steps indicates the number of injected move steps into the system. Steps are 196467cca7d25dbbf13c14cfd8c2ad38ab8eaf56bdaAdam Momtaz * injected about 5ms apart. So a 100 steps may take about 1/2 second to complete. 1973d50587be8ff021369c90554d814839335b445b0Adam Momtaz * @return true of successful 198e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 199dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 200e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 201e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean swipeUp(int steps) throws UiObjectNotFoundException { 202f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(steps); 2033d50587be8ff021369c90554d814839335b445b0Adam Momtaz Rect rect = getVisibleBounds(); 204e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(rect.height() <= SWIPE_MARGIN_LIMIT * 2) 205e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return false; // too small to swipe 206e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return getInteractionController().swipe(rect.centerX(), 207e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu rect.bottom - SWIPE_MARGIN_LIMIT, rect.centerX(), rect.top + SWIPE_MARGIN_LIMIT, 208e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu steps); 209e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 210e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 211e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 212e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * Perform the action on the UI element that is represented by this object, Also see 2131893caed0ad4e73b0676f206282d490c2d345316Thanh Le * {@link UiScrollable#scrollToBeginning(int)}, {@link UiScrollable#scrollToEnd(int)}, 2141893caed0ad4e73b0676f206282d490c2d345316Thanh Le * {@link UiScrollable#scrollBackward()}, {@link UiScrollable#scrollForward()}. This method will 2151893caed0ad4e73b0676f206282d490c2d345316Thanh Le * perform the swipe gesture over any surface. The targeted UI element does not need to have 2161893caed0ad4e73b0676f206282d490c2d345316Thanh Le * the attribute <code>scrollable</code> set to <code>true</code> for this operation to be 2171893caed0ad4e73b0676f206282d490c2d345316Thanh Le * performed. 2183d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 2193d50587be8ff021369c90554d814839335b445b0Adam Momtaz * @param steps indicates the number of injected move steps into the system. Steps are 220467cca7d25dbbf13c14cfd8c2ad38ab8eaf56bdaAdam Momtaz * injected about 5ms apart. So a 100 steps may take about 1/2 second to complete. 2213d50587be8ff021369c90554d814839335b445b0Adam Momtaz * @return true if successful 222e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 223dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 224e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 225e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean swipeDown(int steps) throws UiObjectNotFoundException { 226f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(steps); 2273d50587be8ff021369c90554d814839335b445b0Adam Momtaz Rect rect = getVisibleBounds(); 228e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(rect.height() <= SWIPE_MARGIN_LIMIT * 2) 229e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return false; // too small to swipe 230e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return getInteractionController().swipe(rect.centerX(), 231e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu rect.top + SWIPE_MARGIN_LIMIT, rect.centerX(), 232e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu rect.bottom - SWIPE_MARGIN_LIMIT, steps); 233e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 234e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 235e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 236e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * Perform the action on the UI element that is represented by this object. Also see 2371893caed0ad4e73b0676f206282d490c2d345316Thanh Le * {@link UiScrollable#scrollToBeginning(int)}, {@link UiScrollable#scrollToEnd(int)}, 2381893caed0ad4e73b0676f206282d490c2d345316Thanh Le * {@link UiScrollable#scrollBackward()}, {@link UiScrollable#scrollForward()}. This method will 2391893caed0ad4e73b0676f206282d490c2d345316Thanh Le * perform the swipe gesture over any surface. The targeted UI element does not need to have the 2401893caed0ad4e73b0676f206282d490c2d345316Thanh Le * attribute <code>scrollable</code> set to <code>true</code> for this operation to be 2411893caed0ad4e73b0676f206282d490c2d345316Thanh Le * performed. 2423d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 2433d50587be8ff021369c90554d814839335b445b0Adam Momtaz * @param steps indicates the number of injected move steps into the system. Steps are 244467cca7d25dbbf13c14cfd8c2ad38ab8eaf56bdaAdam Momtaz * injected about 5ms apart. So a 100 steps may take about 1/2 second to complete. 2453d50587be8ff021369c90554d814839335b445b0Adam Momtaz * @return true if successful 246e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 247dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 248e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 249e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean swipeLeft(int steps) throws UiObjectNotFoundException { 250f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(steps); 2513d50587be8ff021369c90554d814839335b445b0Adam Momtaz Rect rect = getVisibleBounds(); 252e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(rect.width() <= SWIPE_MARGIN_LIMIT * 2) 253e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return false; // too small to swipe 254e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return getInteractionController().swipe(rect.right - SWIPE_MARGIN_LIMIT, 255e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu rect.centerY(), rect.left + SWIPE_MARGIN_LIMIT, rect.centerY(), steps); 256e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 257e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 258e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 259e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * Perform the action on the UI element that is represented by this object. Also see 2601893caed0ad4e73b0676f206282d490c2d345316Thanh Le * {@link UiScrollable#scrollToBeginning(int)}, {@link UiScrollable#scrollToEnd(int)}, 2611893caed0ad4e73b0676f206282d490c2d345316Thanh Le * {@link UiScrollable#scrollBackward()}, {@link UiScrollable#scrollForward()}. This method will 2621893caed0ad4e73b0676f206282d490c2d345316Thanh Le * perform the swipe gesture over any surface. The targeted UI element does not need to have the 2631893caed0ad4e73b0676f206282d490c2d345316Thanh Le * attribute <code>scrollable</code> set to <code>true</code> for this operation to be 2641893caed0ad4e73b0676f206282d490c2d345316Thanh Le * performed. 2653d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 2663d50587be8ff021369c90554d814839335b445b0Adam Momtaz * @param steps indicates the number of injected move steps into the system. Steps are 267467cca7d25dbbf13c14cfd8c2ad38ab8eaf56bdaAdam Momtaz * injected about 5ms apart. So a 100 steps may take about 1/2 second to complete. 2683d50587be8ff021369c90554d814839335b445b0Adam Momtaz * @return true if successful 269e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 270dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 271e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 272e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean swipeRight(int steps) throws UiObjectNotFoundException { 273f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(steps); 2743d50587be8ff021369c90554d814839335b445b0Adam Momtaz Rect rect = getVisibleBounds(); 275e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(rect.width() <= SWIPE_MARGIN_LIMIT * 2) 276e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return false; // too small to swipe 277e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return getInteractionController().swipe(rect.left + SWIPE_MARGIN_LIMIT, 278e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu rect.centerY(), rect.right - SWIPE_MARGIN_LIMIT, rect.centerY(), steps); 279e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 280e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 281e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 2823d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Finds the visible bounds of a partially visible UI element 2833d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 284e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @param node 2857f38ef08d07295967b905a61b2356ff6cdf31159Adam Momtaz * @return null if node is null, else a Rect containing visible bounds 286e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 287e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu private Rect getVisibleBounds(AccessibilityNodeInfo node) { 288e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if (node == null) { 289e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return null; 290e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 291e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 292e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // targeted node's bounds 2937f38ef08d07295967b905a61b2356ff6cdf31159Adam Momtaz Rect nodeRect = AccessibilityNodeInfoHelper.getVisibleBoundsInScreen(node); 294e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 295e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // is the targeted node within a scrollable container? 296e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo scrollableParentNode = getScrollableParent(node); 297e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(scrollableParentNode == null) { 298e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // nothing to adjust for so return the node's Rect as is 299e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return nodeRect; 300e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 301e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 302e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // Scrollable parent's visible bounds 3037f38ef08d07295967b905a61b2356ff6cdf31159Adam Momtaz Rect parentRect = AccessibilityNodeInfoHelper 3047f38ef08d07295967b905a61b2356ff6cdf31159Adam Momtaz .getVisibleBoundsInScreen(scrollableParentNode); 305e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // adjust for partial clipping of targeted by parent node if required 306e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu nodeRect.intersect(parentRect); 307e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return nodeRect; 308e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 309e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 310e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 3117f38ef08d07295967b905a61b2356ff6cdf31159Adam Momtaz * Walk the hierarchy up to find a scrollable parent. A scrollable parent 3127f38ef08d07295967b905a61b2356ff6cdf31159Adam Momtaz * indicates that this node may be in a content where it is partially 3137f38ef08d07295967b905a61b2356ff6cdf31159Adam Momtaz * visible due to scrolling. its clickable center maybe invisible and 3147f38ef08d07295967b905a61b2356ff6cdf31159Adam Momtaz * adjustments should be made to the click coordinates. 3153d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 316e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @param node 3171893caed0ad4e73b0676f206282d490c2d345316Thanh Le * @return The accessibility node info. 318e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 319e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu private AccessibilityNodeInfo getScrollableParent(AccessibilityNodeInfo node) { 320e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo parent = node; 321e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu while(parent != null) { 322e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu parent = parent.getParent(); 323e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if (parent != null && parent.isScrollable()) { 324e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return parent; 325e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 326e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 327e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return null; 328e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 329e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 330e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 3313d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Performs a click at the center of the visible bounds of the UI element represented 33246d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * by this UiObject. 3333d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 334e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true id successful else false 335e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 336dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 337e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 338e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean click() throws UiObjectNotFoundException { 339f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(); 340e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT); 341e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 342e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 343e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 344e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu Rect rect = getVisibleBounds(node); 3451dc7d12406947faaee8454c6efb2a0631f5da573Adam Momtaz return getInteractionController().clickAndSync(rect.centerX(), rect.centerY()); 346e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 347e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 348e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 3493d50587be8ff021369c90554d814839335b445b0Adam Momtaz * See {@link #clickAndWaitForNewWindow(long)} 350a46ac3504426564954292b13380120e8cc6b1527Adam Momtaz * This method is intended to reliably wait for window transitions that would typically take 351a46ac3504426564954292b13380120e8cc6b1527Adam Momtaz * longer than the usual default timeouts. 3523d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 3533d50587be8ff021369c90554d814839335b445b0Adam Momtaz * @return true if the event was triggered, else false 3543d50587be8ff021369c90554d814839335b445b0Adam Momtaz * @throws UiObjectNotFoundException 355dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 3563d50587be8ff021369c90554d814839335b445b0Adam Momtaz */ 357e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean clickAndWaitForNewWindow() throws UiObjectNotFoundException { 358f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(); 359e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return clickAndWaitForNewWindow(WAIT_FOR_WINDOW_TMEOUT); 360e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 361e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 362e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 36346d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * Performs a click at the center of the visible bounds of the UI element represented 36446d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * by this UiObject and waits for window transitions. 36546d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * 3663d50587be8ff021369c90554d814839335b445b0Adam Momtaz * This method differ from {@link UiObject#click()} only in that this method waits for a 36746d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * a new window transition as a result of the click. Some examples of a window transition: 368e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * <li>launching a new activity</li> 369e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * <li>bringing up a pop-up menu</li> 370e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * <li>bringing up a dialog</li> 371e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * 3723d50587be8ff021369c90554d814839335b445b0Adam Momtaz * @param timeout timeout before giving up on waiting for a new window 373e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if the event was triggered, else false 374e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 375dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 376e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 377e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean clickAndWaitForNewWindow(long timeout) throws UiObjectNotFoundException { 378f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(timeout); 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); 3841dc7d12406947faaee8454c6efb2a0631f5da573Adam Momtaz return getInteractionController().clickAndWaitForNewWindow(rect.centerX(), rect.centerY()); 385e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 386e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 387e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 3883d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Clicks the top and left corner of the UI element 3893d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 390e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true on success 3911893caed0ad4e73b0676f206282d490c2d345316Thanh Le * @throws UiObjectNotFoundException 392dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 393e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 394e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean clickTopLeft() throws UiObjectNotFoundException { 395f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(); 396e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT); 397e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 398e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 399e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 400e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu Rect rect = getVisibleBounds(node); 4011dc7d12406947faaee8454c6efb2a0631f5da573Adam Momtaz return getInteractionController().clickNoSync(rect.left + 5, rect.top + 5); 402e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 403e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 404e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 4053d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Long clicks bottom and right corner of the UI element 4063d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 407e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if operation was successful 408e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 409dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 410e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 411e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean longClickBottomRight() throws UiObjectNotFoundException { 412f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(); 413e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT); 414e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 415e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 416e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 417e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu Rect rect = getVisibleBounds(node); 4181dc7d12406947faaee8454c6efb2a0631f5da573Adam Momtaz return getInteractionController().longTapNoSync(rect.right - 5, rect.bottom - 5); 419e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 420e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 421e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 4223d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Clicks the bottom and right corner of the UI element 4233d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 424e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true on success 4251893caed0ad4e73b0676f206282d490c2d345316Thanh Le * @throws UiObjectNotFoundException 426dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 427e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 428e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean clickBottomRight() throws UiObjectNotFoundException { 429f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(); 430e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT); 431e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 432e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 433e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 434e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu Rect rect = getVisibleBounds(node); 4351dc7d12406947faaee8454c6efb2a0631f5da573Adam Momtaz return getInteractionController().clickNoSync(rect.right - 5, rect.bottom - 5); 436e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 437e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 438e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 4393d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Long clicks the center of the visible bounds of the UI element 4403d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 441e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if operation was successful 442e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 443dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 444e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 445e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean longClick() throws UiObjectNotFoundException { 446f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(); 447e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT); 448e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 449e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 450e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 451e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu Rect rect = getVisibleBounds(node); 4521dc7d12406947faaee8454c6efb2a0631f5da573Adam Momtaz return getInteractionController().longTapNoSync(rect.centerX(), rect.centerY()); 453e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 454e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 455e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 4563d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Long clicks on the top and left corner of the UI element 4573d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 458e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if operation was successful 459e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 460dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 461e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 462e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean longClickTopLeft() throws UiObjectNotFoundException { 463f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(); 464e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT); 465e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 466e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 467e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 468e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu Rect rect = getVisibleBounds(node); 4691dc7d12406947faaee8454c6efb2a0631f5da573Adam Momtaz return getInteractionController().longTapNoSync(rect.left + 5, rect.top + 5); 470e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 471e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 472e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 4733d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Reads the <code>text</code> property of the UI element 4743d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 475e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return text value of the current node represented by this UiObject 476e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException if no match could be found 477dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 478e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 479e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public String getText() throws UiObjectNotFoundException { 480f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(); 481e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT); 482e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 483e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 484e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 485e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu String retVal = safeStringReturn(node.getText()); 486e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu Log.d(LOG_TAG, String.format("getText() = %s", retVal)); 487e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return retVal; 488e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 489e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 490e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 49197835f3a7c80b147136c44c175eb9e6a4261fd92Adam Momtaz * Reads the <code>className</code> property of the UI element 49297835f3a7c80b147136c44c175eb9e6a4261fd92Adam Momtaz * 49397835f3a7c80b147136c44c175eb9e6a4261fd92Adam Momtaz * @return class name of the current node represented by this UiObject 49497835f3a7c80b147136c44c175eb9e6a4261fd92Adam Momtaz * @throws UiObjectNotFoundException if no match could be found 49597835f3a7c80b147136c44c175eb9e6a4261fd92Adam Momtaz * @since API Level 18 49697835f3a7c80b147136c44c175eb9e6a4261fd92Adam Momtaz */ 49797835f3a7c80b147136c44c175eb9e6a4261fd92Adam Momtaz public String getClassName() throws UiObjectNotFoundException { 49897835f3a7c80b147136c44c175eb9e6a4261fd92Adam Momtaz Tracer.trace(); 49997835f3a7c80b147136c44c175eb9e6a4261fd92Adam Momtaz AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT); 50097835f3a7c80b147136c44c175eb9e6a4261fd92Adam Momtaz if(node == null) { 50197835f3a7c80b147136c44c175eb9e6a4261fd92Adam Momtaz throw new UiObjectNotFoundException(getSelector().toString()); 50297835f3a7c80b147136c44c175eb9e6a4261fd92Adam Momtaz } 50397835f3a7c80b147136c44c175eb9e6a4261fd92Adam Momtaz String retVal = safeStringReturn(node.getClassName()); 50497835f3a7c80b147136c44c175eb9e6a4261fd92Adam Momtaz Log.d(LOG_TAG, String.format("getClassName() = %s", retVal)); 50597835f3a7c80b147136c44c175eb9e6a4261fd92Adam Momtaz return retVal; 50697835f3a7c80b147136c44c175eb9e6a4261fd92Adam Momtaz } 50797835f3a7c80b147136c44c175eb9e6a4261fd92Adam Momtaz 50897835f3a7c80b147136c44c175eb9e6a4261fd92Adam Momtaz /** 5093d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Reads the <code>content_desc</code> property of the UI element 5103d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 511e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return value of node attribute "content_desc" 512e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 513dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 514e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 515e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public String getContentDescription() throws UiObjectNotFoundException { 516f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(); 517e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT); 518e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 519e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 520e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 521e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return safeStringReturn(node.getContentDescription()); 522e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 523e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 524e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 52546d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * Sets the text in an editable field, after clearing the field's content. 52646d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * 52746d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * The {@link UiSelector} selector of this object must reference a UI element that is editable. 52846d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * 52946d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * When you call this method, the method first simulates a {@link #click()} on 53046d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * editable field to set focus. The method then clears the field's contents 53146d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * and injects your specified text into the field. 5323d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 53346d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * If you want to capture the original contents of the field, call {@link #getText()} first. 53446d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * You can then modify the text and use this method to update the field. 53546d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * 53646d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * @param text string to set 537e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if operation is successful 538e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 539dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 540e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 541e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean setText(String text) throws UiObjectNotFoundException { 542f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(text); 543e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu clearTextField(); 544e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return getInteractionController().sendText(text); 545e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 546e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 547e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 54846d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * Clears the existing text contents in an editable field. 54946d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * 55046d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * The {@link UiSelector} of this object must reference a UI element that is editable. 55146d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * 55246d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * When you call this method, the method first sets focus at the start edge of the field. 55346d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * The method then simulates a long-press to select the existing text, and deletes the 55446d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * selected text. 55546d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * 55646d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * If a "Select-All" option is displayed, the method will automatically attempt to use it 55746d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * to ensure full text selection. 55846d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * 55946d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * Note that it is possible that not all the text in the field is selected; for example, 56046d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * if the text contains separators such as spaces, slashes, at symbol etc. 56146d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * Also, not all editable fields support the long-press functionality. 56246d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * 563e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 564dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 565e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 566e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public void clearTextField() throws UiObjectNotFoundException { 567f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(); 568e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // long click left + center 569e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT); 570e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 571e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 572e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 573e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu Rect rect = getVisibleBounds(node); 5741dc7d12406947faaee8454c6efb2a0631f5da573Adam Momtaz getInteractionController().longTapNoSync(rect.left + 20, rect.centerY()); 575e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // check if the edit menu is open 5764ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz UiObject selectAll = new UiObject(new UiSelector().descriptionContains("Select all")); 577e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(selectAll.waitForExists(50)) 578e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu selectAll.click(); 579e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // wait for the selection 580e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu SystemClock.sleep(250); 581e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // delete it 582e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu getInteractionController().sendKey(KeyEvent.KEYCODE_DEL, 0); 583e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 584e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 585e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 5863d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Check if the UI element's <code>checked</code> property is currently true 5873d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 588e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if it is else false 589dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 590e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 591e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean isChecked() throws UiObjectNotFoundException { 592f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(); 593e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT); 594e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 595e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 596e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 597e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return node.isChecked(); 598e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 599e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 600e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 6013d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Check if the UI element's <code>selected</code> property is currently true 6023d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 603e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if it is else false 604e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 605dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 606e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 607e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean isSelected() throws UiObjectNotFoundException { 608f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(); 609e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT); 610e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 611e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 612e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 613e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return node.isSelected(); 614e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 615e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 616e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 6173d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Check if the UI element's <code>checkable</code> property is currently true 6183d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 619e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if it is else false 620e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 621dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 622e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 623e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean isCheckable() throws UiObjectNotFoundException { 624f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(); 625e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT); 626e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 627e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 628e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 629e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return node.isCheckable(); 630e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 631e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 632e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 6333d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Check if the UI element's <code>enabled</code> property is currently true 6343d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 635e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if it is else false 636e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 637dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 638e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 639e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean isEnabled() throws UiObjectNotFoundException { 640f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(); 641e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT); 642e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 643e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 644e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 645e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return node.isEnabled(); 646e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 647e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 648e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 6493d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Check if the UI element's <code>clickable</code> property is currently true 6503d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 651e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if it is else false 652e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 653dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 654e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 655e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean isClickable() throws UiObjectNotFoundException { 656f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(); 657e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT); 658e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 659e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 660e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 661e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return node.isClickable(); 662e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 663e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 664e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 6653d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Check if the UI element's <code>focused</code> property is currently true 6663d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 667e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if it is else false 668e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 669dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 670e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 671e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean isFocused() throws UiObjectNotFoundException { 672f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(); 673e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT); 674e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 675e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 676e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 677e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return node.isFocused(); 678e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 679e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 680e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 6813d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Check if the UI element's <code>focusable</code> property is currently true 6823d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 683e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if it is else false 684e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 685dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 686e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 687e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean isFocusable() throws UiObjectNotFoundException { 688f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(); 689e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT); 690e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 691e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 692e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 693e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return node.isFocusable(); 694e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 695e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 696e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 6973d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Check if the UI element's <code>scrollable</code> property is currently true 6983d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 699e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if it is else false 700e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 701dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 702e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 703e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean isScrollable() throws UiObjectNotFoundException { 704f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(); 705e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT); 706e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 707e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 708e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 709e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return node.isScrollable(); 710e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 711e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 712e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 7133d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Check if the UI element's <code>long-clickable</code> property is currently true 7143d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 715e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if it is else false 716e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 717dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 718e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 719e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean isLongClickable() throws UiObjectNotFoundException { 720f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(); 721e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT); 722e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 723e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 724e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 725e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return node.isLongClickable(); 726e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 727e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 728e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 7293d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Reads the UI element's <code>package</code> property 7303d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 7313d50587be8ff021369c90554d814839335b445b0Adam Momtaz * @return true if it is else false 732e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 733dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 734e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 735e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public String getPackageName() throws UiObjectNotFoundException { 736f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(); 737e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT); 738e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 739e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 740e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 741e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return safeStringReturn(node.getPackageName()); 742e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 743e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 744e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 74546d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * Returns the visible bounds of the UI element. 74646d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * 74746d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * If a portion of the UI element is visible, only the bounds of the visible portion are 74846d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * reported. 7493d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 750e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return Rect 751e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 7521893caed0ad4e73b0676f206282d490c2d345316Thanh Le * @see {@link #getBounds()} 75379693ede92636fe6f3a6ec4dc049a438fd9504ffGuang Zhu * @since API Level 17 754e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 7553d50587be8ff021369c90554d814839335b445b0Adam Momtaz public Rect getVisibleBounds() throws UiObjectNotFoundException { 756f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(); 757e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT); 758e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 759e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 760e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 761e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return getVisibleBounds(node); 762e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 763e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 764e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 76546d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * Returns the UI element's <code>bounds</code> property. See {@link #getVisibleBounds()} 7663d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 7673d50587be8ff021369c90554d814839335b445b0Adam Momtaz * @return Rect 7683d50587be8ff021369c90554d814839335b445b0Adam Momtaz * @throws UiObjectNotFoundException 769dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 7703d50587be8ff021369c90554d814839335b445b0Adam Momtaz */ 7713d50587be8ff021369c90554d814839335b445b0Adam Momtaz public Rect getBounds() throws UiObjectNotFoundException { 772f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(); 7733d50587be8ff021369c90554d814839335b445b0Adam Momtaz AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT); 7743d50587be8ff021369c90554d814839335b445b0Adam Momtaz if(node == null) { 7753d50587be8ff021369c90554d814839335b445b0Adam Momtaz throw new UiObjectNotFoundException(getSelector().toString()); 7763d50587be8ff021369c90554d814839335b445b0Adam Momtaz } 7773d50587be8ff021369c90554d814839335b445b0Adam Momtaz Rect nodeRect = new Rect(); 7783d50587be8ff021369c90554d814839335b445b0Adam Momtaz node.getBoundsInScreen(nodeRect); 7793d50587be8ff021369c90554d814839335b445b0Adam Momtaz 7803d50587be8ff021369c90554d814839335b445b0Adam Momtaz return nodeRect; 7813d50587be8ff021369c90554d814839335b445b0Adam Momtaz } 7823d50587be8ff021369c90554d814839335b445b0Adam Momtaz 7833d50587be8ff021369c90554d814839335b445b0Adam Momtaz /** 78446d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * Waits a specified length of time for a UI element to become visible. 78546d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * 78646d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * This method waits until the UI element becomes visible on the display, or 78746d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * until the timeout has elapsed. You can use this method in situations where 78846d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * the content that you want to select is not immediately displayed. 7893d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 79046d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * @param timeout the amount of time to wait (in milliseconds) 79146d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * @return true if the UI element is displayed, else false if timeout elapsed while waiting 792dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 793e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 794e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean waitForExists(long timeout) { 795f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(timeout); 796e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(findAccessibilityNodeInfo(timeout) != null) { 797e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return true; 798e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 799e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return false; 800e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 801e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 802e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 80346d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * Waits a specified length of time for a UI element to become undetectable. 8043d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 80546d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * This method waits until a UI element is no longer matchable, or until the 80646d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * timeout has elapsed. 80746d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * 80846d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * A UI element becomes undetectable when the {@link UiSelector} of the object is 80946d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * unable to find a match because the element has either changed its state or is no 81046d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * longer displayed. 81146d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * 81246d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * You can use this method when attempting to wait for some long operation 81346d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * to compete, such as downloading a large file or connecting to a remote server. 81446d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * 81546d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * @param timeout time to wait (in milliseconds) 81646d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * @return true if the element is gone before timeout elapsed, else false if timeout elapsed 81746d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * but a matching element is still found. 818dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 819e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 820e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean waitUntilGone(long timeout) { 821f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(timeout); 822e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu long startMills = SystemClock.uptimeMillis(); 823e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu long currentMills = 0; 824e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu while (currentMills <= timeout) { 825e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(findAccessibilityNodeInfo(0) == null) 826e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return true; 827e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu currentMills = SystemClock.uptimeMillis() - startMills; 828e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(timeout > 0) 829e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu SystemClock.sleep(WAIT_FOR_SELECTOR_POLL); 830e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 831e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return false; 832e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 833e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 834e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 83546d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * Check if UI element exists. 83646d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * 837e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * This methods performs a {@link #waitForExists(long)} with zero timeout. This 838e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * basically returns immediately whether the UI element represented by this UiObject 839e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * exists or not. If you need to wait longer for this UI element, then see 840e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * {@link #waitForExists(long)}. 8413d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 842e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if the UI element represented by this UiObject does exist 843dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 844e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 845e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean exists() { 846f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(); 847e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return waitForExists(0); 848e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 849e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 850e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu private String safeStringReturn(CharSequence cs) { 851e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(cs == null) 852e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return ""; 853e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return cs.toString(); 854e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 855c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz 856c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz /** 857c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * PinchOut generates a 2 pointer gesture where each pointer is moving from the center out 858c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * away from each other diagonally towards the edges of the current UI element represented by 859c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * this UiObject. 860c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * @param percent of the object's diagonal length to use for the pinch 861c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * @param steps indicates the number of injected move steps into the system. Steps are 862c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * injected about 5ms apart. So a 100 steps may take about 1/2 second to complete. 863c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * @throws UiObjectNotFoundException 864c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * @since API Level 18 865c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz */ 866c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz public void pinchOut(int percent, int steps) throws UiObjectNotFoundException { 867c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz // make value between 1 and 100 868c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz percent = (percent < 0) ? 1 : (percent > 100) ? 100 : percent; 869c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz float percentage = percent / 100f; 870c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz 871c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT); 872c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz if (node == null) { 873c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz throw new UiObjectNotFoundException(getSelector().toString()); 874c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz } 875c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz 876c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz Rect rect = getVisibleBounds(node); 877c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz if (rect.width() <= FINGER_TOUCH_HALF_WIDTH * 2) 878c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz throw new IllegalStateException("Object width is too small for operation"); 879c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz 880c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz // start from the same point at the center of the control 881c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz Point startPoint1 = new Point(rect.centerX() - FINGER_TOUCH_HALF_WIDTH, rect.centerY()); 882c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz Point startPoint2 = new Point(rect.centerX() + FINGER_TOUCH_HALF_WIDTH, rect.centerY()); 883c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz 884c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz // End at the top-left and bottom-right corners of the control 885c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz Point endPoint1 = new Point(rect.centerX() - (int)((rect.width()/2) * percentage), 886c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz rect.centerY()); 887c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz Point endPoint2 = new Point(rect.centerX() + (int)((rect.width()/2) * percentage), 888c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz rect.centerY()); 889c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz 890c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz twoPointerGesture(startPoint1, startPoint2, endPoint1, endPoint2, steps); 891c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz } 892c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz 893c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz /** 894c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * PinchIn generates a 2 pointer gesture where each pointer is moving towards the other 895c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * diagonally from the edges of the current UI element represented by this UiObject, until the 896c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * center. 897c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * @param percent of the object's diagonal length to use for the pinch 898c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * @param steps indicates the number of injected move steps into the system. Steps are 899c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * injected about 5ms apart. So a 100 steps may take about 1/2 second to complete. 900c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * @throws UiObjectNotFoundException 901c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * @since API Level 18 902c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz */ 903c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz public void pinchIn(int percent, int steps) throws UiObjectNotFoundException { 904c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz // make value between 1 and 100 905c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz percent = (percent < 0) ? 0 : (percent > 100) ? 100 : percent; 906c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz float percentage = percent / 100f; 907c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz 908c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT); 909c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz if (node == null) { 910c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz throw new UiObjectNotFoundException(getSelector().toString()); 911c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz } 912c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz 913c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz Rect rect = getVisibleBounds(node); 914c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz if (rect.width() <= FINGER_TOUCH_HALF_WIDTH * 2) 915c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz throw new IllegalStateException("Object width is too small for operation"); 916c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz 917c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz Point startPoint1 = new Point(rect.centerX() - (int)((rect.width()/2) * percentage), 918c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz rect.centerY()); 919c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz Point startPoint2 = new Point(rect.centerX() + (int)((rect.width()/2) * percentage), 920c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz rect.centerY()); 921c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz 922c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz Point endPoint1 = new Point(rect.centerX() - FINGER_TOUCH_HALF_WIDTH, rect.centerY()); 923c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz Point endPoint2 = new Point(rect.centerX() + FINGER_TOUCH_HALF_WIDTH, rect.centerY()); 924c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz 925c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz twoPointerGesture(startPoint1, startPoint2, endPoint1, endPoint2, steps); 926c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz } 927c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz 928c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz /** 929c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * Generates a 2 pointer gesture from an arbitrary starting and ending points. 930c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * 931c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * @param startPoint1 start point of pointer 1 932c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * @param startPoint2 start point of pointer 2 933c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * @param endPoint1 end point of pointer 1 934c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * @param endPoint2 end point of pointer 2 935c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * @param steps indicates the number of injected move steps into the system. Steps are 936c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * injected about 5ms apart. So a 100 steps may take about 1/2 second to complete. 937c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * @since API Level 18 938c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz */ 939c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz public void twoPointerGesture(Point startPoint1, Point startPoint2, Point endPoint1, 940c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz Point endPoint2, int steps) { 941c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz 942c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz // avoid a divide by zero 943c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz if(steps == 0) 944c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz steps = 1; 945c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz 946c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz final float stepX1 = (endPoint1.x - startPoint1.x) / steps; 947c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz final float stepY1 = (endPoint1.y - startPoint1.y) / steps; 948c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz final float stepX2 = (endPoint2.x - startPoint2.x) / steps; 949c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz final float stepY2 = (endPoint2.y - startPoint2.y) / steps; 950c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz 951c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz int eventX1, eventY1, eventX2, eventY2; 952c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz eventX1 = startPoint1.x; 953c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz eventY1 = startPoint1.y; 954c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz eventX2 = startPoint2.x; 955c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz eventY2 = startPoint2.y; 956c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz 957c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz // allocate for steps plus first down and last up 958c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz PointerCoords[] points1 = new PointerCoords[steps + 2]; 959c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz PointerCoords[] points2 = new PointerCoords[steps + 2]; 960c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz 961c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz // Include the first and last touch downs in the arrays of steps 962c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz for (int i = 0; i < steps + 1; i++) { 963c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz PointerCoords p1 = new PointerCoords(); 964c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz p1.x = eventX1; 965c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz p1.y = eventY1; 966c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz p1.pressure = 1; 967c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz p1.size = 1; 968c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz points1[i] = p1; 969c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz 970c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz PointerCoords p2 = new PointerCoords(); 971c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz p2.x = eventX2; 972c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz p2.y = eventY2; 973c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz p2.pressure = 1; 974c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz p2.size = 1; 975c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz points2[i] = p2; 976c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz 977c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz eventX1 += stepX1; 978c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz eventY1 += stepY1; 979c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz eventX2 += stepX2; 980c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz eventY2 += stepY2; 981c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz } 982c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz 983c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz // ending pointers coordinates 984c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz PointerCoords p1 = new PointerCoords(); 985c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz p1.x = endPoint1.x; 986c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz p1.y = endPoint1.y; 987c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz p1.pressure = 1; 988c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz p1.size = 1; 989c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz points1[steps + 1] = p1; 990c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz 991c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz PointerCoords p2 = new PointerCoords(); 992c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz p2.x = endPoint2.x; 993c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz p2.y = endPoint2.y; 994c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz p2.pressure = 1; 995c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz p2.size = 1; 996c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz points2[steps + 1] = p2; 997c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz 998c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz multiPointerGesture(points1, points2); 999c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz } 1000c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz 1001c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz /** 1002c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * Performs a multi-touch gesture 1003c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * 1004c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * Takes a series of touch coordinates for at least 2 pointers. Each pointer must have 1005c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * all of its touch steps defined in an array of {@link PointerCoords}. By having the ability 1006c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * to specify the touch points along the path of a pointer, the caller is able to specify 1007c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * complex gestures like circles, irregular shapes etc, where each pointer may take a 1008c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * different path. 1009c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * 1010c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * To create a single point on a pointer's touch path 1011c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * <code> 1012c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * PointerCoords p = new PointerCoords(); 1013c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * p.x = stepX; 1014c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * p.y = stepY; 1015c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * p.pressure = 1; 1016c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * p.size = 1; 1017c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * </code> 1018c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * @param touches each array of {@link PointerCoords} constitute a single pointer's touch path. 1019c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * Multiple {@link PointerCoords} arrays constitute multiple pointers, each with its own 1020c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * path. Each {@link PointerCoords} in an array constitute a point on a pointer's path. 1021c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * @since API Level 18 1022c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz */ 1023c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz public void multiPointerGesture(PointerCoords[] ...touches) { 1024c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz getInteractionController().generateMultiPointerGesture(touches); 1025c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz } 1026c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz}