118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu/* 218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * Copyright (C) 2012 The Android Open Source Project 318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * 418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * Licensed under the Apache License, Version 2.0 (the "License"); 518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * you may not use this file except in compliance with the License. 618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * You may obtain a copy of the License at 718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * 818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * http://www.apache.org/licenses/LICENSE-2.0 918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * 1018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * Unless required by applicable law or agreed to in writing, software 1118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * distributed under the License is distributed on an "AS IS" BASIS, 1218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * See the License for the specific language governing permissions and 1418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * limitations under the License. 1518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu */ 1618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 1718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhupackage com.android.uiautomator.core; 1818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 1918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhuimport android.graphics.Point; 2018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhuimport android.graphics.Rect; 2118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhuimport android.os.SystemClock; 2218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhuimport android.util.Log; 2318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhuimport android.view.KeyEvent; 2418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhuimport android.view.MotionEvent.PointerCoords; 2518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhuimport android.view.accessibility.AccessibilityNodeInfo; 2618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 2718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu/** 2818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * A UiObject is a representation of a view. It is not in any way directly bound to a 2918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * view as an object reference. A UiObject contains information to help it 3018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * locate a matching view at runtime based on the {@link UiSelector} properties specified in 3118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * its constructor. Once you create an instance of a UiObject, it can 3218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * be reused for different views that match the selector criteria. 3318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @since API Level 16 3418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu */ 3518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhupublic class UiObject { 3618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu private static final String LOG_TAG = UiObject.class.getSimpleName(); 3718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu /** 3818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @since API Level 16 3918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @deprecated use {@link Configurator#setWaitForSelectorTimeout(long)} 4018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu **/ 4118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu @Deprecated 4218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu protected static final long WAIT_FOR_SELECTOR_TIMEOUT = 10 * 1000; 4318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu /** 4418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @since API Level 16 4518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu **/ 4618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu protected static final long WAIT_FOR_SELECTOR_POLL = 1000; 4718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu // set a default timeout to 5.5s, since ANR threshold is 5s 4818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu /** 4918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @since API Level 16 5018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu **/ 5118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu protected static final long WAIT_FOR_WINDOW_TMEOUT = 5500; 5218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu /** 5318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @since API Level 16 5418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu **/ 5518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu protected static final int SWIPE_MARGIN_LIMIT = 5; 5618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu /** 5718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @since API Level 17 5818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @deprecated use {@link Configurator#setScrollAcknowledgmentTimeout(long)} 5918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu **/ 6018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu @Deprecated 6118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu protected static final long WAIT_FOR_EVENT_TMEOUT = 3 * 1000; 6218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu /** 6318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @since API Level 18 6418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu **/ 6518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu protected static final int FINGER_TOUCH_HALF_WIDTH = 20; 6618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 6718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu private final UiSelector mSelector; 6818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 6918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu private final Configurator mConfig = Configurator.getInstance(); 7018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 7118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu /** 7218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * Constructs a UiObject to represent a view that matches the specified 7318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * selector criteria. 7418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @param selector 7518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @since API Level 16 7618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu */ 7718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu public UiObject(UiSelector selector) { 7818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu mSelector = selector; 7918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 8018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 8118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu /** 8218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * Debugging helper. A test can dump the properties of a selector as a string 8318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * to its logs if needed. <code>getSelector().toString();</code> 8418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * 8518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @return {@link UiSelector} 8618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @since API Level 16 8718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu */ 8818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu public final UiSelector getSelector() { 8918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu Tracer.trace(); 9018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu return new UiSelector(mSelector); 9118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 9218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 9318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu /** 9418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * Retrieves the {@link QueryController} to translate a {@link UiSelector} selector 9518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * into an {@link AccessibilityNodeInfo}. 9618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * 9718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @return {@link QueryController} 9818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu */ 9918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu QueryController getQueryController() { 10018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu return UiDevice.getInstance().getAutomatorBridge().getQueryController(); 10118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 10218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 10318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu /** 10418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * Retrieves the {@link InteractionController} to perform finger actions such as tapping, 10518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * swiping, or entering text. 10618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * 10718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @return {@link InteractionController} 10818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu */ 10918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu InteractionController getInteractionController() { 11018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu return UiDevice.getInstance().getAutomatorBridge().getInteractionController(); 11118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 11218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 11318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu /** 11418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * Creates a new UiObject for a child view that is under the present UiObject. 11518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * 11618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @param selector for child view to match 11718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @return a new UiObject representing the child view 11818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @since API Level 16 11918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu */ 12018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu public UiObject getChild(UiSelector selector) throws UiObjectNotFoundException { 12118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu Tracer.trace(selector); 12218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu return new UiObject(getSelector().childSelector(selector)); 12318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 12418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 12518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu /** 12618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * Creates a new UiObject for a sibling view or a child of the sibling view, 12718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * relative to the present UiObject. 12818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * 12918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @param selector for a sibling view or children of the sibling view 13018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @return a new UiObject representing the matched view 13118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @throws UiObjectNotFoundException 13218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @since API Level 16 13318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu */ 13418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu public UiObject getFromParent(UiSelector selector) throws UiObjectNotFoundException { 13518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu Tracer.trace(selector); 13618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu return new UiObject(getSelector().fromParent(selector)); 13718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 13818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 13918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu /** 14018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * Counts the child views immediately under the present UiObject. 14118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * 14218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @return the count of child views. 14318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @throws UiObjectNotFoundException 14418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @since API Level 16 14518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu */ 14618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu public int getChildCount() throws UiObjectNotFoundException { 14718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu Tracer.trace(); 14818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout()); 14918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu if(node == null) { 15018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 15118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 15218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu return node.getChildCount(); 15318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 15418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 15518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu /** 15618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * Finds a matching UI element in the accessibility hierarchy, by 15718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * using the selector for this UiObject. 15818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * 15918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @param timeout in milliseconds 16018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @return AccessibilityNodeInfo if found else null 16118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @since API Level 16 16218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu */ 16318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu protected AccessibilityNodeInfo findAccessibilityNodeInfo(long timeout) { 16418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu AccessibilityNodeInfo node = null; 16518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu long startMills = SystemClock.uptimeMillis(); 16618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu long currentMills = 0; 16718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu while (currentMills <= timeout) { 16818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu node = getQueryController().findAccessibilityNodeInfo(getSelector()); 16918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu if (node != null) { 17018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu break; 17118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } else { 17218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu // does nothing if we're reentering another runWatchers() 17318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu UiDevice.getInstance().runWatchers(); 17418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 17518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu currentMills = SystemClock.uptimeMillis() - startMills; 17618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu if(timeout > 0) { 17718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu SystemClock.sleep(WAIT_FOR_SELECTOR_POLL); 17818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 17918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 18018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu return node; 18118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 18218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 18318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu /** 18418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * Drags this object to a destination UiObject. 18518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * The number of steps specified in your input parameter can influence the 18618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * drag speed, and varying speeds may impact the results. Consider 18718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * evaluating different speeds when using this method in your tests. 18818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * 18918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @param destObj the destination UiObject. 19018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @param steps usually 40 steps. You can increase or decrease the steps to change the speed. 19118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @return true if successful 19218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @throws UiObjectNotFoundException 19318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @since API Level 18 19418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu */ 19518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu public boolean dragTo(UiObject destObj, int steps) throws UiObjectNotFoundException { 19618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu Rect srcRect = getVisibleBounds(); 19718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu Rect dstRect = destObj.getVisibleBounds(); 19818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu return getInteractionController().swipe(srcRect.centerX(), srcRect.centerY(), 19918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu dstRect.centerX(), dstRect.centerY(), steps, true); 20018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 20118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 20218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu /** 20318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * Drags this object to arbitrary coordinates. 20418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * The number of steps specified in your input parameter can influence the 20518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * drag speed, and varying speeds may impact the results. Consider 20618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * evaluating different speeds when using this method in your tests. 20718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * 20818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @param destX the X-axis coordinate. 20918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @param destY the Y-axis coordinate. 21018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @param steps usually 40 steps. You can increase or decrease the steps to change the speed. 21118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @return true if successful 21218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @throws UiObjectNotFoundException 21318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @since API Level 18 21418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu */ 21518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu public boolean dragTo(int destX, int destY, int steps) throws UiObjectNotFoundException { 21618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu Rect srcRect = getVisibleBounds(); 21718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu return getInteractionController().swipe(srcRect.centerX(), srcRect.centerY(), destX, destY, 21818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu steps, true); 21918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 22018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 22118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu /** 22218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * Performs the swipe up action on the UiObject. 22318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * See also: 22418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * <ul> 22518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * <li>{@link UiScrollable#scrollToBeginning(int)}</li> 22618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * <li>{@link UiScrollable#scrollToEnd(int)}</li> 22718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * <li>{@link UiScrollable#scrollBackward()}</li> 22818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * <li>{@link UiScrollable#scrollForward()}</li> 22918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * </ul> 23018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * 23118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @param steps indicates the number of injected move steps into the system. Steps are 23218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * injected about 5ms apart. So a 100 steps may take about 1/2 second to complete. 23318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @return true of successful 23418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @throws UiObjectNotFoundException 23518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @since API Level 16 23618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu */ 23718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu public boolean swipeUp(int steps) throws UiObjectNotFoundException { 23818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu Tracer.trace(steps); 23918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu Rect rect = getVisibleBounds(); 24018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu if(rect.height() <= SWIPE_MARGIN_LIMIT * 2) 24118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu return false; // too small to swipe 24218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu return getInteractionController().swipe(rect.centerX(), 24318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu rect.bottom - SWIPE_MARGIN_LIMIT, rect.centerX(), rect.top + SWIPE_MARGIN_LIMIT, 24418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu steps); 24518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 24618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 24718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu /** 24818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * Performs the swipe down action on the UiObject. 24918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * The swipe gesture can be performed over any surface. The targeted 25018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * UI element does not need to be scrollable. 25118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * See also: 25218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * <ul> 25318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * <li>{@link UiScrollable#scrollToBeginning(int)}</li> 25418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * <li>{@link UiScrollable#scrollToEnd(int)}</li> 25518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * <li>{@link UiScrollable#scrollBackward()}</li> 25618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * <li>{@link UiScrollable#scrollForward()}</li> 25718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * </ul> 25818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * 25918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @param steps indicates the number of injected move steps into the system. Steps are 26018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * injected about 5ms apart. So a 100 steps may take about 1/2 second to complete. 26118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @return true if successful 26218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @throws UiObjectNotFoundException 26318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @since API Level 16 26418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu */ 26518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu public boolean swipeDown(int steps) throws UiObjectNotFoundException { 26618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu Tracer.trace(steps); 26718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu Rect rect = getVisibleBounds(); 26818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu if(rect.height() <= SWIPE_MARGIN_LIMIT * 2) 26918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu return false; // too small to swipe 27018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu return getInteractionController().swipe(rect.centerX(), 27118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu rect.top + SWIPE_MARGIN_LIMIT, rect.centerX(), 27218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu rect.bottom - SWIPE_MARGIN_LIMIT, steps); 27318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 27418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 27518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu /** 27618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * Performs the swipe left action on the UiObject. 27718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * The swipe gesture can be performed over any surface. The targeted 27818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * UI element does not need to be scrollable. 27918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * See also: 28018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * <ul> 28118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * <li>{@link UiScrollable#scrollToBeginning(int)}</li> 28218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * <li>{@link UiScrollable#scrollToEnd(int)}</li> 28318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * <li>{@link UiScrollable#scrollBackward()}</li> 28418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * <li>{@link UiScrollable#scrollForward()}</li> 28518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * </ul> 28618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * 28718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @param steps indicates the number of injected move steps into the system. Steps are 28818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * injected about 5ms apart. So a 100 steps may take about 1/2 second to complete. 28918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @return true if successful 29018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @throws UiObjectNotFoundException 29118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @since API Level 16 29218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu */ 29318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu public boolean swipeLeft(int steps) throws UiObjectNotFoundException { 29418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu Tracer.trace(steps); 29518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu Rect rect = getVisibleBounds(); 29618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu if(rect.width() <= SWIPE_MARGIN_LIMIT * 2) 29718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu return false; // too small to swipe 29818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu return getInteractionController().swipe(rect.right - SWIPE_MARGIN_LIMIT, 29918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu rect.centerY(), rect.left + SWIPE_MARGIN_LIMIT, rect.centerY(), steps); 30018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 30118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 30218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu /** 30318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * Performs the swipe right action on the UiObject. 30418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * The swipe gesture can be performed over any surface. The targeted 30518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * UI element does not need to be scrollable. 30618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * See also: 30718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * <ul> 30818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * <li>{@link UiScrollable#scrollToBeginning(int)}</li> 30918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * <li>{@link UiScrollable#scrollToEnd(int)}</li> 31018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * <li>{@link UiScrollable#scrollBackward()}</li> 31118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * <li>{@link UiScrollable#scrollForward()}</li> 31218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * </ul> 31318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * 31418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @param steps indicates the number of injected move steps into the system. Steps are 31518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * injected about 5ms apart. So a 100 steps may take about 1/2 second to complete. 31618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @return true if successful 31718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @throws UiObjectNotFoundException 31818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @since API Level 16 31918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu */ 32018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu public boolean swipeRight(int steps) throws UiObjectNotFoundException { 32118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu Tracer.trace(steps); 32218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu Rect rect = getVisibleBounds(); 32318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu if(rect.width() <= SWIPE_MARGIN_LIMIT * 2) 32418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu return false; // too small to swipe 32518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu return getInteractionController().swipe(rect.left + SWIPE_MARGIN_LIMIT, 32618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu rect.centerY(), rect.right - SWIPE_MARGIN_LIMIT, rect.centerY(), steps); 32718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 32818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 32918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu /** 33018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * Finds the visible bounds of a partially visible UI element 33118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * 33218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @param node 33318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @return null if node is null, else a Rect containing visible bounds 33418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu */ 33518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu private Rect getVisibleBounds(AccessibilityNodeInfo node) { 33618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu if (node == null) { 33718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu return null; 33818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 33918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 34018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu // targeted node's bounds 34118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu int w = UiDevice.getInstance().getDisplayWidth(); 34218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu int h = UiDevice.getInstance().getDisplayHeight(); 34318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu Rect nodeRect = AccessibilityNodeInfoHelper.getVisibleBoundsInScreen(node, w, h); 34418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 34518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu // is the targeted node within a scrollable container? 34618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu AccessibilityNodeInfo scrollableParentNode = getScrollableParent(node); 34718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu if(scrollableParentNode == null) { 34818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu // nothing to adjust for so return the node's Rect as is 34918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu return nodeRect; 35018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 35118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 35218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu // Scrollable parent's visible bounds 35318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu Rect parentRect = AccessibilityNodeInfoHelper 35418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu .getVisibleBoundsInScreen(scrollableParentNode, w, h); 35518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu // adjust for partial clipping of targeted by parent node if required 35618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu nodeRect.intersect(parentRect); 35718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu return nodeRect; 35818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 35918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 36018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu /** 36118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * Walks up the layout hierarchy to find a scrollable parent. A scrollable parent 36218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * indicates that this node might be in a container where it is partially 36318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * visible due to scrolling. In this case, its clickable center might not be visible and 36418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * the click coordinates should be adjusted. 36518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * 36618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @param node 36718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @return The accessibility node info. 36818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu */ 36918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu private AccessibilityNodeInfo getScrollableParent(AccessibilityNodeInfo node) { 37018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu AccessibilityNodeInfo parent = node; 37118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu while(parent != null) { 37218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu parent = parent.getParent(); 37318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu if (parent != null && parent.isScrollable()) { 37418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu return parent; 37518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 37618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 37718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu return null; 37818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 37918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 38018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu /** 38118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * Performs a click at the center of the visible bounds of the UI element represented 38218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * by this UiObject. 38318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * 38418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @return true id successful else false 38518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @throws UiObjectNotFoundException 38618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @since API Level 16 38718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu */ 38818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu public boolean click() throws UiObjectNotFoundException { 38918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu Tracer.trace(); 39018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout()); 39118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu if(node == null) { 39218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 39318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 39418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu Rect rect = getVisibleBounds(node); 39518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu return getInteractionController().clickAndSync(rect.centerX(), rect.centerY(), 39618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu mConfig.getActionAcknowledgmentTimeout()); 39718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 39818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 39918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu /** 40018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * Waits for window transitions that would typically take longer than the 40118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * usual default timeouts. 40218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * See {@link #clickAndWaitForNewWindow(long)} 40318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * 40418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @return true if the event was triggered, else false 40518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @throws UiObjectNotFoundException 40618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @since API Level 16 40718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu */ 40818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu public boolean clickAndWaitForNewWindow() throws UiObjectNotFoundException { 40918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu Tracer.trace(); 41018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu return clickAndWaitForNewWindow(WAIT_FOR_WINDOW_TMEOUT); 41118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 41218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 41318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu /** 41418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * Performs a click at the center of the visible bounds of the UI element represented 41518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * by this UiObject and waits for window transitions. 41618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * 41718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * This method differ from {@link UiObject#click()} only in that this method waits for a 41818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * a new window transition as a result of the click. Some examples of a window transition: 41918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * <li>launching a new activity</li> 42018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * <li>bringing up a pop-up menu</li> 42118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * <li>bringing up a dialog</li> 42218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * 42318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @param timeout timeout before giving up on waiting for a new window 42418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @return true if the event was triggered, else false 42518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @throws UiObjectNotFoundException 42618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @since API Level 16 42718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu */ 42818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu public boolean clickAndWaitForNewWindow(long timeout) throws UiObjectNotFoundException { 42918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu Tracer.trace(timeout); 43018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout()); 43118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu if(node == null) { 43218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 43318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 43418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu Rect rect = getVisibleBounds(node); 43518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu return getInteractionController().clickAndWaitForNewWindow(rect.centerX(), rect.centerY(), 43618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu mConfig.getActionAcknowledgmentTimeout()); 43718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 43818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 43918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu /** 44018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * Clicks the top and left corner of the UI element 44118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * 44218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @return true on success 44318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @throws UiObjectNotFoundException 44418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @since API Level 16 44518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu */ 44618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu public boolean clickTopLeft() throws UiObjectNotFoundException { 44718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu Tracer.trace(); 44818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout()); 44918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu if(node == null) { 45018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 45118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 45218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu Rect rect = getVisibleBounds(node); 45318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu return getInteractionController().clickNoSync(rect.left + 5, rect.top + 5); 45418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 45518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 45618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu /** 45718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * Long clicks bottom and right corner of the UI element 45818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * 45918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @return true if operation was successful 46018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @throws UiObjectNotFoundException 46118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @since API Level 16 46218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu */ 46318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu public boolean longClickBottomRight() throws UiObjectNotFoundException { 46418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu Tracer.trace(); 46518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout()); 46618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu if(node == null) { 46718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 46818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 46918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu Rect rect = getVisibleBounds(node); 47018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu return getInteractionController().longTapNoSync(rect.right - 5, rect.bottom - 5); 47118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 47218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 47318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu /** 47418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * Clicks the bottom and right corner of the UI element 47518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * 47618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @return true on success 47718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @throws UiObjectNotFoundException 47818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @since API Level 16 47918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu */ 48018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu public boolean clickBottomRight() throws UiObjectNotFoundException { 48118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu Tracer.trace(); 48218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout()); 48318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu if(node == null) { 48418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 48518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 48618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu Rect rect = getVisibleBounds(node); 48718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu return getInteractionController().clickNoSync(rect.right - 5, rect.bottom - 5); 48818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 48918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 49018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu /** 49118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * Long clicks the center of the visible bounds of the UI element 49218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * 49318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @return true if operation was successful 49418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @throws UiObjectNotFoundException 49518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @since API Level 16 49618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu */ 49718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu public boolean longClick() throws UiObjectNotFoundException { 49818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu Tracer.trace(); 49918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout()); 50018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu if(node == null) { 50118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 50218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 50318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu Rect rect = getVisibleBounds(node); 50418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu return getInteractionController().longTapNoSync(rect.centerX(), rect.centerY()); 50518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 50618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 50718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu /** 50818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * Long clicks on the top and left corner of the UI element 50918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * 51018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @return true if operation was successful 51118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @throws UiObjectNotFoundException 51218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @since API Level 16 51318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu */ 51418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu public boolean longClickTopLeft() throws UiObjectNotFoundException { 51518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu Tracer.trace(); 51618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout()); 51718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu if(node == null) { 51818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 51918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 52018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu Rect rect = getVisibleBounds(node); 52118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu return getInteractionController().longTapNoSync(rect.left + 5, rect.top + 5); 52218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 52318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 52418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu /** 52518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * Reads the <code>text</code> property of the UI element 52618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * 52718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @return text value of the current node represented by this UiObject 52818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @throws UiObjectNotFoundException if no match could be found 52918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @since API Level 16 53018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu */ 53118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu public String getText() throws UiObjectNotFoundException { 53218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu Tracer.trace(); 53318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout()); 53418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu if(node == null) { 53518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 53618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 53718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu String retVal = safeStringReturn(node.getText()); 53818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu Log.d(LOG_TAG, String.format("getText() = %s", retVal)); 53918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu return retVal; 54018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 54118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 54218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu /** 54318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * Retrieves the <code>className</code> property of the UI element. 54418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * 54518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @return class name of the current node represented by this UiObject 54618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @throws UiObjectNotFoundException if no match was found 54718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @since API Level 18 54818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu */ 54918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu public String getClassName() throws UiObjectNotFoundException { 55018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu Tracer.trace(); 55118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout()); 55218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu if(node == null) { 55318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 55418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 55518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu String retVal = safeStringReturn(node.getClassName()); 55618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu Log.d(LOG_TAG, String.format("getClassName() = %s", retVal)); 55718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu return retVal; 55818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 55918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 56018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu /** 56118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * Reads the <code>content_desc</code> property of the UI element 56218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * 56318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @return value of node attribute "content_desc" 56418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @throws UiObjectNotFoundException 56518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @since API Level 16 56618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu */ 56718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu public String getContentDescription() throws UiObjectNotFoundException { 56818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu Tracer.trace(); 56918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout()); 57018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu if(node == null) { 57118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 57218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 57318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu return safeStringReturn(node.getContentDescription()); 57418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 57518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 57618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu /** 57718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * Sets the text in an editable field, after clearing the field's content. 57818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * 57918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * The {@link UiSelector} selector of this object must reference a UI element that is editable. 58018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * 58118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * When you call this method, the method first simulates a {@link #click()} on 58218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * editable field to set focus. The method then clears the field's contents 58318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * and injects your specified text into the field. 58418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * 58518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * If you want to capture the original contents of the field, call {@link #getText()} first. 58618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * You can then modify the text and use this method to update the field. 58718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * 58818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @param text string to set 58918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @return true if operation is successful 59018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @throws UiObjectNotFoundException 59118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @since API Level 16 59218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu */ 59318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu public boolean setText(String text) throws UiObjectNotFoundException { 59418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu Tracer.trace(text); 59518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu clearTextField(); 59618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu return getInteractionController().sendText(text); 59718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 59818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 59918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu /** 60018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * Clears the existing text contents in an editable field. 60118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * 60218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * The {@link UiSelector} of this object must reference a UI element that is editable. 60318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * 60418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * When you call this method, the method first sets focus at the start edge of the field. 60518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * The method then simulates a long-press to select the existing text, and deletes the 60618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * selected text. 60718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * 60818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * If a "Select-All" option is displayed, the method will automatically attempt to use it 60918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * to ensure full text selection. 61018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * 61118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * Note that it is possible that not all the text in the field is selected; for example, 61218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * if the text contains separators such as spaces, slashes, at symbol etc. 61318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * Also, not all editable fields support the long-press functionality. 61418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * 61518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @throws UiObjectNotFoundException 61618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @since API Level 16 61718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu */ 61818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu public void clearTextField() throws UiObjectNotFoundException { 61918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu Tracer.trace(); 62018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu // long click left + center 62118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout()); 62218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu if(node == null) { 62318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 62418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 62518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu Rect rect = getVisibleBounds(node); 62618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu getInteractionController().longTapNoSync(rect.left + 20, rect.centerY()); 62718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu // check if the edit menu is open 62818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu UiObject selectAll = new UiObject(new UiSelector().descriptionContains("Select all")); 62918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu if(selectAll.waitForExists(50)) 63018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu selectAll.click(); 63118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu // wait for the selection 63218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu SystemClock.sleep(250); 63318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu // delete it 63418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu getInteractionController().sendKey(KeyEvent.KEYCODE_DEL, 0); 63518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 63618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 63718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu /** 63818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * Check if the UI element's <code>checked</code> property is currently true 63918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * 64018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @return true if it is else false 64118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @since API Level 16 64218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu */ 64318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu public boolean isChecked() throws UiObjectNotFoundException { 64418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu Tracer.trace(); 64518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout()); 64618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu if(node == null) { 64718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 64818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 64918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu return node.isChecked(); 65018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 65118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 65218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu /** 65318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * Checks if the UI element's <code>selected</code> property is currently true. 65418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * 65518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @return true if it is else false 65618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @throws UiObjectNotFoundException 65718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @since API Level 16 65818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu */ 65918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu public boolean isSelected() throws UiObjectNotFoundException { 66018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu Tracer.trace(); 66118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout()); 66218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu if(node == null) { 66318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 66418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 66518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu return node.isSelected(); 66618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 66718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 66818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu /** 66918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * Checks if the UI element's <code>checkable</code> property is currently true. 67018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * 67118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @return true if it is else false 67218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @throws UiObjectNotFoundException 67318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @since API Level 16 67418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu */ 67518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu public boolean isCheckable() throws UiObjectNotFoundException { 67618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu Tracer.trace(); 67718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout()); 67818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu if(node == null) { 67918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 68018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 68118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu return node.isCheckable(); 68218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 68318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 68418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu /** 68518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * Checks if the UI element's <code>enabled</code> property is currently true. 68618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * 68718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @return true if it is else false 68818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @throws UiObjectNotFoundException 68918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @since API Level 16 69018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu */ 69118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu public boolean isEnabled() throws UiObjectNotFoundException { 69218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu Tracer.trace(); 69318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout()); 69418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu if(node == null) { 69518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 69618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 69718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu return node.isEnabled(); 69818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 69918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 70018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu /** 70118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * Checks if the UI element's <code>clickable</code> property is currently true. 70218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * 70318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @return true if it is else false 70418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @throws UiObjectNotFoundException 70518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @since API Level 16 70618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu */ 70718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu public boolean isClickable() throws UiObjectNotFoundException { 70818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu Tracer.trace(); 70918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout()); 71018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu if(node == null) { 71118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 71218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 71318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu return node.isClickable(); 71418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 71518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 71618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu /** 71718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * Check if the UI element's <code>focused</code> property is currently true 71818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * 71918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @return true if it is else false 72018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @throws UiObjectNotFoundException 72118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @since API Level 16 72218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu */ 72318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu public boolean isFocused() throws UiObjectNotFoundException { 72418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu Tracer.trace(); 72518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout()); 72618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu if(node == null) { 72718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 72818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 72918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu return node.isFocused(); 73018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 73118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 73218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu /** 73318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * Check if the UI element's <code>focusable</code> property is currently true. 73418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * 73518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @return true if it is else false 73618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @throws UiObjectNotFoundException 73718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @since API Level 16 73818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu */ 73918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu public boolean isFocusable() throws UiObjectNotFoundException { 74018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu Tracer.trace(); 74118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout()); 74218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu if(node == null) { 74318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 74418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 74518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu return node.isFocusable(); 74618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 74718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 74818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu /** 74918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * Check if the view's <code>scrollable</code> property is currently true 75018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * 75118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @return true if it is else false 75218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @throws UiObjectNotFoundException 75318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @since API Level 16 75418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu */ 75518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu public boolean isScrollable() throws UiObjectNotFoundException { 75618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu Tracer.trace(); 75718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout()); 75818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu if(node == null) { 75918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 76018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 76118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu return node.isScrollable(); 76218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 76318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 76418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu /** 76518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * Check if the view's <code>long-clickable</code> property is currently true 76618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * 76718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @return true if it is else false 76818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @throws UiObjectNotFoundException 76918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @since API Level 16 77018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu */ 77118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu public boolean isLongClickable() throws UiObjectNotFoundException { 77218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu Tracer.trace(); 77318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout()); 77418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu if(node == null) { 77518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 77618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 77718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu return node.isLongClickable(); 77818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 77918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 78018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu /** 78118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * Reads the view's <code>package</code> property 78218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * 78318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @return true if it is else false 78418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @throws UiObjectNotFoundException 78518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @since API Level 16 78618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu */ 78718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu public String getPackageName() throws UiObjectNotFoundException { 78818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu Tracer.trace(); 78918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout()); 79018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu if(node == null) { 79118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 79218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 79318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu return safeStringReturn(node.getPackageName()); 79418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 79518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 79618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu /** 79718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * Returns the visible bounds of the view. 79818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * 79918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * If a portion of the view is visible, only the bounds of the visible portion are 80018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * reported. 80118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * 80218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @return Rect 80318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @throws UiObjectNotFoundException 80418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @see {@link #getBounds()} 80518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @since API Level 17 80618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu */ 80718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu public Rect getVisibleBounds() throws UiObjectNotFoundException { 80818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu Tracer.trace(); 80918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout()); 81018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu if(node == null) { 81118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 81218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 81318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu return getVisibleBounds(node); 81418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 81518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 81618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu /** 81718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * Returns the view's <code>bounds</code> property. See {@link #getVisibleBounds()} 81818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * 81918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @return Rect 82018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @throws UiObjectNotFoundException 82118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @since API Level 16 82218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu */ 82318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu public Rect getBounds() throws UiObjectNotFoundException { 82418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu Tracer.trace(); 82518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout()); 82618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu if(node == null) { 82718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 82818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 82918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu Rect nodeRect = new Rect(); 83018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu node.getBoundsInScreen(nodeRect); 83118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 83218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu return nodeRect; 83318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 83418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 83518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu /** 83618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * Waits a specified length of time for a view to become visible. 83718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * 83818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * This method waits until the view becomes visible on the display, or 83918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * until the timeout has elapsed. You can use this method in situations where 84018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * the content that you want to select is not immediately displayed. 84118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * 84218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @param timeout the amount of time to wait (in milliseconds) 84318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @return true if the view is displayed, else false if timeout elapsed while waiting 84418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @since API Level 16 84518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu */ 84618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu public boolean waitForExists(long timeout) { 84718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu Tracer.trace(timeout); 84818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu if(findAccessibilityNodeInfo(timeout) != null) { 84918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu return true; 85018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 85118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu return false; 85218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 85318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 85418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu /** 85518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * Waits a specified length of time for a view to become undetectable. 85618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * 85718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * This method waits until a view is no longer matchable, or until the 85818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * timeout has elapsed. 85918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * 86018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * A view becomes undetectable when the {@link UiSelector} of the object is 86118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * unable to find a match because the element has either changed its state or is no 86218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * longer displayed. 86318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * 86418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * You can use this method when attempting to wait for some long operation 86518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * to compete, such as downloading a large file or connecting to a remote server. 86618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * 86718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @param timeout time to wait (in milliseconds) 86818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @return true if the element is gone before timeout elapsed, else false if timeout elapsed 86918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * but a matching element is still found. 87018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @since API Level 16 87118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu */ 87218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu public boolean waitUntilGone(long timeout) { 87318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu Tracer.trace(timeout); 87418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu long startMills = SystemClock.uptimeMillis(); 87518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu long currentMills = 0; 87618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu while (currentMills <= timeout) { 87718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu if(findAccessibilityNodeInfo(0) == null) 87818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu return true; 87918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu currentMills = SystemClock.uptimeMillis() - startMills; 88018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu if(timeout > 0) 88118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu SystemClock.sleep(WAIT_FOR_SELECTOR_POLL); 88218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 88318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu return false; 88418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 88518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 88618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu /** 88718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * Check if view exists. 88818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * 88918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * This methods performs a {@link #waitForExists(long)} with zero timeout. This 89018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * basically returns immediately whether the view represented by this UiObject 89118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * exists or not. If you need to wait longer for this view, then see 89218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * {@link #waitForExists(long)}. 89318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * 89418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @return true if the view represented by this UiObject does exist 89518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @since API Level 16 89618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu */ 89718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu public boolean exists() { 89818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu Tracer.trace(); 89918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu return waitForExists(0); 90018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 90118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 90218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu private String safeStringReturn(CharSequence cs) { 90318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu if(cs == null) 90418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu return ""; 90518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu return cs.toString(); 90618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 90718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 90818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu /** 90918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * Performs a two-pointer gesture, where each pointer moves diagonally 91018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * opposite across the other, from the center out towards the edges of the 91118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * this UiObject. 91218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @param percent percentage of the object's diagonal length for the pinch gesture 91318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @param steps the number of steps for the gesture. Steps are injected 91418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * about 5 milliseconds apart, so 100 steps may take around 0.5 seconds to complete. 91518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @return <code>true</code> if all touch events for this gesture are injected successfully, 91618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * <code>false</code> otherwise 91718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @throws UiObjectNotFoundException 91818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @since API Level 18 91918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu */ 92018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu public boolean pinchOut(int percent, int steps) throws UiObjectNotFoundException { 92118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu // make value between 1 and 100 92218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu percent = (percent < 0) ? 1 : (percent > 100) ? 100 : percent; 92318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu float percentage = percent / 100f; 92418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 92518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout()); 92618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu if (node == null) { 92718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 92818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 92918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 93018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu Rect rect = getVisibleBounds(node); 93118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu if (rect.width() <= FINGER_TOUCH_HALF_WIDTH * 2) 93218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu throw new IllegalStateException("Object width is too small for operation"); 93318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 93418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu // start from the same point at the center of the control 93518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu Point startPoint1 = new Point(rect.centerX() - FINGER_TOUCH_HALF_WIDTH, rect.centerY()); 93618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu Point startPoint2 = new Point(rect.centerX() + FINGER_TOUCH_HALF_WIDTH, rect.centerY()); 93718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 93818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu // End at the top-left and bottom-right corners of the control 93918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu Point endPoint1 = new Point(rect.centerX() - (int)((rect.width()/2) * percentage), 94018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu rect.centerY()); 94118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu Point endPoint2 = new Point(rect.centerX() + (int)((rect.width()/2) * percentage), 94218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu rect.centerY()); 94318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 94418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu return performTwoPointerGesture(startPoint1, startPoint2, endPoint1, endPoint2, steps); 94518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 94618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 94718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu /** 94818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * Performs a two-pointer gesture, where each pointer moves diagonally 94918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * toward the other, from the edges to the center of this UiObject . 95018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @param percent percentage of the object's diagonal length for the pinch gesture 95118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @param steps the number of steps for the gesture. Steps are injected 95218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * about 5 milliseconds apart, so 100 steps may take around 0.5 seconds to complete. 95318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @return <code>true</code> if all touch events for this gesture are injected successfully, 95418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * <code>false</code> otherwise 95518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @throws UiObjectNotFoundException 95618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @since API Level 18 95718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu */ 95818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu public boolean pinchIn(int percent, int steps) throws UiObjectNotFoundException { 95918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu // make value between 1 and 100 96018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu percent = (percent < 0) ? 0 : (percent > 100) ? 100 : percent; 96118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu float percentage = percent / 100f; 96218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 96318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout()); 96418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu if (node == null) { 96518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 96618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 96718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 96818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu Rect rect = getVisibleBounds(node); 96918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu if (rect.width() <= FINGER_TOUCH_HALF_WIDTH * 2) 97018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu throw new IllegalStateException("Object width is too small for operation"); 97118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 97218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu Point startPoint1 = new Point(rect.centerX() - (int)((rect.width()/2) * percentage), 97318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu rect.centerY()); 97418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu Point startPoint2 = new Point(rect.centerX() + (int)((rect.width()/2) * percentage), 97518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu rect.centerY()); 97618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 97718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu Point endPoint1 = new Point(rect.centerX() - FINGER_TOUCH_HALF_WIDTH, rect.centerY()); 97818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu Point endPoint2 = new Point(rect.centerX() + FINGER_TOUCH_HALF_WIDTH, rect.centerY()); 97918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 98018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu return performTwoPointerGesture(startPoint1, startPoint2, endPoint1, endPoint2, steps); 98118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 98218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 98318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu /** 98418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * Generates a two-pointer gesture with arbitrary starting and ending points. 98518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * 98618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @param startPoint1 start point of pointer 1 98718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @param startPoint2 start point of pointer 2 98818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @param endPoint1 end point of pointer 1 98918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @param endPoint2 end point of pointer 2 99018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @param steps the number of steps for the gesture. Steps are injected 99118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * about 5 milliseconds apart, so 100 steps may take around 0.5 seconds to complete. 99218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @return <code>true</code> if all touch events for this gesture are injected successfully, 99318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * <code>false</code> otherwise 99418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @since API Level 18 99518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu */ 99618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu public boolean performTwoPointerGesture(Point startPoint1, Point startPoint2, Point endPoint1, 99718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu Point endPoint2, int steps) { 99818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 99918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu // avoid a divide by zero 100018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu if(steps == 0) 100118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu steps = 1; 100218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 100318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu final float stepX1 = (endPoint1.x - startPoint1.x) / steps; 100418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu final float stepY1 = (endPoint1.y - startPoint1.y) / steps; 100518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu final float stepX2 = (endPoint2.x - startPoint2.x) / steps; 100618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu final float stepY2 = (endPoint2.y - startPoint2.y) / steps; 100718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 100818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu int eventX1, eventY1, eventX2, eventY2; 100918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu eventX1 = startPoint1.x; 101018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu eventY1 = startPoint1.y; 101118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu eventX2 = startPoint2.x; 101218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu eventY2 = startPoint2.y; 101318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 101418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu // allocate for steps plus first down and last up 101518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu PointerCoords[] points1 = new PointerCoords[steps + 2]; 101618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu PointerCoords[] points2 = new PointerCoords[steps + 2]; 101718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 101818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu // Include the first and last touch downs in the arrays of steps 101918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu for (int i = 0; i < steps + 1; i++) { 102018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu PointerCoords p1 = new PointerCoords(); 102118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu p1.x = eventX1; 102218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu p1.y = eventY1; 102318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu p1.pressure = 1; 102418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu p1.size = 1; 102518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu points1[i] = p1; 102618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 102718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu PointerCoords p2 = new PointerCoords(); 102818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu p2.x = eventX2; 102918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu p2.y = eventY2; 103018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu p2.pressure = 1; 103118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu p2.size = 1; 103218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu points2[i] = p2; 103318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 103418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu eventX1 += stepX1; 103518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu eventY1 += stepY1; 103618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu eventX2 += stepX2; 103718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu eventY2 += stepY2; 103818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 103918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 104018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu // ending pointers coordinates 104118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu PointerCoords p1 = new PointerCoords(); 104218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu p1.x = endPoint1.x; 104318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu p1.y = endPoint1.y; 104418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu p1.pressure = 1; 104518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu p1.size = 1; 104618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu points1[steps + 1] = p1; 104718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 104818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu PointerCoords p2 = new PointerCoords(); 104918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu p2.x = endPoint2.x; 105018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu p2.y = endPoint2.y; 105118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu p2.pressure = 1; 105218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu p2.size = 1; 105318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu points2[steps + 1] = p2; 105418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 105518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu return performMultiPointerGesture(points1, points2); 105618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 105718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 105818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu /** 105918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * Performs a multi-touch gesture. You must specify touch coordinates for 106018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * at least 2 pointers. Each pointer must have all of its touch steps 106118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * defined in an array of {@link PointerCoords}. You can use this method to 106218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * specify complex gestures, like circles and irregular shapes, where each 106318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * pointer may take a different path. 106418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * 106518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * To create a single point on a pointer's touch path: 106618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * <code> 106718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * PointerCoords p = new PointerCoords(); 106818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * p.x = stepX; 106918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * p.y = stepY; 107018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * p.pressure = 1; 107118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * p.size = 1; 107218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * </code> 107318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @param touches represents the pointers' paths. Each {@link PointerCoords} 107418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * array represents a different pointer. Each {@link PointerCoords} in an 107518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * array element represents a touch point on a pointer's path. 107618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @return <code>true</code> if all touch events for this gesture are injected successfully, 107718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * <code>false</code> otherwise 107818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @since API Level 18 107918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu */ 108018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu public boolean performMultiPointerGesture(PointerCoords[] ...touches) { 108118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu return getInteractionController().performMultiPointerGesture(touches); 108218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 108318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu} 1084