UiObject.java revision 9ebf91aa923d2424298cb908a79dd03aefbf0a8f
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/** 28445e82ee022c484166ce7175973827f591ff2ea7quddusc * A UiObject is a representation of a view. It is not in any way directly bound to a 29445e82ee022c484166ce7175973827f591ff2ea7quddusc * view as an object reference. A UiObject contains information to help it 30445e82ee022c484166ce7175973827f591ff2ea7quddusc * locate a matching view at runtime based on the {@link UiSelector} properties specified in 31445e82ee022c484166ce7175973827f591ff2ea7quddusc * its constructor. Once you create an instance of a UiObject, it can 32445e82ee022c484166ce7175973827f591ff2ea7quddusc * be reused for different views that match the selector criteria. 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 /** 72445e82ee022c484166ce7175973827f591ff2ea7quddusc * Constructs a UiObject to represent a view that matches the specified 73445e82ee022c484166ce7175973827f591ff2ea7quddusc * selector criteria. 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, 105445e82ee022c484166ce7175973827f591ff2ea7quddusc * 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 /** 114445e82ee022c484166ce7175973827f591ff2ea7quddusc * Creates a new UiObject for a child view that is under the present UiObject. 1153d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 116445e82ee022c484166ce7175973827f591ff2ea7quddusc * @param selector for child view to match 117445e82ee022c484166ce7175973827f591ff2ea7quddusc * @return a new UiObject representing the child view 118dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 119e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 1204ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz public UiObject getChild(UiSelector selector) throws UiObjectNotFoundException { 121f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(selector); 1224ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz return new UiObject(getSelector().childSelector(selector)); 123e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 124e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 125e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 126445e82ee022c484166ce7175973827f591ff2ea7quddusc * Creates a new UiObject for a sibling view or a child of the sibling view, 127445e82ee022c484166ce7175973827f591ff2ea7quddusc * relative to the present UiObject. 1283d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 129445e82ee022c484166ce7175973827f591ff2ea7quddusc * @param selector for a sibling view or children of the sibling view 130445e82ee022c484166ce7175973827f591ff2ea7quddusc * @return a new UiObject representing the matched view 131e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 132dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 133e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 1344ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz public UiObject getFromParent(UiSelector selector) throws UiObjectNotFoundException { 135f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(selector); 1364ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz return new UiObject(getSelector().fromParent(selector)); 137e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 138e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 139e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 140445e82ee022c484166ce7175973827f591ff2ea7quddusc * Counts the child views immediately under the present UiObject. 1413d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 142445e82ee022c484166ce7175973827f591ff2ea7quddusc * @return the count of child views. 143e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 144dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 145e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 146e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public int getChildCount() throws UiObjectNotFoundException { 147f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(); 1480d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout()); 149e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 150e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 151e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 152e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return node.getChildCount(); 153e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 154e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 155e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 156445e82ee022c484166ce7175973827f591ff2ea7quddusc * Finds a matching UI element in the accessibility hierarchy, by 157445e82ee022c484166ce7175973827f591ff2ea7quddusc * using the selector for this UiObject. 1583d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 159e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @param timeout in milliseconds 160e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return AccessibilityNodeInfo if found else null 161dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 162e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 163e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu protected AccessibilityNodeInfo findAccessibilityNodeInfo(long timeout) { 164e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo node = null; 165bb36257f15f090966e2aeb9fd4f092e1a54722b1Adam Momtaz long startMills = SystemClock.uptimeMillis(); 166bb36257f15f090966e2aeb9fd4f092e1a54722b1Adam Momtaz long currentMills = 0; 167bb36257f15f090966e2aeb9fd4f092e1a54722b1Adam Momtaz while (currentMills <= timeout) { 168e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu node = getQueryController().findAccessibilityNodeInfo(getSelector()); 169bb36257f15f090966e2aeb9fd4f092e1a54722b1Adam Momtaz if (node != null) { 170bb36257f15f090966e2aeb9fd4f092e1a54722b1Adam Momtaz break; 171bb36257f15f090966e2aeb9fd4f092e1a54722b1Adam Momtaz } else { 172bb36257f15f090966e2aeb9fd4f092e1a54722b1Adam Momtaz // does nothing if we're reentering another runWatchers() 173bb36257f15f090966e2aeb9fd4f092e1a54722b1Adam Momtaz UiDevice.getInstance().runWatchers(); 174bb36257f15f090966e2aeb9fd4f092e1a54722b1Adam Momtaz } 175bb36257f15f090966e2aeb9fd4f092e1a54722b1Adam Momtaz currentMills = SystemClock.uptimeMillis() - startMills; 176bb36257f15f090966e2aeb9fd4f092e1a54722b1Adam Momtaz if(timeout > 0) { 177bb36257f15f090966e2aeb9fd4f092e1a54722b1Adam Momtaz SystemClock.sleep(WAIT_FOR_SELECTOR_POLL); 178e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 179e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 180e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return node; 181e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 182e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 183e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 184445e82ee022c484166ce7175973827f591ff2ea7quddusc * Drags this object to a destination UiObject. 185445e82ee022c484166ce7175973827f591ff2ea7quddusc * The number of steps specified in your input parameter can influence the 186445e82ee022c484166ce7175973827f591ff2ea7quddusc * drag speed, and varying speeds may impact the results. Consider 187445e82ee022c484166ce7175973827f591ff2ea7quddusc * evaluating different speeds when using this method in your tests. 1888d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz * 189445e82ee022c484166ce7175973827f591ff2ea7quddusc * @param destObj the destination UiObject. 190445e82ee022c484166ce7175973827f591ff2ea7quddusc * @param steps usually 40 steps. You can increase or decrease the steps to change the speed. 191445e82ee022c484166ce7175973827f591ff2ea7quddusc * @return true if successful 1928d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz * @throws UiObjectNotFoundException 1938d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz * @since API Level 18 1948d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz */ 1958d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz public boolean dragTo(UiObject destObj, int steps) throws UiObjectNotFoundException { 1968d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz Rect srcRect = getVisibleBounds(); 1978d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz Rect dstRect = destObj.getVisibleBounds(); 1988d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz return getInteractionController().swipe(srcRect.centerX(), srcRect.centerY(), 1998d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz dstRect.centerX(), dstRect.centerY(), steps, true); 2008d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz } 2018d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz 2028d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz /** 203445e82ee022c484166ce7175973827f591ff2ea7quddusc * Drags this object to arbitrary coordinates. 204445e82ee022c484166ce7175973827f591ff2ea7quddusc * The number of steps specified in your input parameter can influence the 205445e82ee022c484166ce7175973827f591ff2ea7quddusc * drag speed, and varying speeds may impact the results. Consider 206445e82ee022c484166ce7175973827f591ff2ea7quddusc * evaluating different speeds when using this method in your tests. 2078d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz * 208445e82ee022c484166ce7175973827f591ff2ea7quddusc * @param destX the X-axis coordinate. 209445e82ee022c484166ce7175973827f591ff2ea7quddusc * @param destY the Y-axis coordinate. 210445e82ee022c484166ce7175973827f591ff2ea7quddusc * @param steps usually 40 steps. You can increase or decrease the steps to change the speed. 211445e82ee022c484166ce7175973827f591ff2ea7quddusc * @return true if successful 2128d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz * @throws UiObjectNotFoundException 2138d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz * @since API Level 18 2148d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz */ 2158d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz public boolean dragTo(int destX, int destY, int steps) throws UiObjectNotFoundException { 2168d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz Rect srcRect = getVisibleBounds(); 2178d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz return getInteractionController().swipe(srcRect.centerX(), srcRect.centerY(), destX, destY, 2188d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz steps, true); 2198d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz } 2208d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz 2218d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz /** 222445e82ee022c484166ce7175973827f591ff2ea7quddusc * Performs the swipe up action on the UiObject. 223445e82ee022c484166ce7175973827f591ff2ea7quddusc * See also: 224445e82ee022c484166ce7175973827f591ff2ea7quddusc * <ul> 225445e82ee022c484166ce7175973827f591ff2ea7quddusc * <li>{@link UiScrollable#scrollToBeginning(int)}</li> 226445e82ee022c484166ce7175973827f591ff2ea7quddusc * <li>{@link UiScrollable#scrollToEnd(int)}</li> 227445e82ee022c484166ce7175973827f591ff2ea7quddusc * <li>{@link UiScrollable#scrollBackward()}</li> 228445e82ee022c484166ce7175973827f591ff2ea7quddusc * <li>{@link UiScrollable#scrollForward()}</li> 229445e82ee022c484166ce7175973827f591ff2ea7quddusc * </ul> 2303d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 231467cca7d25dbbf13c14cfd8c2ad38ab8eaf56bdaAdam Momtaz * @param steps indicates the number of injected move steps into the system. Steps are 232467cca7d25dbbf13c14cfd8c2ad38ab8eaf56bdaAdam Momtaz * injected about 5ms apart. So a 100 steps may take about 1/2 second to complete. 2333d50587be8ff021369c90554d814839335b445b0Adam Momtaz * @return true of successful 234e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 235dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 236e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 237e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean swipeUp(int steps) throws UiObjectNotFoundException { 238f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(steps); 2393d50587be8ff021369c90554d814839335b445b0Adam Momtaz Rect rect = getVisibleBounds(); 240e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(rect.height() <= SWIPE_MARGIN_LIMIT * 2) 241e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return false; // too small to swipe 242e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return getInteractionController().swipe(rect.centerX(), 243e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu rect.bottom - SWIPE_MARGIN_LIMIT, rect.centerX(), rect.top + SWIPE_MARGIN_LIMIT, 244e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu steps); 245e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 246e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 247e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 248445e82ee022c484166ce7175973827f591ff2ea7quddusc * Performs the swipe down action on the UiObject. 249445e82ee022c484166ce7175973827f591ff2ea7quddusc * The swipe gesture can be performed over any surface. The targeted 250445e82ee022c484166ce7175973827f591ff2ea7quddusc * UI element does not need to be scrollable. 251445e82ee022c484166ce7175973827f591ff2ea7quddusc * See also: 252445e82ee022c484166ce7175973827f591ff2ea7quddusc * <ul> 253445e82ee022c484166ce7175973827f591ff2ea7quddusc * <li>{@link UiScrollable#scrollToBeginning(int)}</li> 254445e82ee022c484166ce7175973827f591ff2ea7quddusc * <li>{@link UiScrollable#scrollToEnd(int)}</li> 255445e82ee022c484166ce7175973827f591ff2ea7quddusc * <li>{@link UiScrollable#scrollBackward()}</li> 256445e82ee022c484166ce7175973827f591ff2ea7quddusc * <li>{@link UiScrollable#scrollForward()}</li> 257445e82ee022c484166ce7175973827f591ff2ea7quddusc * </ul> 2583d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 2593d50587be8ff021369c90554d814839335b445b0Adam Momtaz * @param steps indicates the number of injected move steps into the system. Steps are 260467cca7d25dbbf13c14cfd8c2ad38ab8eaf56bdaAdam Momtaz * injected about 5ms apart. So a 100 steps may take about 1/2 second to complete. 2613d50587be8ff021369c90554d814839335b445b0Adam Momtaz * @return true if successful 262e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 263dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 264e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 265e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean swipeDown(int steps) throws UiObjectNotFoundException { 266f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(steps); 2673d50587be8ff021369c90554d814839335b445b0Adam Momtaz Rect rect = getVisibleBounds(); 268e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(rect.height() <= SWIPE_MARGIN_LIMIT * 2) 269e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return false; // too small to swipe 270e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return getInteractionController().swipe(rect.centerX(), 271e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu rect.top + SWIPE_MARGIN_LIMIT, rect.centerX(), 272e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu rect.bottom - SWIPE_MARGIN_LIMIT, steps); 273e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 274e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 275e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 276445e82ee022c484166ce7175973827f591ff2ea7quddusc * Performs the swipe left action on the UiObject. 277445e82ee022c484166ce7175973827f591ff2ea7quddusc * The swipe gesture can be performed over any surface. The targeted 278445e82ee022c484166ce7175973827f591ff2ea7quddusc * UI element does not need to be scrollable. 279445e82ee022c484166ce7175973827f591ff2ea7quddusc * See also: 280445e82ee022c484166ce7175973827f591ff2ea7quddusc * <ul> 281445e82ee022c484166ce7175973827f591ff2ea7quddusc * <li>{@link UiScrollable#scrollToBeginning(int)}</li> 282445e82ee022c484166ce7175973827f591ff2ea7quddusc * <li>{@link UiScrollable#scrollToEnd(int)}</li> 283445e82ee022c484166ce7175973827f591ff2ea7quddusc * <li>{@link UiScrollable#scrollBackward()}</li> 284445e82ee022c484166ce7175973827f591ff2ea7quddusc * <li>{@link UiScrollable#scrollForward()}</li> 285445e82ee022c484166ce7175973827f591ff2ea7quddusc * </ul> 2863d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 2873d50587be8ff021369c90554d814839335b445b0Adam Momtaz * @param steps indicates the number of injected move steps into the system. Steps are 288467cca7d25dbbf13c14cfd8c2ad38ab8eaf56bdaAdam Momtaz * injected about 5ms apart. So a 100 steps may take about 1/2 second to complete. 2893d50587be8ff021369c90554d814839335b445b0Adam Momtaz * @return true if successful 290e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 291dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 292e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 293e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean swipeLeft(int steps) throws UiObjectNotFoundException { 294f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(steps); 2953d50587be8ff021369c90554d814839335b445b0Adam Momtaz Rect rect = getVisibleBounds(); 296e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(rect.width() <= SWIPE_MARGIN_LIMIT * 2) 297e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return false; // too small to swipe 298e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return getInteractionController().swipe(rect.right - SWIPE_MARGIN_LIMIT, 299e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu rect.centerY(), rect.left + SWIPE_MARGIN_LIMIT, rect.centerY(), steps); 300e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 301e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 302e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 303445e82ee022c484166ce7175973827f591ff2ea7quddusc * Performs the swipe right action on the UiObject. 304445e82ee022c484166ce7175973827f591ff2ea7quddusc * The swipe gesture can be performed over any surface. The targeted 305445e82ee022c484166ce7175973827f591ff2ea7quddusc * UI element does not need to be scrollable. 306445e82ee022c484166ce7175973827f591ff2ea7quddusc * See also: 307445e82ee022c484166ce7175973827f591ff2ea7quddusc * <ul> 308445e82ee022c484166ce7175973827f591ff2ea7quddusc * <li>{@link UiScrollable#scrollToBeginning(int)}</li> 309445e82ee022c484166ce7175973827f591ff2ea7quddusc * <li>{@link UiScrollable#scrollToEnd(int)}</li> 310445e82ee022c484166ce7175973827f591ff2ea7quddusc * <li>{@link UiScrollable#scrollBackward()}</li> 311445e82ee022c484166ce7175973827f591ff2ea7quddusc * <li>{@link UiScrollable#scrollForward()}</li> 312445e82ee022c484166ce7175973827f591ff2ea7quddusc * </ul> 3133d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 3143d50587be8ff021369c90554d814839335b445b0Adam Momtaz * @param steps indicates the number of injected move steps into the system. Steps are 315467cca7d25dbbf13c14cfd8c2ad38ab8eaf56bdaAdam Momtaz * injected about 5ms apart. So a 100 steps may take about 1/2 second to complete. 3163d50587be8ff021369c90554d814839335b445b0Adam Momtaz * @return true if successful 317e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 318dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 319e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 320e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean swipeRight(int steps) throws UiObjectNotFoundException { 321f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(steps); 3223d50587be8ff021369c90554d814839335b445b0Adam Momtaz Rect rect = getVisibleBounds(); 323e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(rect.width() <= SWIPE_MARGIN_LIMIT * 2) 324e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return false; // too small to swipe 325e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return getInteractionController().swipe(rect.left + SWIPE_MARGIN_LIMIT, 326e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu rect.centerY(), rect.right - SWIPE_MARGIN_LIMIT, rect.centerY(), steps); 327e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 328e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 329e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 3303d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Finds the visible bounds of a partially visible UI element 3313d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 332e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @param node 3337f38ef08d07295967b905a61b2356ff6cdf31159Adam Momtaz * @return null if node is null, else a Rect containing visible bounds 334e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 335e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu private Rect getVisibleBounds(AccessibilityNodeInfo node) { 336e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if (node == null) { 337e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return null; 338e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 339e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 340e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // targeted node's bounds 34123296fc6448cd265fbb45c1fd9041976ae0da274Guang Zhu int w = UiDevice.getInstance().getDisplayWidth(); 34223296fc6448cd265fbb45c1fd9041976ae0da274Guang Zhu int h = UiDevice.getInstance().getDisplayHeight(); 34323296fc6448cd265fbb45c1fd9041976ae0da274Guang Zhu Rect nodeRect = AccessibilityNodeInfoHelper.getVisibleBoundsInScreen(node, w, h); 344e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 345e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // is the targeted node within a scrollable container? 346e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo scrollableParentNode = getScrollableParent(node); 347e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(scrollableParentNode == null) { 348e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // nothing to adjust for so return the node's Rect as is 349e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return nodeRect; 350e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 351e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 352e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // Scrollable parent's visible bounds 3537f38ef08d07295967b905a61b2356ff6cdf31159Adam Momtaz Rect parentRect = AccessibilityNodeInfoHelper 35423296fc6448cd265fbb45c1fd9041976ae0da274Guang Zhu .getVisibleBoundsInScreen(scrollableParentNode, w, h); 355e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // adjust for partial clipping of targeted by parent node if required 356e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu nodeRect.intersect(parentRect); 357e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return nodeRect; 358e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 359e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 360e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 361445e82ee022c484166ce7175973827f591ff2ea7quddusc * Walks up the layout hierarchy to find a scrollable parent. A scrollable parent 362445e82ee022c484166ce7175973827f591ff2ea7quddusc * indicates that this node might be in a container where it is partially 363445e82ee022c484166ce7175973827f591ff2ea7quddusc * visible due to scrolling. In this case, its clickable center might not be visible and 364445e82ee022c484166ce7175973827f591ff2ea7quddusc * the click coordinates should be adjusted. 3653d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 366e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @param node 3671893caed0ad4e73b0676f206282d490c2d345316Thanh Le * @return The accessibility node info. 368e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 369e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu private AccessibilityNodeInfo getScrollableParent(AccessibilityNodeInfo node) { 370e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo parent = node; 371e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu while(parent != null) { 372e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu parent = parent.getParent(); 373e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if (parent != null && parent.isScrollable()) { 374e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return parent; 375e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 376e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 377e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return null; 378e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 379e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 380e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 3813d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Performs a click at the center of the visible bounds of the UI element represented 38246d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * by this UiObject. 3833d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 384e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true id successful else false 385e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 386dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 387e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 388e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean click() throws UiObjectNotFoundException { 389f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(); 3900d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout()); 391e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 392e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 393e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 394e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu Rect rect = getVisibleBounds(node); 3950d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz return getInteractionController().clickAndSync(rect.centerX(), rect.centerY(), 3960d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz mConfig.getActionAcknowledgmentTimeout()); 397e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 398e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 399e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 400445e82ee022c484166ce7175973827f591ff2ea7quddusc * Waits for window transitions that would typically take longer than the 401445e82ee022c484166ce7175973827f591ff2ea7quddusc * usual default timeouts. 4023d50587be8ff021369c90554d814839335b445b0Adam Momtaz * See {@link #clickAndWaitForNewWindow(long)} 4033d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 4043d50587be8ff021369c90554d814839335b445b0Adam Momtaz * @return true if the event was triggered, else false 4053d50587be8ff021369c90554d814839335b445b0Adam Momtaz * @throws UiObjectNotFoundException 406dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 4073d50587be8ff021369c90554d814839335b445b0Adam Momtaz */ 408e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean clickAndWaitForNewWindow() throws UiObjectNotFoundException { 409f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(); 410e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return clickAndWaitForNewWindow(WAIT_FOR_WINDOW_TMEOUT); 411e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 412e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 413e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 41446d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * Performs a click at the center of the visible bounds of the UI element represented 41546d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * by this UiObject and waits for window transitions. 41646d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * 4173d50587be8ff021369c90554d814839335b445b0Adam Momtaz * This method differ from {@link UiObject#click()} only in that this method waits for a 41846d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * a new window transition as a result of the click. Some examples of a window transition: 419e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * <li>launching a new activity</li> 420e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * <li>bringing up a pop-up menu</li> 421e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * <li>bringing up a dialog</li> 422e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * 4233d50587be8ff021369c90554d814839335b445b0Adam Momtaz * @param timeout timeout before giving up on waiting for a new window 424e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if the event was triggered, else false 425e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 426dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 427e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 428e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean clickAndWaitForNewWindow(long timeout) throws UiObjectNotFoundException { 429f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(timeout); 4300d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout()); 431e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 432e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 433e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 434e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu Rect rect = getVisibleBounds(node); 4350d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz return getInteractionController().clickAndWaitForNewWindow(rect.centerX(), rect.centerY(), 4360d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz mConfig.getActionAcknowledgmentTimeout()); 437e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 438e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 439e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 4403d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Clicks the top and left corner of the UI element 4413d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 442e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true on success 4431893caed0ad4e73b0676f206282d490c2d345316Thanh Le * @throws UiObjectNotFoundException 444dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 445e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 446e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean clickTopLeft() throws UiObjectNotFoundException { 447f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(); 4480d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout()); 449e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 450e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 451e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 452e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu Rect rect = getVisibleBounds(node); 4531dc7d12406947faaee8454c6efb2a0631f5da573Adam Momtaz return getInteractionController().clickNoSync(rect.left + 5, rect.top + 5); 454e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 455e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 456e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 4573d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Long clicks bottom and right corner of the UI element 4583d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 459e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if operation was successful 460e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 461dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 462e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 463e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean longClickBottomRight() throws UiObjectNotFoundException { 464f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(); 4650d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout()); 466e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 467e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 468e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 469e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu Rect rect = getVisibleBounds(node); 4701dc7d12406947faaee8454c6efb2a0631f5da573Adam Momtaz return getInteractionController().longTapNoSync(rect.right - 5, rect.bottom - 5); 471e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 472e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 473e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 4743d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Clicks the bottom and right corner of the UI element 4753d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 476e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true on success 4771893caed0ad4e73b0676f206282d490c2d345316Thanh Le * @throws UiObjectNotFoundException 478dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 479e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 480e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean clickBottomRight() throws UiObjectNotFoundException { 481f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(); 4820d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout()); 483e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 484e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 485e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 486e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu Rect rect = getVisibleBounds(node); 4871dc7d12406947faaee8454c6efb2a0631f5da573Adam Momtaz return getInteractionController().clickNoSync(rect.right - 5, rect.bottom - 5); 488e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 489e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 490e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 4913d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Long clicks the center of the visible bounds of the UI element 4923d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 493e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if operation was successful 494e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 495dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 496e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 497e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean longClick() throws UiObjectNotFoundException { 498f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(); 4990d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout()); 500e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 501e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 502e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 503e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu Rect rect = getVisibleBounds(node); 5041dc7d12406947faaee8454c6efb2a0631f5da573Adam Momtaz return getInteractionController().longTapNoSync(rect.centerX(), rect.centerY()); 505e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 506e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 507e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 5083d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Long clicks on the top and left corner of the UI element 5093d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 510e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if operation was successful 511e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 512dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 513e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 514e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean longClickTopLeft() throws UiObjectNotFoundException { 515f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(); 5160d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout()); 517e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 518e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 519e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 520e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu Rect rect = getVisibleBounds(node); 5211dc7d12406947faaee8454c6efb2a0631f5da573Adam Momtaz return getInteractionController().longTapNoSync(rect.left + 5, rect.top + 5); 522e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 523e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 524e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 5253d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Reads the <code>text</code> property of the UI element 5263d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 527e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return text value of the current node represented by this UiObject 528e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException if no match could be found 529dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 530e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 531e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public String getText() throws UiObjectNotFoundException { 532f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(); 5330d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout()); 534e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 535e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 536e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 537e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu String retVal = safeStringReturn(node.getText()); 538e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu Log.d(LOG_TAG, String.format("getText() = %s", retVal)); 539e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return retVal; 540e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 541e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 542e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 543445e82ee022c484166ce7175973827f591ff2ea7quddusc * Retrieves the <code>className</code> property of the UI element. 54497835f3a7c80b147136c44c175eb9e6a4261fd92Adam Momtaz * 54597835f3a7c80b147136c44c175eb9e6a4261fd92Adam Momtaz * @return class name of the current node represented by this UiObject 546445e82ee022c484166ce7175973827f591ff2ea7quddusc * @throws UiObjectNotFoundException if no match was found 54797835f3a7c80b147136c44c175eb9e6a4261fd92Adam Momtaz * @since API Level 18 54897835f3a7c80b147136c44c175eb9e6a4261fd92Adam Momtaz */ 54997835f3a7c80b147136c44c175eb9e6a4261fd92Adam Momtaz public String getClassName() throws UiObjectNotFoundException { 55097835f3a7c80b147136c44c175eb9e6a4261fd92Adam Momtaz Tracer.trace(); 5510d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout()); 55297835f3a7c80b147136c44c175eb9e6a4261fd92Adam Momtaz if(node == null) { 55397835f3a7c80b147136c44c175eb9e6a4261fd92Adam Momtaz throw new UiObjectNotFoundException(getSelector().toString()); 55497835f3a7c80b147136c44c175eb9e6a4261fd92Adam Momtaz } 55597835f3a7c80b147136c44c175eb9e6a4261fd92Adam Momtaz String retVal = safeStringReturn(node.getClassName()); 55697835f3a7c80b147136c44c175eb9e6a4261fd92Adam Momtaz Log.d(LOG_TAG, String.format("getClassName() = %s", retVal)); 55797835f3a7c80b147136c44c175eb9e6a4261fd92Adam Momtaz return retVal; 55897835f3a7c80b147136c44c175eb9e6a4261fd92Adam Momtaz } 55997835f3a7c80b147136c44c175eb9e6a4261fd92Adam Momtaz 56097835f3a7c80b147136c44c175eb9e6a4261fd92Adam Momtaz /** 5613d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Reads the <code>content_desc</code> property of the UI element 5623d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 563e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return value of node attribute "content_desc" 564e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 565dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 566e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 567e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public String getContentDescription() throws UiObjectNotFoundException { 568f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(); 5690d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout()); 570e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 571e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 572e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 573e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return safeStringReturn(node.getContentDescription()); 574e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 575e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 576e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 57746d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * Sets the text in an editable field, after clearing the field's content. 57846d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * 57946d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * The {@link UiSelector} selector of this object must reference a UI element that is editable. 58046d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * 58146d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * When you call this method, the method first simulates a {@link #click()} on 58246d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * editable field to set focus. The method then clears the field's contents 58346d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * and injects your specified text into the field. 5843d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 58546d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * If you want to capture the original contents of the field, call {@link #getText()} first. 58646d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * You can then modify the text and use this method to update the field. 58746d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * 58846d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * @param text string to set 589e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if operation is successful 590e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 591dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 592e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 593e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean setText(String text) throws UiObjectNotFoundException { 594f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(text); 595e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu clearTextField(); 596e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return getInteractionController().sendText(text); 597e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 598e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 599e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 60046d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * Clears the existing text contents in an editable field. 60146d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * 60246d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * The {@link UiSelector} of this object must reference a UI element that is editable. 60346d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * 60446d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * When you call this method, the method first sets focus at the start edge of the field. 60546d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * The method then simulates a long-press to select the existing text, and deletes the 60646d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * selected text. 60746d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * 60846d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * If a "Select-All" option is displayed, the method will automatically attempt to use it 60946d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * to ensure full text selection. 61046d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * 61146d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * Note that it is possible that not all the text in the field is selected; for example, 61246d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * if the text contains separators such as spaces, slashes, at symbol etc. 61346d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * Also, not all editable fields support the long-press functionality. 61446d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * 615e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 616dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 617e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 618e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public void clearTextField() throws UiObjectNotFoundException { 619f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(); 620e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // long click left + center 6210d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout()); 622e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 623e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 624e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 625e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu Rect rect = getVisibleBounds(node); 6261dc7d12406947faaee8454c6efb2a0631f5da573Adam Momtaz getInteractionController().longTapNoSync(rect.left + 20, rect.centerY()); 627e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // check if the edit menu is open 6284ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz UiObject selectAll = new UiObject(new UiSelector().descriptionContains("Select all")); 629e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(selectAll.waitForExists(50)) 630e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu selectAll.click(); 631e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // wait for the selection 632e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu SystemClock.sleep(250); 633e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // delete it 634e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu getInteractionController().sendKey(KeyEvent.KEYCODE_DEL, 0); 635e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 636e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 637e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 6383d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Check if the UI element's <code>checked</code> property is currently true 6393d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 640e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if it is else false 641dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 642e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 643e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean isChecked() throws UiObjectNotFoundException { 644f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(); 6450d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout()); 646e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 647e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 648e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 649e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return node.isChecked(); 650e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 651e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 652e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 653445e82ee022c484166ce7175973827f591ff2ea7quddusc * Checks if the UI element's <code>selected</code> property is currently true. 6543d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 655e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if it is else false 656e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 657dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 658e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 659e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean isSelected() throws UiObjectNotFoundException { 660f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(); 6610d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout()); 662e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 663e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 664e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 665e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return node.isSelected(); 666e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 667e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 668e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 669445e82ee022c484166ce7175973827f591ff2ea7quddusc * Checks if the UI element's <code>checkable</code> property is currently true. 6703d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 671e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if it is else false 672e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 673dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 674e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 675e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean isCheckable() throws UiObjectNotFoundException { 676f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(); 6770d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout()); 678e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 679e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 680e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 681e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return node.isCheckable(); 682e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 683e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 684e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 685445e82ee022c484166ce7175973827f591ff2ea7quddusc * Checks if the UI element's <code>enabled</code> property is currently true. 6863d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 687e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if it is else false 688e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 689dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 690e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 691e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean isEnabled() throws UiObjectNotFoundException { 692f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(); 6930d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout()); 694e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 695e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 696e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 697e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return node.isEnabled(); 698e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 699e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 700e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 701445e82ee022c484166ce7175973827f591ff2ea7quddusc * Checks if the UI element's <code>clickable</code> property is currently true. 7023d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 703e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if it is else false 704e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 705dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 706e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 707e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean isClickable() throws UiObjectNotFoundException { 708f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(); 7090d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout()); 710e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 711e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 712e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 713e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return node.isClickable(); 714e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 715e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 716e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 7173d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Check if the UI element's <code>focused</code> property is currently true 7183d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 719e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if it is else false 720e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 721dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 722e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 723e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean isFocused() throws UiObjectNotFoundException { 724f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(); 7250d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout()); 726e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 727e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 728e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 729e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return node.isFocused(); 730e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 731e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 732e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 733445e82ee022c484166ce7175973827f591ff2ea7quddusc * Check if the UI element's <code>focusable</code> property is currently true. 7343d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 735e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if it is else false 736e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 737dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 738e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 739e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean isFocusable() throws UiObjectNotFoundException { 740f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(); 7410d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout()); 742e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 743e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 744e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 745e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return node.isFocusable(); 746e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 747e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 748e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 749445e82ee022c484166ce7175973827f591ff2ea7quddusc * Check if the view's <code>scrollable</code> property is currently true 7503d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 751e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if it is else false 752e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 753dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 754e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 755e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean isScrollable() throws UiObjectNotFoundException { 756f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(); 7570d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout()); 758e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 759e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 760e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 761e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return node.isScrollable(); 762e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 763e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 764e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 765445e82ee022c484166ce7175973827f591ff2ea7quddusc * Check if the view's <code>long-clickable</code> property is currently true 7663d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 767e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if it is else false 768e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 769dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 770e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 771e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean isLongClickable() throws UiObjectNotFoundException { 772f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(); 7730d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout()); 774e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 775e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 776e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 777e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return node.isLongClickable(); 778e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 779e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 780e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 781445e82ee022c484166ce7175973827f591ff2ea7quddusc * Reads the view's <code>package</code> property 7823d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 7833d50587be8ff021369c90554d814839335b445b0Adam Momtaz * @return true if it is else false 784e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 785dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 786e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 787e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public String getPackageName() throws UiObjectNotFoundException { 788f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(); 7890d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout()); 790e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 791e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 792e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 793e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return safeStringReturn(node.getPackageName()); 794e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 795e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 796e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 797445e82ee022c484166ce7175973827f591ff2ea7quddusc * Returns the visible bounds of the view. 79846d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * 799445e82ee022c484166ce7175973827f591ff2ea7quddusc * If a portion of the view is visible, only the bounds of the visible portion are 80046d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * reported. 8013d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 802e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return Rect 803e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 8041893caed0ad4e73b0676f206282d490c2d345316Thanh Le * @see {@link #getBounds()} 80579693ede92636fe6f3a6ec4dc049a438fd9504ffGuang Zhu * @since API Level 17 806e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 8073d50587be8ff021369c90554d814839335b445b0Adam Momtaz public Rect getVisibleBounds() throws UiObjectNotFoundException { 808f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(); 8090d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout()); 810e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 811e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 812e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 813e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return getVisibleBounds(node); 814e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 815e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 816e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 817445e82ee022c484166ce7175973827f591ff2ea7quddusc * Returns the view's <code>bounds</code> property. See {@link #getVisibleBounds()} 8183d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 8193d50587be8ff021369c90554d814839335b445b0Adam Momtaz * @return Rect 8203d50587be8ff021369c90554d814839335b445b0Adam Momtaz * @throws UiObjectNotFoundException 821dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 8223d50587be8ff021369c90554d814839335b445b0Adam Momtaz */ 8233d50587be8ff021369c90554d814839335b445b0Adam Momtaz public Rect getBounds() throws UiObjectNotFoundException { 824f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(); 8250d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout()); 8263d50587be8ff021369c90554d814839335b445b0Adam Momtaz if(node == null) { 8273d50587be8ff021369c90554d814839335b445b0Adam Momtaz throw new UiObjectNotFoundException(getSelector().toString()); 8283d50587be8ff021369c90554d814839335b445b0Adam Momtaz } 8293d50587be8ff021369c90554d814839335b445b0Adam Momtaz Rect nodeRect = new Rect(); 8303d50587be8ff021369c90554d814839335b445b0Adam Momtaz node.getBoundsInScreen(nodeRect); 8313d50587be8ff021369c90554d814839335b445b0Adam Momtaz 8323d50587be8ff021369c90554d814839335b445b0Adam Momtaz return nodeRect; 8333d50587be8ff021369c90554d814839335b445b0Adam Momtaz } 8343d50587be8ff021369c90554d814839335b445b0Adam Momtaz 8353d50587be8ff021369c90554d814839335b445b0Adam Momtaz /** 836445e82ee022c484166ce7175973827f591ff2ea7quddusc * Waits a specified length of time for a view to become visible. 83746d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * 838445e82ee022c484166ce7175973827f591ff2ea7quddusc * This method waits until the view becomes visible on the display, or 83946d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * until the timeout has elapsed. You can use this method in situations where 84046d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * the content that you want to select is not immediately displayed. 8413d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 84246d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * @param timeout the amount of time to wait (in milliseconds) 843445e82ee022c484166ce7175973827f591ff2ea7quddusc * @return true if the view is displayed, else false if timeout elapsed while waiting 844dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 845e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 846e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean waitForExists(long timeout) { 847f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(timeout); 848e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(findAccessibilityNodeInfo(timeout) != null) { 849e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return true; 850e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 851e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return false; 852e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 853e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 854e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 855445e82ee022c484166ce7175973827f591ff2ea7quddusc * Waits a specified length of time for a view to become undetectable. 8563d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 857445e82ee022c484166ce7175973827f591ff2ea7quddusc * This method waits until a view is no longer matchable, or until the 85846d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * timeout has elapsed. 85946d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * 860445e82ee022c484166ce7175973827f591ff2ea7quddusc * A view becomes undetectable when the {@link UiSelector} of the object is 86146d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * unable to find a match because the element has either changed its state or is no 86246d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * longer displayed. 86346d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * 86446d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * You can use this method when attempting to wait for some long operation 86546d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * to compete, such as downloading a large file or connecting to a remote server. 86646d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * 86746d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * @param timeout time to wait (in milliseconds) 86846d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * @return true if the element is gone before timeout elapsed, else false if timeout elapsed 86946d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * but a matching element is still found. 870dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 871e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 872e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean waitUntilGone(long timeout) { 873f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(timeout); 874e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu long startMills = SystemClock.uptimeMillis(); 875e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu long currentMills = 0; 876e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu while (currentMills <= timeout) { 877e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(findAccessibilityNodeInfo(0) == null) 878e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return true; 879e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu currentMills = SystemClock.uptimeMillis() - startMills; 880e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(timeout > 0) 881e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu SystemClock.sleep(WAIT_FOR_SELECTOR_POLL); 882e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 883e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return false; 884e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 885e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 886e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 887445e82ee022c484166ce7175973827f591ff2ea7quddusc * Check if view exists. 88846d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * 889e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * This methods performs a {@link #waitForExists(long)} with zero timeout. This 890445e82ee022c484166ce7175973827f591ff2ea7quddusc * basically returns immediately whether the view represented by this UiObject 891445e82ee022c484166ce7175973827f591ff2ea7quddusc * exists or not. If you need to wait longer for this view, then see 892e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * {@link #waitForExists(long)}. 8933d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 894445e82ee022c484166ce7175973827f591ff2ea7quddusc * @return true if the view represented by this UiObject does exist 895dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 896e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 897e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public boolean exists() { 898f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(); 899e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return waitForExists(0); 900e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 901e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 902e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu private String safeStringReturn(CharSequence cs) { 903e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(cs == null) 904e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return ""; 905e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return cs.toString(); 906e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 907c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz 908c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz /** 909445e82ee022c484166ce7175973827f591ff2ea7quddusc * Performs a two-pointer gesture, where each pointer moves diagonally 910445e82ee022c484166ce7175973827f591ff2ea7quddusc * opposite across the other, from the center out towards the edges of the 911c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * this UiObject. 912445e82ee022c484166ce7175973827f591ff2ea7quddusc * @param percent percentage of the object's diagonal length for the pinch gesture 913445e82ee022c484166ce7175973827f591ff2ea7quddusc * @param steps the number of steps for the gesture. Steps are injected 914445e82ee022c484166ce7175973827f591ff2ea7quddusc * about 5 milliseconds apart, so 100 steps may take around 0.5 seconds to complete. 9151078ab1070411af45d5e8ec3b56abec6789e7722Guang Zhu * @return <code>true</code> if all touch events for this gesture are injected successfully, 916445e82ee022c484166ce7175973827f591ff2ea7quddusc * <code>false</code> otherwise 917c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * @throws UiObjectNotFoundException 918c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * @since API Level 18 919c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz */ 9201078ab1070411af45d5e8ec3b56abec6789e7722Guang Zhu public boolean pinchOut(int percent, int steps) throws UiObjectNotFoundException { 921c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz // make value between 1 and 100 922c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz percent = (percent < 0) ? 1 : (percent > 100) ? 100 : percent; 923c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz float percentage = percent / 100f; 924c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz 9250d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout()); 926c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz if (node == null) { 927c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz throw new UiObjectNotFoundException(getSelector().toString()); 928c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz } 929c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz 930c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz Rect rect = getVisibleBounds(node); 931c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz if (rect.width() <= FINGER_TOUCH_HALF_WIDTH * 2) 932c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz throw new IllegalStateException("Object width is too small for operation"); 933c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz 934c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz // start from the same point at the center of the control 935c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz Point startPoint1 = new Point(rect.centerX() - FINGER_TOUCH_HALF_WIDTH, rect.centerY()); 936c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz Point startPoint2 = new Point(rect.centerX() + FINGER_TOUCH_HALF_WIDTH, rect.centerY()); 937c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz 938c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz // End at the top-left and bottom-right corners of the control 939c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz Point endPoint1 = new Point(rect.centerX() - (int)((rect.width()/2) * percentage), 940c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz rect.centerY()); 941c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz Point endPoint2 = new Point(rect.centerX() + (int)((rect.width()/2) * percentage), 942c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz rect.centerY()); 943c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz 9441078ab1070411af45d5e8ec3b56abec6789e7722Guang Zhu return performTwoPointerGesture(startPoint1, startPoint2, endPoint1, endPoint2, steps); 945c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz } 946c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz 947c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz /** 948445e82ee022c484166ce7175973827f591ff2ea7quddusc * Performs a two-pointer gesture, where each pointer moves diagonally 949445e82ee022c484166ce7175973827f591ff2ea7quddusc * toward the other, from the edges to the center of this UiObject . 950445e82ee022c484166ce7175973827f591ff2ea7quddusc * @param percent percentage of the object's diagonal length for the pinch gesture 951445e82ee022c484166ce7175973827f591ff2ea7quddusc * @param steps the number of steps for the gesture. Steps are injected 952445e82ee022c484166ce7175973827f591ff2ea7quddusc * about 5 milliseconds apart, so 100 steps may take around 0.5 seconds to complete. 9531078ab1070411af45d5e8ec3b56abec6789e7722Guang Zhu * @return <code>true</code> if all touch events for this gesture are injected successfully, 954445e82ee022c484166ce7175973827f591ff2ea7quddusc * <code>false</code> otherwise 955c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * @throws UiObjectNotFoundException 956c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * @since API Level 18 957c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz */ 9581078ab1070411af45d5e8ec3b56abec6789e7722Guang Zhu public boolean pinchIn(int percent, int steps) throws UiObjectNotFoundException { 959c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz // make value between 1 and 100 960c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz percent = (percent < 0) ? 0 : (percent > 100) ? 100 : percent; 961c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz float percentage = percent / 100f; 962c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz 9630d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout()); 964c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz if (node == null) { 965c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz throw new UiObjectNotFoundException(getSelector().toString()); 966c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz } 967c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz 968c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz Rect rect = getVisibleBounds(node); 969c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz if (rect.width() <= FINGER_TOUCH_HALF_WIDTH * 2) 970c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz throw new IllegalStateException("Object width is too small for operation"); 971c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz 972c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz Point startPoint1 = new Point(rect.centerX() - (int)((rect.width()/2) * percentage), 973c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz rect.centerY()); 974c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz Point startPoint2 = new Point(rect.centerX() + (int)((rect.width()/2) * percentage), 975c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz rect.centerY()); 976c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz 977c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz Point endPoint1 = new Point(rect.centerX() - FINGER_TOUCH_HALF_WIDTH, rect.centerY()); 978c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz Point endPoint2 = new Point(rect.centerX() + FINGER_TOUCH_HALF_WIDTH, rect.centerY()); 979c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz 9801078ab1070411af45d5e8ec3b56abec6789e7722Guang Zhu return performTwoPointerGesture(startPoint1, startPoint2, endPoint1, endPoint2, steps); 981c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz } 982c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz 983c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz /** 984445e82ee022c484166ce7175973827f591ff2ea7quddusc * Generates a two-pointer gesture with arbitrary starting and ending points. 985c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * 986c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * @param startPoint1 start point of pointer 1 987c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * @param startPoint2 start point of pointer 2 988c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * @param endPoint1 end point of pointer 1 989c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * @param endPoint2 end point of pointer 2 990445e82ee022c484166ce7175973827f591ff2ea7quddusc * @param steps the number of steps for the gesture. Steps are injected 991445e82ee022c484166ce7175973827f591ff2ea7quddusc * about 5 milliseconds apart, so 100 steps may take around 0.5 seconds to complete. 9921078ab1070411af45d5e8ec3b56abec6789e7722Guang Zhu * @return <code>true</code> if all touch events for this gesture are injected successfully, 993445e82ee022c484166ce7175973827f591ff2ea7quddusc * <code>false</code> otherwise 994c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * @since API Level 18 995c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz */ 9961078ab1070411af45d5e8ec3b56abec6789e7722Guang Zhu public boolean performTwoPointerGesture(Point startPoint1, Point startPoint2, Point endPoint1, 997c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz Point endPoint2, int steps) { 998c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz 999c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz // avoid a divide by zero 1000c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz if(steps == 0) 1001c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz steps = 1; 1002c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz 1003c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz final float stepX1 = (endPoint1.x - startPoint1.x) / steps; 1004c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz final float stepY1 = (endPoint1.y - startPoint1.y) / steps; 1005c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz final float stepX2 = (endPoint2.x - startPoint2.x) / steps; 1006c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz final float stepY2 = (endPoint2.y - startPoint2.y) / steps; 1007c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz 1008c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz int eventX1, eventY1, eventX2, eventY2; 1009c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz eventX1 = startPoint1.x; 1010c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz eventY1 = startPoint1.y; 1011c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz eventX2 = startPoint2.x; 1012c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz eventY2 = startPoint2.y; 1013c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz 1014c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz // allocate for steps plus first down and last up 1015c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz PointerCoords[] points1 = new PointerCoords[steps + 2]; 1016c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz PointerCoords[] points2 = new PointerCoords[steps + 2]; 1017c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz 1018c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz // Include the first and last touch downs in the arrays of steps 1019c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz for (int i = 0; i < steps + 1; i++) { 1020c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz PointerCoords p1 = new PointerCoords(); 1021c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz p1.x = eventX1; 1022c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz p1.y = eventY1; 1023c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz p1.pressure = 1; 1024c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz p1.size = 1; 1025c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz points1[i] = p1; 1026c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz 1027c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz PointerCoords p2 = new PointerCoords(); 1028c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz p2.x = eventX2; 1029c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz p2.y = eventY2; 1030c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz p2.pressure = 1; 1031c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz p2.size = 1; 1032c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz points2[i] = p2; 1033c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz 1034c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz eventX1 += stepX1; 1035c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz eventY1 += stepY1; 1036c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz eventX2 += stepX2; 1037c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz eventY2 += stepY2; 1038c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz } 1039c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz 1040c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz // ending pointers coordinates 1041c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz PointerCoords p1 = new PointerCoords(); 1042c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz p1.x = endPoint1.x; 1043c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz p1.y = endPoint1.y; 1044c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz p1.pressure = 1; 1045c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz p1.size = 1; 1046c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz points1[steps + 1] = p1; 1047c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz 1048c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz PointerCoords p2 = new PointerCoords(); 1049c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz p2.x = endPoint2.x; 1050c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz p2.y = endPoint2.y; 1051c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz p2.pressure = 1; 1052c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz p2.size = 1; 1053c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz points2[steps + 1] = p2; 1054c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz 10551078ab1070411af45d5e8ec3b56abec6789e7722Guang Zhu return performMultiPointerGesture(points1, points2); 1056c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz } 1057c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz 1058c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz /** 1059445e82ee022c484166ce7175973827f591ff2ea7quddusc * Performs a multi-touch gesture. You must specify touch coordinates for 1060445e82ee022c484166ce7175973827f591ff2ea7quddusc * at least 2 pointers. Each pointer must have all of its touch steps 1061445e82ee022c484166ce7175973827f591ff2ea7quddusc * defined in an array of {@link PointerCoords}. You can use this method to 1062445e82ee022c484166ce7175973827f591ff2ea7quddusc * specify complex gestures, like circles and irregular shapes, where each 1063445e82ee022c484166ce7175973827f591ff2ea7quddusc * pointer may take a different path. 1064c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * 1065445e82ee022c484166ce7175973827f591ff2ea7quddusc * To create a single point on a pointer's touch path: 1066c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * <code> 1067c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * PointerCoords p = new PointerCoords(); 1068c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * p.x = stepX; 1069c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * p.y = stepY; 1070c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * p.pressure = 1; 1071c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * p.size = 1; 1072c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * </code> 10739ebf91aa923d2424298cb908a79dd03aefbf0a8fGuang Zhu * @param touches represents the pointers' paths. Each {@link PointerCoords} 10749ebf91aa923d2424298cb908a79dd03aefbf0a8fGuang Zhu * array represents a different pointer. Each {@link PointerCoords} in an 1075445e82ee022c484166ce7175973827f591ff2ea7quddusc * array element represents a touch point on a pointer's path. 10761078ab1070411af45d5e8ec3b56abec6789e7722Guang Zhu * @return <code>true</code> if all touch events for this gesture are injected successfully, 1077445e82ee022c484166ce7175973827f591ff2ea7quddusc * <code>false</code> otherwise 1078c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz * @since API Level 18 1079c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz */ 10801078ab1070411af45d5e8ec3b56abec6789e7722Guang Zhu public boolean performMultiPointerGesture(PointerCoords[] ...touches) { 10811078ab1070411af45d5e8ec3b56abec6789e7722Guang Zhu return getInteractionController().performMultiPointerGesture(touches); 1082c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz } 10839ebf91aa923d2424298cb908a79dd03aefbf0a8fGuang Zhu} 1084