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