UiObject.java revision 46fcf070655a908e4ffaf93fe0d2b7be21bb004b
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 390d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz * @deprecated use {@link Configurator#setWaitForSelectorTimeout(long)} 40dbba713661688a285e701a006ce2d199296ac328Guang Zhu **/ 410d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz @Deprecated 42e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu protected static final long WAIT_FOR_SELECTOR_TIMEOUT = 10 * 1000; 43dbba713661688a285e701a006ce2d199296ac328Guang Zhu /** 44dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 45dbba713661688a285e701a006ce2d199296ac328Guang Zhu **/ 46e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu protected static final long WAIT_FOR_SELECTOR_POLL = 1000; 47e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // set a default timeout to 5.5s, since ANR threshold is 5s 48dbba713661688a285e701a006ce2d199296ac328Guang Zhu /** 49dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 50dbba713661688a285e701a006ce2d199296ac328Guang Zhu **/ 51e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu protected static final long WAIT_FOR_WINDOW_TMEOUT = 5500; 52dbba713661688a285e701a006ce2d199296ac328Guang Zhu /** 53c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * @since API Level 16 54c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz **/ 55c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz protected static final int SWIPE_MARGIN_LIMIT = 5; 56c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz /** 57dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 17 580d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz * @deprecated use {@link Configurator#setScrollAcknowledgmentTimeout(long)} 59dbba713661688a285e701a006ce2d199296ac328Guang Zhu **/ 600d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz @Deprecated 616088c8f9e34e34a4958b1601ed7c1bb34c95da21Adam Momtaz protected static final long WAIT_FOR_EVENT_TMEOUT = 3 * 1000; 62dbba713661688a285e701a006ce2d199296ac328Guang Zhu /** 63c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * @since API Level 18 64dbba713661688a285e701a006ce2d199296ac328Guang Zhu **/ 65c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz protected static final int FINGER_TOUCH_HALF_WIDTH = 20; 66e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 677f38ef08d07295967b905a61b2356ff6cdf31159Adam Momtaz private final UiSelector mSelector; 68e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 690d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz private final Configurator mConfig = Configurator.getInstance(); 700d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz 71e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 723d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Constructs a UiObject to represent a specific UI element matched by the specified 733d50587be8ff021369c90554d814839335b445b0Adam Momtaz * {@link UiSelector} selector properties. 74e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @param selector 75dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 76e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 774ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz public UiObject(UiSelector selector) { 78e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu mSelector = selector; 79e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 80e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 81e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 823d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Debugging helper. A test can dump the properties of a selector as a string 833d50587be8ff021369c90554d814839335b445b0Adam Momtaz * to its logs if needed. <code>getSelector().toString();</code> 843d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 854ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz * @return {@link UiSelector} 86dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 87e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 884ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz public final UiSelector getSelector() { 89f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(); 904ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz return new UiSelector(mSelector); 91e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 92e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 93e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 943d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Retrieves the {@link QueryController} to translate a {@link UiSelector} selector 953d50587be8ff021369c90554d814839335b445b0Adam Momtaz * into an {@link AccessibilityNodeInfo}. 963d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 97e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return {@link QueryController} 98e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 99ddc1008f06fd2a875037026490ce1f848a442572Guang Zhu QueryController getQueryController() { 10046fcf070655a908e4ffaf93fe0d2b7be21bb004bGuang Zhu return UiDevice.getInstance().getAutomatorBridge().getQueryController(); 101e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 102e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 103e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 1043d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Retrieves the {@link InteractionController} to perform finger actions such as tapping, 1053d50587be8ff021369c90554d814839335b445b0Adam Momtaz * swiping or entering text. 1063d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 107e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return {@link InteractionController} 108e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 109ddc1008f06fd2a875037026490ce1f848a442572Guang Zhu InteractionController getInteractionController() { 11046fcf070655a908e4ffaf93fe0d2b7be21bb004bGuang Zhu return UiDevice.getInstance().getAutomatorBridge().getInteractionController(); 111e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 112e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 113e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 1143d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Creates a new UiObject representing a child UI element of the element currently represented 1153d50587be8ff021369c90554d814839335b445b0Adam Momtaz * by this UiObject. 1163d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 1173d50587be8ff021369c90554d814839335b445b0Adam Momtaz * @param selector for UI element to match 1183d50587be8ff021369c90554d814839335b445b0Adam Momtaz * @return a new UiObject representing the matched UI element 119dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 120e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 1214ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz public UiObject getChild(UiSelector selector) throws UiObjectNotFoundException { 122f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(selector); 1234ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz return new UiObject(getSelector().childSelector(selector)); 124e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 125e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 126e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 1273d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Creates a new UiObject representing a child UI element from the parent element currently 1283d50587be8ff021369c90554d814839335b445b0Adam Momtaz * represented by this object. Essentially this is starting the search from the parent 1293d50587be8ff021369c90554d814839335b445b0Adam Momtaz * element and can also be used to find sibling UI elements to the one currently represented 1303d50587be8ff021369c90554d814839335b445b0Adam Momtaz * by this UiObject. 1313d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 1323d50587be8ff021369c90554d814839335b445b0Adam Momtaz * @param selector for the UI element to match 1333d50587be8ff021369c90554d814839335b445b0Adam Momtaz * @return a new UiObject representing the matched UI element 134e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 135dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 136e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 1374ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz public UiObject getFromParent(UiSelector selector) throws UiObjectNotFoundException { 138f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(selector); 1394ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz return new UiObject(getSelector().fromParent(selector)); 140e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 141e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 142e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 1433d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Counts the child UI elements immediately under the UI element currently represented by 144e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * this UiObject. 1453d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 146e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return the count of child UI elements. 147e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 148dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 149e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 150e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public int getChildCount() throws UiObjectNotFoundException { 151f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(); 1520d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout()); 153e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 154e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 155e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 156e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return node.getChildCount(); 157e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 158e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 159e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 1603d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Uses the member UiSelector properties to find a matching UI element reported in 1613d50587be8ff021369c90554d814839335b445b0Adam Momtaz * the accessibility hierarchy. 1623d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 163e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @param timeout in milliseconds 164e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return AccessibilityNodeInfo if found else null 165dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 166e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 167e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu protected AccessibilityNodeInfo findAccessibilityNodeInfo(long timeout) { 168e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo node = null; 169bb36257f15f090966e2aeb9fd4f092e1a54722b1Adam Momtaz long startMills = SystemClock.uptimeMillis(); 170bb36257f15f090966e2aeb9fd4f092e1a54722b1Adam Momtaz long currentMills = 0; 171bb36257f15f090966e2aeb9fd4f092e1a54722b1Adam Momtaz while (currentMills <= timeout) { 172e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu node = getQueryController().findAccessibilityNodeInfo(getSelector()); 173bb36257f15f090966e2aeb9fd4f092e1a54722b1Adam Momtaz if (node != null) { 174bb36257f15f090966e2aeb9fd4f092e1a54722b1Adam Momtaz break; 175bb36257f15f090966e2aeb9fd4f092e1a54722b1Adam Momtaz } else { 176bb36257f15f090966e2aeb9fd4f092e1a54722b1Adam Momtaz // does nothing if we're reentering another runWatchers() 177bb36257f15f090966e2aeb9fd4f092e1a54722b1Adam Momtaz UiDevice.getInstance().runWatchers(); 178bb36257f15f090966e2aeb9fd4f092e1a54722b1Adam Momtaz } 179bb36257f15f090966e2aeb9fd4f092e1a54722b1Adam Momtaz currentMills = SystemClock.uptimeMillis() - startMills; 180bb36257f15f090966e2aeb9fd4f092e1a54722b1Adam Momtaz if(timeout > 0) { 181bb36257f15f090966e2aeb9fd4f092e1a54722b1Adam Momtaz SystemClock.sleep(WAIT_FOR_SELECTOR_POLL); 182e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 183e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 184e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return node; 185e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 186e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 187e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 1888d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz * Performs a drag of this object to a destination UiObject. Note that the number of steps 1898d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz * used can influence the drag speed and varying speeds may impact the results. Consider 1908d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz * evaluating different speeds when testing this method. 1918d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz * 1928d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz * @param destObj 1938d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz * @param steps usually 40 steps. More or less to change the speed. 1948d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz * @return true of successful 1958d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz * @throws UiObjectNotFoundException 1968d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz * @since API Level 18 1978d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz */ 1988d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz public boolean dragTo(UiObject destObj, int steps) throws UiObjectNotFoundException { 1998d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz Rect srcRect = getVisibleBounds(); 2008d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz Rect dstRect = destObj.getVisibleBounds(); 2018d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz return getInteractionController().swipe(srcRect.centerX(), srcRect.centerY(), 2028d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz dstRect.centerX(), dstRect.centerY(), steps, true); 2038d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz } 2048d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz 2058d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz /** 2068d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz * Performs a drag of this object to arbitrary coordinates. Note that the number of steps 2078d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz * used will influence the drag speed and varying speeds may impact the results. Consider 2088d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz * evaluating different speeds when testing this method. 2098d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz * 2108d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz * @param destX 2118d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz * @param destY 2128d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz * @param steps 2138d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz * @return true of successful 2148d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz * @throws UiObjectNotFoundException 2158d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz * @since API Level 18 2168d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz */ 2178d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz public boolean dragTo(int destX, int destY, int steps) throws UiObjectNotFoundException { 2188d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz Rect srcRect = getVisibleBounds(); 2198d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz return getInteractionController().swipe(srcRect.centerX(), srcRect.centerY(), destX, destY, 2208d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz steps, true); 2218d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz } 2228d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz 2238d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz /** 2243d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Perform the action on the UI element that is represented by this UiObject. Also see 2251893caed0ad4e73b0676f206282d490c2d345316Thanh Le * {@link UiScrollable#scrollToBeginning(int)}, {@link UiScrollable#scrollToEnd(int)}, 2261893caed0ad4e73b0676f206282d490c2d345316Thanh Le * {@link UiScrollable#scrollBackward()}, {@link UiScrollable#scrollForward()}. 2273d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 228467cca7d25dbbf13c14cfd8c2ad38ab8eaf56bdaAdam Momtaz * @param steps indicates the number of injected move steps into the system. Steps are 229467cca7d25dbbf13c14cfd8c2ad38ab8eaf56bdaAdam Momtaz * injected about 5ms apart. So a 100 steps may take about 1/2 second to complete. 2303d50587be8ff021369c90554d814839335b445b0Adam Momtaz * @return true of successful 231e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 232dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 233e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 234e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean swipeUp(int steps) throws UiObjectNotFoundException { 235f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(steps); 2363d50587be8ff021369c90554d814839335b445b0Adam Momtaz Rect rect = getVisibleBounds(); 237e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(rect.height() <= SWIPE_MARGIN_LIMIT * 2) 238e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return false; // too small to swipe 239e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return getInteractionController().swipe(rect.centerX(), 240e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu rect.bottom - SWIPE_MARGIN_LIMIT, rect.centerX(), rect.top + SWIPE_MARGIN_LIMIT, 241e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu steps); 242e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 243e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 244e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 245e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * Perform the action on the UI element that is represented by this object, Also see 2461893caed0ad4e73b0676f206282d490c2d345316Thanh Le * {@link UiScrollable#scrollToBeginning(int)}, {@link UiScrollable#scrollToEnd(int)}, 2471893caed0ad4e73b0676f206282d490c2d345316Thanh Le * {@link UiScrollable#scrollBackward()}, {@link UiScrollable#scrollForward()}. This method will 2481893caed0ad4e73b0676f206282d490c2d345316Thanh Le * perform the swipe gesture over any surface. The targeted UI element does not need to have 2491893caed0ad4e73b0676f206282d490c2d345316Thanh Le * the attribute <code>scrollable</code> set to <code>true</code> for this operation to be 2501893caed0ad4e73b0676f206282d490c2d345316Thanh Le * performed. 2513d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 2523d50587be8ff021369c90554d814839335b445b0Adam Momtaz * @param steps indicates the number of injected move steps into the system. Steps are 253467cca7d25dbbf13c14cfd8c2ad38ab8eaf56bdaAdam Momtaz * injected about 5ms apart. So a 100 steps may take about 1/2 second to complete. 2543d50587be8ff021369c90554d814839335b445b0Adam Momtaz * @return true if successful 255e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 256dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 257e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 258e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean swipeDown(int steps) throws UiObjectNotFoundException { 259f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(steps); 2603d50587be8ff021369c90554d814839335b445b0Adam Momtaz Rect rect = getVisibleBounds(); 261e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(rect.height() <= SWIPE_MARGIN_LIMIT * 2) 262e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return false; // too small to swipe 263e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return getInteractionController().swipe(rect.centerX(), 264e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu rect.top + SWIPE_MARGIN_LIMIT, rect.centerX(), 265e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu rect.bottom - SWIPE_MARGIN_LIMIT, steps); 266e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 267e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 268e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 269e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * Perform the action on the UI element that is represented by this object. Also see 2701893caed0ad4e73b0676f206282d490c2d345316Thanh Le * {@link UiScrollable#scrollToBeginning(int)}, {@link UiScrollable#scrollToEnd(int)}, 2711893caed0ad4e73b0676f206282d490c2d345316Thanh Le * {@link UiScrollable#scrollBackward()}, {@link UiScrollable#scrollForward()}. This method will 2721893caed0ad4e73b0676f206282d490c2d345316Thanh Le * perform the swipe gesture over any surface. The targeted UI element does not need to have the 2731893caed0ad4e73b0676f206282d490c2d345316Thanh Le * attribute <code>scrollable</code> set to <code>true</code> for this operation to be 2741893caed0ad4e73b0676f206282d490c2d345316Thanh Le * performed. 2753d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 2763d50587be8ff021369c90554d814839335b445b0Adam Momtaz * @param steps indicates the number of injected move steps into the system. Steps are 277467cca7d25dbbf13c14cfd8c2ad38ab8eaf56bdaAdam Momtaz * injected about 5ms apart. So a 100 steps may take about 1/2 second to complete. 2783d50587be8ff021369c90554d814839335b445b0Adam Momtaz * @return true if successful 279e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 280dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 281e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 282e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean swipeLeft(int steps) throws UiObjectNotFoundException { 283f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(steps); 2843d50587be8ff021369c90554d814839335b445b0Adam Momtaz Rect rect = getVisibleBounds(); 285e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(rect.width() <= SWIPE_MARGIN_LIMIT * 2) 286e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return false; // too small to swipe 287e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return getInteractionController().swipe(rect.right - SWIPE_MARGIN_LIMIT, 288e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu rect.centerY(), rect.left + SWIPE_MARGIN_LIMIT, rect.centerY(), steps); 289e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 290e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 291e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 292e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * Perform the action on the UI element that is represented by this object. Also see 2931893caed0ad4e73b0676f206282d490c2d345316Thanh Le * {@link UiScrollable#scrollToBeginning(int)}, {@link UiScrollable#scrollToEnd(int)}, 2941893caed0ad4e73b0676f206282d490c2d345316Thanh Le * {@link UiScrollable#scrollBackward()}, {@link UiScrollable#scrollForward()}. This method will 2951893caed0ad4e73b0676f206282d490c2d345316Thanh Le * perform the swipe gesture over any surface. The targeted UI element does not need to have the 2961893caed0ad4e73b0676f206282d490c2d345316Thanh Le * attribute <code>scrollable</code> set to <code>true</code> for this operation to be 2971893caed0ad4e73b0676f206282d490c2d345316Thanh Le * performed. 2983d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 2993d50587be8ff021369c90554d814839335b445b0Adam Momtaz * @param steps indicates the number of injected move steps into the system. Steps are 300467cca7d25dbbf13c14cfd8c2ad38ab8eaf56bdaAdam Momtaz * injected about 5ms apart. So a 100 steps may take about 1/2 second to complete. 3013d50587be8ff021369c90554d814839335b445b0Adam Momtaz * @return true if successful 302e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 303dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 304e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 305e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean swipeRight(int steps) throws UiObjectNotFoundException { 306f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(steps); 3073d50587be8ff021369c90554d814839335b445b0Adam Momtaz Rect rect = getVisibleBounds(); 308e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(rect.width() <= SWIPE_MARGIN_LIMIT * 2) 309e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return false; // too small to swipe 310e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return getInteractionController().swipe(rect.left + SWIPE_MARGIN_LIMIT, 311e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu rect.centerY(), rect.right - SWIPE_MARGIN_LIMIT, rect.centerY(), steps); 312e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 313e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 314e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 3153d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Finds the visible bounds of a partially visible UI element 3163d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 317e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @param node 3187f38ef08d07295967b905a61b2356ff6cdf31159Adam Momtaz * @return null if node is null, else a Rect containing visible bounds 319e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 320e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu private Rect getVisibleBounds(AccessibilityNodeInfo node) { 321e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if (node == null) { 322e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return null; 323e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 324e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 325e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // targeted node's bounds 32623296fc6448cd265fbb45c1fd9041976ae0da274Guang Zhu int w = UiDevice.getInstance().getDisplayWidth(); 32723296fc6448cd265fbb45c1fd9041976ae0da274Guang Zhu int h = UiDevice.getInstance().getDisplayHeight(); 32823296fc6448cd265fbb45c1fd9041976ae0da274Guang Zhu Rect nodeRect = AccessibilityNodeInfoHelper.getVisibleBoundsInScreen(node, w, h); 329e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 330e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // is the targeted node within a scrollable container? 331e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo scrollableParentNode = getScrollableParent(node); 332e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(scrollableParentNode == null) { 333e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // nothing to adjust for so return the node's Rect as is 334e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return nodeRect; 335e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 336e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 337e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // Scrollable parent's visible bounds 3387f38ef08d07295967b905a61b2356ff6cdf31159Adam Momtaz Rect parentRect = AccessibilityNodeInfoHelper 33923296fc6448cd265fbb45c1fd9041976ae0da274Guang Zhu .getVisibleBoundsInScreen(scrollableParentNode, w, h); 340e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // adjust for partial clipping of targeted by parent node if required 341e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu nodeRect.intersect(parentRect); 342e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return nodeRect; 343e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 344e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 345e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 3467f38ef08d07295967b905a61b2356ff6cdf31159Adam Momtaz * Walk the hierarchy up to find a scrollable parent. A scrollable parent 3477f38ef08d07295967b905a61b2356ff6cdf31159Adam Momtaz * indicates that this node may be in a content where it is partially 3487f38ef08d07295967b905a61b2356ff6cdf31159Adam Momtaz * visible due to scrolling. its clickable center maybe invisible and 3497f38ef08d07295967b905a61b2356ff6cdf31159Adam Momtaz * adjustments should be made to the click coordinates. 3503d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 351e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @param node 3521893caed0ad4e73b0676f206282d490c2d345316Thanh Le * @return The accessibility node info. 353e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 354e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu private AccessibilityNodeInfo getScrollableParent(AccessibilityNodeInfo node) { 355e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo parent = node; 356e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu while(parent != null) { 357e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu parent = parent.getParent(); 358e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if (parent != null && parent.isScrollable()) { 359e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return parent; 360e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 361e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 362e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return null; 363e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 364e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 365e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 3663d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Performs a click at the center of the visible bounds of the UI element represented 36746d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * by this UiObject. 3683d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 369e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true id successful else false 370e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 371dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 372e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 373e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean click() throws UiObjectNotFoundException { 374f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(); 3750d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout()); 376e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 377e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 378e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 379e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu Rect rect = getVisibleBounds(node); 3800d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz return getInteractionController().clickAndSync(rect.centerX(), rect.centerY(), 3810d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz mConfig.getActionAcknowledgmentTimeout()); 382e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 383e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 384e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 3853d50587be8ff021369c90554d814839335b445b0Adam Momtaz * See {@link #clickAndWaitForNewWindow(long)} 386a46ac3504426564954292b13380120e8cc6b1527Adam Momtaz * This method is intended to reliably wait for window transitions that would typically take 387a46ac3504426564954292b13380120e8cc6b1527Adam Momtaz * longer than the usual default timeouts. 3883d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 3893d50587be8ff021369c90554d814839335b445b0Adam Momtaz * @return true if the event was triggered, else false 3903d50587be8ff021369c90554d814839335b445b0Adam Momtaz * @throws UiObjectNotFoundException 391dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 3923d50587be8ff021369c90554d814839335b445b0Adam Momtaz */ 393e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean clickAndWaitForNewWindow() throws UiObjectNotFoundException { 394f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(); 395e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return clickAndWaitForNewWindow(WAIT_FOR_WINDOW_TMEOUT); 396e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 397e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 398e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 39946d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * Performs a click at the center of the visible bounds of the UI element represented 40046d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * by this UiObject and waits for window transitions. 40146d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * 4023d50587be8ff021369c90554d814839335b445b0Adam Momtaz * This method differ from {@link UiObject#click()} only in that this method waits for a 40346d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * a new window transition as a result of the click. Some examples of a window transition: 404e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * <li>launching a new activity</li> 405e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * <li>bringing up a pop-up menu</li> 406e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * <li>bringing up a dialog</li> 407e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * 4083d50587be8ff021369c90554d814839335b445b0Adam Momtaz * @param timeout timeout before giving up on waiting for a new window 409e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if the event was triggered, else false 410e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 411dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 412e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 413e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean clickAndWaitForNewWindow(long timeout) throws UiObjectNotFoundException { 414f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(timeout); 4150d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout()); 416e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 417e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 418e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 419e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu Rect rect = getVisibleBounds(node); 4200d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz return getInteractionController().clickAndWaitForNewWindow(rect.centerX(), rect.centerY(), 4210d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz mConfig.getActionAcknowledgmentTimeout()); 422e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 423e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 424e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 4253d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Clicks the top and left corner of the UI element 4263d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 427e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true on success 4281893caed0ad4e73b0676f206282d490c2d345316Thanh Le * @throws UiObjectNotFoundException 429dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 430e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 431e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean clickTopLeft() throws UiObjectNotFoundException { 432f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(); 4330d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout()); 434e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 435e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 436e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 437e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu Rect rect = getVisibleBounds(node); 4381dc7d12406947faaee8454c6efb2a0631f5da573Adam Momtaz return getInteractionController().clickNoSync(rect.left + 5, rect.top + 5); 439e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 440e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 441e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 4423d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Long clicks bottom and right corner of the UI element 4433d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 444e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if operation was successful 445e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 446dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 447e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 448e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean longClickBottomRight() throws UiObjectNotFoundException { 449f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(); 4500d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout()); 451e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 452e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 453e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 454e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu Rect rect = getVisibleBounds(node); 4551dc7d12406947faaee8454c6efb2a0631f5da573Adam Momtaz return getInteractionController().longTapNoSync(rect.right - 5, rect.bottom - 5); 456e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 457e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 458e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 4593d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Clicks the bottom and right corner of the UI element 4603d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 461e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true on success 4621893caed0ad4e73b0676f206282d490c2d345316Thanh Le * @throws UiObjectNotFoundException 463dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 464e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 465e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean clickBottomRight() throws UiObjectNotFoundException { 466f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(); 4670d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout()); 468e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 469e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 470e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 471e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu Rect rect = getVisibleBounds(node); 4721dc7d12406947faaee8454c6efb2a0631f5da573Adam Momtaz return getInteractionController().clickNoSync(rect.right - 5, rect.bottom - 5); 473e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 474e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 475e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 4763d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Long clicks the center of the visible bounds of the UI element 4773d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 478e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if operation was successful 479e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 480dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 481e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 482e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean longClick() throws UiObjectNotFoundException { 483f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(); 4840d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout()); 485e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 486e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 487e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 488e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu Rect rect = getVisibleBounds(node); 4891dc7d12406947faaee8454c6efb2a0631f5da573Adam Momtaz return getInteractionController().longTapNoSync(rect.centerX(), rect.centerY()); 490e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 491e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 492e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 4933d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Long clicks on the top and left corner of the UI element 4943d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 495e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if operation was successful 496e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 497dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 498e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 499e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean longClickTopLeft() throws UiObjectNotFoundException { 500f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(); 5010d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout()); 502e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 503e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 504e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 505e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu Rect rect = getVisibleBounds(node); 5061dc7d12406947faaee8454c6efb2a0631f5da573Adam Momtaz return getInteractionController().longTapNoSync(rect.left + 5, rect.top + 5); 507e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 508e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 509e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 5103d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Reads the <code>text</code> property of the UI element 5113d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 512e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return text value of the current node represented by this UiObject 513e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException if no match could be found 514dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 515e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 516e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public String getText() throws UiObjectNotFoundException { 517f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(); 5180d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout()); 519e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 520e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 521e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 522e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu String retVal = safeStringReturn(node.getText()); 523e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu Log.d(LOG_TAG, String.format("getText() = %s", retVal)); 524e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return retVal; 525e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 526e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 527e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 52897835f3a7c80b147136c44c175eb9e6a4261fd92Adam Momtaz * Reads the <code>className</code> property of the UI element 52997835f3a7c80b147136c44c175eb9e6a4261fd92Adam Momtaz * 53097835f3a7c80b147136c44c175eb9e6a4261fd92Adam Momtaz * @return class name of the current node represented by this UiObject 53197835f3a7c80b147136c44c175eb9e6a4261fd92Adam Momtaz * @throws UiObjectNotFoundException if no match could be found 53297835f3a7c80b147136c44c175eb9e6a4261fd92Adam Momtaz * @since API Level 18 53397835f3a7c80b147136c44c175eb9e6a4261fd92Adam Momtaz */ 53497835f3a7c80b147136c44c175eb9e6a4261fd92Adam Momtaz public String getClassName() throws UiObjectNotFoundException { 53597835f3a7c80b147136c44c175eb9e6a4261fd92Adam Momtaz Tracer.trace(); 5360d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout()); 53797835f3a7c80b147136c44c175eb9e6a4261fd92Adam Momtaz if(node == null) { 53897835f3a7c80b147136c44c175eb9e6a4261fd92Adam Momtaz throw new UiObjectNotFoundException(getSelector().toString()); 53997835f3a7c80b147136c44c175eb9e6a4261fd92Adam Momtaz } 54097835f3a7c80b147136c44c175eb9e6a4261fd92Adam Momtaz String retVal = safeStringReturn(node.getClassName()); 54197835f3a7c80b147136c44c175eb9e6a4261fd92Adam Momtaz Log.d(LOG_TAG, String.format("getClassName() = %s", retVal)); 54297835f3a7c80b147136c44c175eb9e6a4261fd92Adam Momtaz return retVal; 54397835f3a7c80b147136c44c175eb9e6a4261fd92Adam Momtaz } 54497835f3a7c80b147136c44c175eb9e6a4261fd92Adam Momtaz 54597835f3a7c80b147136c44c175eb9e6a4261fd92Adam Momtaz /** 5463d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Reads the <code>content_desc</code> property of the UI element 5473d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 548e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return value of node attribute "content_desc" 549e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 550dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 551e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 552e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public String getContentDescription() throws UiObjectNotFoundException { 553f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(); 5540d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout()); 555e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 556e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 557e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 558e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return safeStringReturn(node.getContentDescription()); 559e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 560e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 561e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 56246d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * Sets the text in an editable field, after clearing the field's content. 56346d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * 56446d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * The {@link UiSelector} selector of this object must reference a UI element that is editable. 56546d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * 56646d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * When you call this method, the method first simulates a {@link #click()} on 56746d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * editable field to set focus. The method then clears the field's contents 56846d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * and injects your specified text into the field. 5693d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 57046d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * If you want to capture the original contents of the field, call {@link #getText()} first. 57146d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * You can then modify the text and use this method to update the field. 57246d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * 57346d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * @param text string to set 574e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if operation is successful 575e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 576dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 577e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 578e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean setText(String text) throws UiObjectNotFoundException { 579f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(text); 580e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu clearTextField(); 581e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return getInteractionController().sendText(text); 582e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 583e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 584e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 58546d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * Clears the existing text contents in an editable field. 58646d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * 58746d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * The {@link UiSelector} of this object must reference a UI element that is editable. 58846d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * 58946d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * When you call this method, the method first sets focus at the start edge of the field. 59046d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * The method then simulates a long-press to select the existing text, and deletes the 59146d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * selected text. 59246d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * 59346d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * If a "Select-All" option is displayed, the method will automatically attempt to use it 59446d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * to ensure full text selection. 59546d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * 59646d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * Note that it is possible that not all the text in the field is selected; for example, 59746d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * if the text contains separators such as spaces, slashes, at symbol etc. 59846d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * Also, not all editable fields support the long-press functionality. 59946d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * 600e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 601dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 602e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 603e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public void clearTextField() throws UiObjectNotFoundException { 604f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(); 605e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // long click left + center 6060d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout()); 607e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 608e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 609e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 610e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu Rect rect = getVisibleBounds(node); 6111dc7d12406947faaee8454c6efb2a0631f5da573Adam Momtaz getInteractionController().longTapNoSync(rect.left + 20, rect.centerY()); 612e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // check if the edit menu is open 6134ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz UiObject selectAll = new UiObject(new UiSelector().descriptionContains("Select all")); 614e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(selectAll.waitForExists(50)) 615e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu selectAll.click(); 616e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // wait for the selection 617e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu SystemClock.sleep(250); 618e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // delete it 619e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu getInteractionController().sendKey(KeyEvent.KEYCODE_DEL, 0); 620e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 621e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 622e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 6233d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Check if the UI element's <code>checked</code> property is currently true 6243d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 625e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if it is else false 626dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 627e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 628e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean isChecked() throws UiObjectNotFoundException { 629f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(); 6300d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout()); 631e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 632e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 633e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 634e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return node.isChecked(); 635e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 636e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 637e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 6383d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Check if the UI element's <code>selected</code> property is currently true 6393d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 640e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if it is else false 641e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 642dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 643e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 644e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean isSelected() throws UiObjectNotFoundException { 645f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(); 6460d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout()); 647e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 648e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 649e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 650e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return node.isSelected(); 651e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 652e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 653e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 6543d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Check if the UI element's <code>checkable</code> property is currently true 6553d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 656e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if it is else false 657e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 658dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 659e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 660e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean isCheckable() throws UiObjectNotFoundException { 661f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(); 6620d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout()); 663e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 664e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 665e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 666e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return node.isCheckable(); 667e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 668e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 669e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 6703d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Check if the UI element's <code>enabled</code> property is currently true 6713d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 672e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if it is else false 673e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 674dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 675e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 676e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean isEnabled() throws UiObjectNotFoundException { 677f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(); 6780d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout()); 679e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 680e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 681e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 682e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return node.isEnabled(); 683e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 684e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 685e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 6863d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Check if the UI element's <code>clickable</code> property is currently true 6873d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 688e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if it is else false 689e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 690dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 691e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 692e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean isClickable() throws UiObjectNotFoundException { 693f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(); 6940d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout()); 695e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 696e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 697e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 698e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return node.isClickable(); 699e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 700e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 701e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 7023d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Check if the UI element's <code>focused</code> property is currently true 7033d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 704e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if it is else false 705e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 706dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 707e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 708e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean isFocused() throws UiObjectNotFoundException { 709f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(); 7100d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout()); 711e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 712e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 713e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 714e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return node.isFocused(); 715e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 716e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 717e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 7183d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Check if the UI element's <code>focusable</code> property is currently true 7193d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 720e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if it is else false 721e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 722dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 723e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 724e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean isFocusable() throws UiObjectNotFoundException { 725f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(); 7260d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout()); 727e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 728e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 729e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 730e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return node.isFocusable(); 731e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 732e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 733e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 7343d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Check if the UI element's <code>scrollable</code> property is currently true 7353d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 736e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if it is else false 737e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 738dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 739e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 740e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean isScrollable() throws UiObjectNotFoundException { 741f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(); 7420d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout()); 743e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 744e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 745e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 746e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return node.isScrollable(); 747e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 748e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 749e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 7503d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Check if the UI element's <code>long-clickable</code> property is currently true 7513d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 752e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if it is else false 753e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 754dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 755e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 756e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean isLongClickable() throws UiObjectNotFoundException { 757f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(); 7580d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout()); 759e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 760e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 761e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 762e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return node.isLongClickable(); 763e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 764e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 765e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 7663d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Reads the UI element's <code>package</code> property 7673d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 7683d50587be8ff021369c90554d814839335b445b0Adam Momtaz * @return true if it is else false 769e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 770dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 771e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 772e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public String getPackageName() throws UiObjectNotFoundException { 773f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(); 7740d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout()); 775e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 776e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 777e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 778e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return safeStringReturn(node.getPackageName()); 779e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 780e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 781e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 78246d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * Returns the visible bounds of the UI element. 78346d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * 78446d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * If a portion of the UI element is visible, only the bounds of the visible portion are 78546d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * reported. 7863d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 787e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return Rect 788e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 7891893caed0ad4e73b0676f206282d490c2d345316Thanh Le * @see {@link #getBounds()} 79079693ede92636fe6f3a6ec4dc049a438fd9504ffGuang Zhu * @since API Level 17 791e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 7923d50587be8ff021369c90554d814839335b445b0Adam Momtaz public Rect getVisibleBounds() throws UiObjectNotFoundException { 793f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(); 7940d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout()); 795e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 796e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 797e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 798e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return getVisibleBounds(node); 799e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 800e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 801e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 80246d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * Returns the UI element's <code>bounds</code> property. See {@link #getVisibleBounds()} 8033d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 8043d50587be8ff021369c90554d814839335b445b0Adam Momtaz * @return Rect 8053d50587be8ff021369c90554d814839335b445b0Adam Momtaz * @throws UiObjectNotFoundException 806dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 8073d50587be8ff021369c90554d814839335b445b0Adam Momtaz */ 8083d50587be8ff021369c90554d814839335b445b0Adam Momtaz public Rect getBounds() throws UiObjectNotFoundException { 809f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(); 8100d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout()); 8113d50587be8ff021369c90554d814839335b445b0Adam Momtaz if(node == null) { 8123d50587be8ff021369c90554d814839335b445b0Adam Momtaz throw new UiObjectNotFoundException(getSelector().toString()); 8133d50587be8ff021369c90554d814839335b445b0Adam Momtaz } 8143d50587be8ff021369c90554d814839335b445b0Adam Momtaz Rect nodeRect = new Rect(); 8153d50587be8ff021369c90554d814839335b445b0Adam Momtaz node.getBoundsInScreen(nodeRect); 8163d50587be8ff021369c90554d814839335b445b0Adam Momtaz 8173d50587be8ff021369c90554d814839335b445b0Adam Momtaz return nodeRect; 8183d50587be8ff021369c90554d814839335b445b0Adam Momtaz } 8193d50587be8ff021369c90554d814839335b445b0Adam Momtaz 8203d50587be8ff021369c90554d814839335b445b0Adam Momtaz /** 82146d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * Waits a specified length of time for a UI element to become visible. 82246d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * 82346d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * This method waits until the UI element becomes visible on the display, or 82446d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * until the timeout has elapsed. You can use this method in situations where 82546d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * the content that you want to select is not immediately displayed. 8263d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 82746d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * @param timeout the amount of time to wait (in milliseconds) 82846d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * @return true if the UI element is displayed, else false if timeout elapsed while waiting 829dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 830e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 831e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean waitForExists(long timeout) { 832f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(timeout); 833e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(findAccessibilityNodeInfo(timeout) != null) { 834e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return true; 835e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 836e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return false; 837e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 838e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 839e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 84046d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * Waits a specified length of time for a UI element to become undetectable. 8413d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 84246d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * This method waits until a UI element is no longer matchable, or until the 84346d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * timeout has elapsed. 84446d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * 84546d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * A UI element becomes undetectable when the {@link UiSelector} of the object is 84646d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * unable to find a match because the element has either changed its state or is no 84746d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * longer displayed. 84846d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * 84946d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * You can use this method when attempting to wait for some long operation 85046d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * to compete, such as downloading a large file or connecting to a remote server. 85146d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * 85246d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * @param timeout time to wait (in milliseconds) 85346d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * @return true if the element is gone before timeout elapsed, else false if timeout elapsed 85446d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * but a matching element is still found. 855dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 856e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 857e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean waitUntilGone(long timeout) { 858f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(timeout); 859e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu long startMills = SystemClock.uptimeMillis(); 860e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu long currentMills = 0; 861e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu while (currentMills <= timeout) { 862e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(findAccessibilityNodeInfo(0) == null) 863e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return true; 864e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu currentMills = SystemClock.uptimeMillis() - startMills; 865e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(timeout > 0) 866e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu SystemClock.sleep(WAIT_FOR_SELECTOR_POLL); 867e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 868e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return false; 869e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 870e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 871e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 87246d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * Check if UI element exists. 87346d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * 874e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * This methods performs a {@link #waitForExists(long)} with zero timeout. This 875e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * basically returns immediately whether the UI element represented by this UiObject 876e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * exists or not. If you need to wait longer for this UI element, then see 877e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * {@link #waitForExists(long)}. 8783d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 879e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if the UI element represented by this UiObject does exist 880dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 881e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 882e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean exists() { 883f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(); 884e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return waitForExists(0); 885e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 886e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 887e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu private String safeStringReturn(CharSequence cs) { 888e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(cs == null) 889e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return ""; 890e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return cs.toString(); 891e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 892c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz 893c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz /** 894c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * PinchOut generates a 2 pointer gesture where each pointer is moving from the center out 895c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * away from each other diagonally towards the edges of the current UI element represented by 896c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * this UiObject. 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. 9001078ab1070411af45d5e8ec3b56abec6789e7722Guang Zhu * @return <code>true</code> if all touch events for this gesture are injected successfully, 9011078ab1070411af45d5e8ec3b56abec6789e7722Guang Zhu * <code>false</code> otherwise 902c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * @throws UiObjectNotFoundException 903c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * @since API Level 18 904c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz */ 9051078ab1070411af45d5e8ec3b56abec6789e7722Guang Zhu public boolean pinchOut(int percent, int steps) throws UiObjectNotFoundException { 906c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz // make value between 1 and 100 907c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz percent = (percent < 0) ? 1 : (percent > 100) ? 100 : percent; 908c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz float percentage = percent / 100f; 909c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz 9100d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout()); 911c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz if (node == null) { 912c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz throw new UiObjectNotFoundException(getSelector().toString()); 913c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz } 914c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz 915c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz Rect rect = getVisibleBounds(node); 916c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz if (rect.width() <= FINGER_TOUCH_HALF_WIDTH * 2) 917c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz throw new IllegalStateException("Object width is too small for operation"); 918c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz 919c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz // start from the same point at the center of the control 920c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz Point startPoint1 = new Point(rect.centerX() - FINGER_TOUCH_HALF_WIDTH, rect.centerY()); 921c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz Point startPoint2 = new Point(rect.centerX() + FINGER_TOUCH_HALF_WIDTH, rect.centerY()); 922c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz 923c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz // End at the top-left and bottom-right corners of the control 924c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz Point endPoint1 = new Point(rect.centerX() - (int)((rect.width()/2) * percentage), 925c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz rect.centerY()); 926c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz Point endPoint2 = new Point(rect.centerX() + (int)((rect.width()/2) * percentage), 927c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz rect.centerY()); 928c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz 9291078ab1070411af45d5e8ec3b56abec6789e7722Guang Zhu return performTwoPointerGesture(startPoint1, startPoint2, endPoint1, endPoint2, steps); 930c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz } 931c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz 932c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz /** 933c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * PinchIn generates a 2 pointer gesture where each pointer is moving towards the other 934c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * diagonally from the edges of the current UI element represented by this UiObject, until the 935c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * center. 936c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * @param percent of the object's diagonal length to use for the pinch 937c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * @param steps indicates the number of injected move steps into the system. Steps are 938c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * injected about 5ms apart. So a 100 steps may take about 1/2 second to complete. 9391078ab1070411af45d5e8ec3b56abec6789e7722Guang Zhu * @return <code>true</code> if all touch events for this gesture are injected successfully, 9401078ab1070411af45d5e8ec3b56abec6789e7722Guang Zhu * <code>false</code> otherwise 941c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * @throws UiObjectNotFoundException 942c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * @since API Level 18 943c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz */ 9441078ab1070411af45d5e8ec3b56abec6789e7722Guang Zhu public boolean pinchIn(int percent, int steps) throws UiObjectNotFoundException { 945c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz // make value between 1 and 100 946c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz percent = (percent < 0) ? 0 : (percent > 100) ? 100 : percent; 947c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz float percentage = percent / 100f; 948c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz 9490d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout()); 950c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz if (node == null) { 951c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz throw new UiObjectNotFoundException(getSelector().toString()); 952c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz } 953c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz 954c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz Rect rect = getVisibleBounds(node); 955c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz if (rect.width() <= FINGER_TOUCH_HALF_WIDTH * 2) 956c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz throw new IllegalStateException("Object width is too small for operation"); 957c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz 958c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz Point startPoint1 = new Point(rect.centerX() - (int)((rect.width()/2) * percentage), 959c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz rect.centerY()); 960c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz Point startPoint2 = new Point(rect.centerX() + (int)((rect.width()/2) * percentage), 961c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz rect.centerY()); 962c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz 963c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz Point endPoint1 = new Point(rect.centerX() - FINGER_TOUCH_HALF_WIDTH, rect.centerY()); 964c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz Point endPoint2 = new Point(rect.centerX() + FINGER_TOUCH_HALF_WIDTH, rect.centerY()); 965c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz 9661078ab1070411af45d5e8ec3b56abec6789e7722Guang Zhu return performTwoPointerGesture(startPoint1, startPoint2, endPoint1, endPoint2, steps); 967c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz } 968c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz 969c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz /** 970c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * Generates a 2 pointer gesture from an arbitrary starting and ending points. 971c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * 972c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * @param startPoint1 start point of pointer 1 973c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * @param startPoint2 start point of pointer 2 974c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * @param endPoint1 end point of pointer 1 975c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * @param endPoint2 end point of pointer 2 976c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * @param steps indicates the number of injected move steps into the system. Steps are 977c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * injected about 5ms apart. So a 100 steps may take about 1/2 second to complete. 9781078ab1070411af45d5e8ec3b56abec6789e7722Guang Zhu * @return <code>true</code> if all touch events for this gesture are injected successfully, 9791078ab1070411af45d5e8ec3b56abec6789e7722Guang Zhu * <code>false</code> otherwise 980c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * @since API Level 18 981c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz */ 9821078ab1070411af45d5e8ec3b56abec6789e7722Guang Zhu public boolean performTwoPointerGesture(Point startPoint1, Point startPoint2, Point endPoint1, 983c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz Point endPoint2, int steps) { 984c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz 985c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz // avoid a divide by zero 986c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz if(steps == 0) 987c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz steps = 1; 988c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz 989c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz final float stepX1 = (endPoint1.x - startPoint1.x) / steps; 990c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz final float stepY1 = (endPoint1.y - startPoint1.y) / steps; 991c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz final float stepX2 = (endPoint2.x - startPoint2.x) / steps; 992c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz final float stepY2 = (endPoint2.y - startPoint2.y) / steps; 993c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz 994c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz int eventX1, eventY1, eventX2, eventY2; 995c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz eventX1 = startPoint1.x; 996c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz eventY1 = startPoint1.y; 997c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz eventX2 = startPoint2.x; 998c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz eventY2 = startPoint2.y; 999c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz 1000c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz // allocate for steps plus first down and last up 1001c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz PointerCoords[] points1 = new PointerCoords[steps + 2]; 1002c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz PointerCoords[] points2 = new PointerCoords[steps + 2]; 1003c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz 1004c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz // Include the first and last touch downs in the arrays of steps 1005c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz for (int i = 0; i < steps + 1; i++) { 1006c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz PointerCoords p1 = new PointerCoords(); 1007c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz p1.x = eventX1; 1008c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz p1.y = eventY1; 1009c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz p1.pressure = 1; 1010c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz p1.size = 1; 1011c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz points1[i] = p1; 1012c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz 1013c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz PointerCoords p2 = new PointerCoords(); 1014c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz p2.x = eventX2; 1015c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz p2.y = eventY2; 1016c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz p2.pressure = 1; 1017c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz p2.size = 1; 1018c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz points2[i] = p2; 1019c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz 1020c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz eventX1 += stepX1; 1021c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz eventY1 += stepY1; 1022c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz eventX2 += stepX2; 1023c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz eventY2 += stepY2; 1024c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz } 1025c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz 1026c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz // ending pointers coordinates 1027c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz PointerCoords p1 = new PointerCoords(); 1028c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz p1.x = endPoint1.x; 1029c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz p1.y = endPoint1.y; 1030c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz p1.pressure = 1; 1031c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz p1.size = 1; 1032c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz points1[steps + 1] = p1; 1033c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz 1034c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz PointerCoords p2 = new PointerCoords(); 1035c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz p2.x = endPoint2.x; 1036c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz p2.y = endPoint2.y; 1037c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz p2.pressure = 1; 1038c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz p2.size = 1; 1039c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz points2[steps + 1] = p2; 1040c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz 10411078ab1070411af45d5e8ec3b56abec6789e7722Guang Zhu return performMultiPointerGesture(points1, points2); 1042c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz } 1043c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz 1044c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz /** 1045c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * Performs a multi-touch gesture 1046c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * 1047c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * Takes a series of touch coordinates for at least 2 pointers. Each pointer must have 1048c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * all of its touch steps defined in an array of {@link PointerCoords}. By having the ability 1049c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * to specify the touch points along the path of a pointer, the caller is able to specify 1050c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * complex gestures like circles, irregular shapes etc, where each pointer may take a 1051c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * different path. 1052c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * 1053c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * To create a single point on a pointer's touch path 1054c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * <code> 1055c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * PointerCoords p = new PointerCoords(); 1056c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * p.x = stepX; 1057c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * p.y = stepY; 1058c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * p.pressure = 1; 1059c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * p.size = 1; 1060c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * </code> 1061c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * @param touches each array of {@link PointerCoords} constitute a single pointer's touch path. 1062c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * Multiple {@link PointerCoords} arrays constitute multiple pointers, each with its own 1063c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * path. Each {@link PointerCoords} in an array constitute a point on a pointer's path. 10641078ab1070411af45d5e8ec3b56abec6789e7722Guang Zhu * @return <code>true</code> if all touch events for this gesture are injected successfully, 10651078ab1070411af45d5e8ec3b56abec6789e7722Guang Zhu * <code>false</code> otherwise 1066c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * @since API Level 18 1067c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz */ 10681078ab1070411af45d5e8ec3b56abec6789e7722Guang Zhu public boolean performMultiPointerGesture(PointerCoords[] ...touches) { 10691078ab1070411af45d5e8ec3b56abec6789e7722Guang Zhu return getInteractionController().performMultiPointerGesture(touches); 1070c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz } 1071b4671570eb1caa88c7b6042f81f1ca3a2cb6a916Guang Zhu} 1072