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