UiObject.java revision 1078ab1070411af45d5e8ec3b56abec6789e7722
1e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu/*
2e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * Copyright (C) 2012 The Android Open Source Project
3e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu *
4e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * Licensed under the Apache License, Version 2.0 (the "License");
5e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * you may not use this file except in compliance with the License.
6e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * You may obtain a copy of the License at
7e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu *
8e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu *      http://www.apache.org/licenses/LICENSE-2.0
9e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu *
10e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * Unless required by applicable law or agreed to in writing, software
11e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * distributed under the License is distributed on an "AS IS" BASIS,
12e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * See the License for the specific language governing permissions and
14e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * limitations under the License.
15e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */
16e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
17e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhupackage com.android.uiautomator.core;
18e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
19c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtazimport android.graphics.Point;
20e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhuimport android.graphics.Rect;
21e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhuimport android.os.SystemClock;
22e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhuimport android.util.Log;
23e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhuimport android.view.KeyEvent;
24c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtazimport android.view.MotionEvent.PointerCoords;
25e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhuimport android.view.accessibility.AccessibilityNodeInfo;
26e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
27e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu/**
2846d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * A UiObject is a representation of a UI element. It is not in any way directly bound to a
2946d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * UI element as an object reference. A UiObject holds information to help it
3046d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * locate a matching UI element at runtime based on the {@link UiSelector} properties specified in
3146d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * its constructor. Since a UiObject is a representative for a UI element, it can
3246d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * be reused for different views with matching UI elements.
33dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16
34e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */
35e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhupublic class UiObject {
36e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    private static final String LOG_TAG = UiObject.class.getSimpleName();
37dbba713661688a285e701a006ce2d199296ac328Guang Zhu    /**
38dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
390d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz     * @deprecated use {@link Configurator#setWaitForSelectorTimeout(long)}
40dbba713661688a285e701a006ce2d199296ac328Guang Zhu     **/
410d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz    @Deprecated
42e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    protected static final long WAIT_FOR_SELECTOR_TIMEOUT = 10 * 1000;
43dbba713661688a285e701a006ce2d199296ac328Guang Zhu    /**
44dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
45dbba713661688a285e701a006ce2d199296ac328Guang Zhu     **/
46e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    protected static final long WAIT_FOR_SELECTOR_POLL = 1000;
47e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    // set a default timeout to 5.5s, since ANR threshold is 5s
48dbba713661688a285e701a006ce2d199296ac328Guang Zhu    /**
49dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
50dbba713661688a285e701a006ce2d199296ac328Guang Zhu     **/
51e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    protected static final long WAIT_FOR_WINDOW_TMEOUT = 5500;
52dbba713661688a285e701a006ce2d199296ac328Guang Zhu    /**
53c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz     * @since API Level 16
54c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz     **/
55c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz    protected static final int SWIPE_MARGIN_LIMIT = 5;
56c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz    /**
57dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 17
580d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz     * @deprecated use {@link Configurator#setScrollAcknowledgmentTimeout(long)}
59dbba713661688a285e701a006ce2d199296ac328Guang Zhu     **/
600d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz    @Deprecated
616088c8f9e34e34a4958b1601ed7c1bb34c95da21Adam Momtaz    protected static final long WAIT_FOR_EVENT_TMEOUT = 3 * 1000;
62dbba713661688a285e701a006ce2d199296ac328Guang Zhu    /**
63c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz     * @since API Level 18
64dbba713661688a285e701a006ce2d199296ac328Guang Zhu     **/
65c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz    protected static final int FINGER_TOUCH_HALF_WIDTH = 20;
66e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
677f38ef08d07295967b905a61b2356ff6cdf31159Adam Momtaz    private final UiSelector mSelector;
68ddc1008f06fd2a875037026490ce1f848a442572Guang Zhu    private final UiAutomatorBridge mUiAutomationBridge;
69e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
700d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz    private final Configurator mConfig = Configurator.getInstance();
710d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz
72e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
733d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * Constructs a UiObject to represent a specific UI element matched by the specified
743d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * {@link UiSelector} selector properties.
75e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @param selector
76dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
77e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
784ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz    public UiObject(UiSelector selector) {
79e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        mUiAutomationBridge = UiDevice.getInstance().getAutomatorBridge();
80e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        mSelector = selector;
81e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
82e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
83e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
843d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * Debugging helper. A test can dump the properties of a selector as a string
853d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * to its logs if needed. <code>getSelector().toString();</code>
863d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
874ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz     * @return {@link UiSelector}
88dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
89e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
904ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz    public final UiSelector getSelector() {
91f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine        Tracer.trace();
924ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz        return new UiSelector(mSelector);
93e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
94e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
95e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
963d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * Retrieves the {@link QueryController} to translate a {@link UiSelector} selector
973d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * into an {@link AccessibilityNodeInfo}.
983d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
99e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @return {@link QueryController}
100e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
101ddc1008f06fd2a875037026490ce1f848a442572Guang Zhu    QueryController getQueryController() {
102e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        return mUiAutomationBridge.getQueryController();
103e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
104e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
105e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
1063d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * Retrieves the {@link InteractionController} to perform finger actions such as tapping,
1073d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * swiping or entering text.
1083d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
109e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @return {@link InteractionController}
110e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
111ddc1008f06fd2a875037026490ce1f848a442572Guang Zhu    InteractionController getInteractionController() {
112e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        return mUiAutomationBridge.getInteractionController();
113e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
114e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
115e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
1163d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * Creates a new UiObject representing a child UI element of the element currently represented
1173d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * by this UiObject.
1183d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
1193d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * @param selector for UI element to match
1203d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * @return a new UiObject representing the matched UI element
121dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
122e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
1234ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz    public UiObject getChild(UiSelector selector) throws UiObjectNotFoundException {
124f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine        Tracer.trace(selector);
1254ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz        return new UiObject(getSelector().childSelector(selector));
126e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
127e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
128e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
1293d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * Creates a new UiObject representing a child UI element from the parent element currently
1303d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * represented by this object. Essentially this is starting the search from the parent
1313d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * element and can also be used to find sibling UI elements to the one currently represented
1323d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * by this UiObject.
1333d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
1343d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * @param selector for the UI element to match
1353d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * @return a new UiObject representing the matched UI element
136e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @throws UiObjectNotFoundException
137dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
138e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
1394ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz    public UiObject getFromParent(UiSelector selector) throws UiObjectNotFoundException {
140f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine        Tracer.trace(selector);
1414ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz        return new UiObject(getSelector().fromParent(selector));
142e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
143e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
144e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
1453d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * Counts the child UI elements immediately under the UI element currently represented by
146e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * this UiObject.
1473d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
148e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @return the count of child UI elements.
149e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @throws UiObjectNotFoundException
150dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
151e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
152e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    public int getChildCount() throws UiObjectNotFoundException {
153f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine        Tracer.trace();
1540d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz        AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout());
155e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        if(node == null) {
156e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            throw new UiObjectNotFoundException(getSelector().toString());
157e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
158e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        return node.getChildCount();
159e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
160e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
161e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
1623d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * Uses the member UiSelector properties to find a matching UI element reported in
1633d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * the accessibility hierarchy.
1643d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
165e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @param timeout in milliseconds
166e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @return AccessibilityNodeInfo if found else null
167dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
168e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
169e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    protected AccessibilityNodeInfo findAccessibilityNodeInfo(long timeout) {
170e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        AccessibilityNodeInfo node = null;
171bb36257f15f090966e2aeb9fd4f092e1a54722b1Adam Momtaz        long startMills = SystemClock.uptimeMillis();
172bb36257f15f090966e2aeb9fd4f092e1a54722b1Adam Momtaz        long currentMills = 0;
173bb36257f15f090966e2aeb9fd4f092e1a54722b1Adam Momtaz        while (currentMills <= timeout) {
174e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            node = getQueryController().findAccessibilityNodeInfo(getSelector());
175bb36257f15f090966e2aeb9fd4f092e1a54722b1Adam Momtaz            if (node != null) {
176bb36257f15f090966e2aeb9fd4f092e1a54722b1Adam Momtaz                break;
177bb36257f15f090966e2aeb9fd4f092e1a54722b1Adam Momtaz            } else {
178bb36257f15f090966e2aeb9fd4f092e1a54722b1Adam Momtaz                // does nothing if we're reentering another runWatchers()
179bb36257f15f090966e2aeb9fd4f092e1a54722b1Adam Momtaz                UiDevice.getInstance().runWatchers();
180bb36257f15f090966e2aeb9fd4f092e1a54722b1Adam Momtaz            }
181bb36257f15f090966e2aeb9fd4f092e1a54722b1Adam Momtaz            currentMills = SystemClock.uptimeMillis() - startMills;
182bb36257f15f090966e2aeb9fd4f092e1a54722b1Adam Momtaz            if(timeout > 0) {
183bb36257f15f090966e2aeb9fd4f092e1a54722b1Adam Momtaz                SystemClock.sleep(WAIT_FOR_SELECTOR_POLL);
184e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            }
185e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
186e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        return node;
187e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
188e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
189e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
1908d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz     * Performs a drag of this object to a destination UiObject. Note that the number of steps
1918d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz     * used can influence the drag speed and varying speeds may impact the results. Consider
1928d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz     * evaluating different speeds when testing this method.
1938d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz     *
1948d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz     * @param destObj
1958d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz     * @param steps usually 40 steps. More or less to change the speed.
1968d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz     * @return true of successful
1978d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz     * @throws UiObjectNotFoundException
1988d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz     * @since API Level 18
1998d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz     */
2008d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz    public boolean dragTo(UiObject destObj, int steps) throws UiObjectNotFoundException {
2018d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz        Rect srcRect = getVisibleBounds();
2028d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz        Rect dstRect = destObj.getVisibleBounds();
2038d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz        return getInteractionController().swipe(srcRect.centerX(), srcRect.centerY(),
2048d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz                dstRect.centerX(), dstRect.centerY(), steps, true);
2058d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz    }
2068d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz
2078d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz    /**
2088d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz     * Performs a drag of this object to arbitrary coordinates. Note that the number of steps
2098d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz     * used will influence the drag speed and varying speeds may impact the results. Consider
2108d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz     * evaluating different speeds when testing this method.
2118d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz     *
2128d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz     * @param destX
2138d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz     * @param destY
2148d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz     * @param steps
2158d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz     * @return true of successful
2168d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz     * @throws UiObjectNotFoundException
2178d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz     * @since API Level 18
2188d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz     */
2198d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz    public boolean dragTo(int destX, int destY, int steps) throws UiObjectNotFoundException {
2208d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz        Rect srcRect = getVisibleBounds();
2218d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz        return getInteractionController().swipe(srcRect.centerX(), srcRect.centerY(), destX, destY,
2228d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz                steps, true);
2238d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz    }
2248d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz
2258d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz    /**
2263d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * Perform the action on the UI element that is represented by this UiObject. Also see
2271893caed0ad4e73b0676f206282d490c2d345316Thanh Le     * {@link UiScrollable#scrollToBeginning(int)}, {@link UiScrollable#scrollToEnd(int)},
2281893caed0ad4e73b0676f206282d490c2d345316Thanh Le     * {@link UiScrollable#scrollBackward()}, {@link UiScrollable#scrollForward()}.
2293d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
230467cca7d25dbbf13c14cfd8c2ad38ab8eaf56bdaAdam Momtaz     * @param steps indicates the number of injected move steps into the system. Steps are
231467cca7d25dbbf13c14cfd8c2ad38ab8eaf56bdaAdam Momtaz     * injected about 5ms apart. So a 100 steps may take about 1/2 second to complete.
2323d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * @return true of successful
233e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @throws UiObjectNotFoundException
234dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
235e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
236e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    public boolean swipeUp(int steps) throws UiObjectNotFoundException {
237f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine        Tracer.trace(steps);
2383d50587be8ff021369c90554d814839335b445b0Adam Momtaz        Rect rect = getVisibleBounds();
239e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        if(rect.height() <= SWIPE_MARGIN_LIMIT * 2)
240e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            return false; // too small to swipe
241e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        return getInteractionController().swipe(rect.centerX(),
242e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                rect.bottom - SWIPE_MARGIN_LIMIT, rect.centerX(), rect.top + SWIPE_MARGIN_LIMIT,
243e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                steps);
244e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
245e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
246e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
247e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * Perform the action on the UI element that is represented by this object, Also see
2481893caed0ad4e73b0676f206282d490c2d345316Thanh Le     * {@link UiScrollable#scrollToBeginning(int)}, {@link UiScrollable#scrollToEnd(int)},
2491893caed0ad4e73b0676f206282d490c2d345316Thanh Le     * {@link UiScrollable#scrollBackward()}, {@link UiScrollable#scrollForward()}. This method will
2501893caed0ad4e73b0676f206282d490c2d345316Thanh Le     * perform the swipe gesture over any surface.  The targeted UI element does not need to have
2511893caed0ad4e73b0676f206282d490c2d345316Thanh Le     * the attribute <code>scrollable</code> set to <code>true</code> for this operation to be
2521893caed0ad4e73b0676f206282d490c2d345316Thanh Le     * performed.
2533d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
2543d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * @param steps indicates the number of injected move steps into the system. Steps are
255467cca7d25dbbf13c14cfd8c2ad38ab8eaf56bdaAdam Momtaz     * injected about 5ms apart. So a 100 steps may take about 1/2 second to complete.
2563d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * @return true if successful
257e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @throws UiObjectNotFoundException
258dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
259e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
260e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    public boolean swipeDown(int steps) throws UiObjectNotFoundException {
261f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine        Tracer.trace(steps);
2623d50587be8ff021369c90554d814839335b445b0Adam Momtaz        Rect rect = getVisibleBounds();
263e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        if(rect.height() <= SWIPE_MARGIN_LIMIT * 2)
264e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            return false; // too small to swipe
265e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        return getInteractionController().swipe(rect.centerX(),
266e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                rect.top + SWIPE_MARGIN_LIMIT, rect.centerX(),
267e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                rect.bottom - SWIPE_MARGIN_LIMIT, steps);
268e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
269e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
270e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
271e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * Perform the action on the UI element that is represented by this object. Also see
2721893caed0ad4e73b0676f206282d490c2d345316Thanh Le     * {@link UiScrollable#scrollToBeginning(int)}, {@link UiScrollable#scrollToEnd(int)},
2731893caed0ad4e73b0676f206282d490c2d345316Thanh Le     * {@link UiScrollable#scrollBackward()}, {@link UiScrollable#scrollForward()}. This method will
2741893caed0ad4e73b0676f206282d490c2d345316Thanh Le     * perform the swipe gesture over any surface. The targeted UI element does not need to have the
2751893caed0ad4e73b0676f206282d490c2d345316Thanh Le     * attribute <code>scrollable</code> set to <code>true</code> for this operation to be
2761893caed0ad4e73b0676f206282d490c2d345316Thanh Le     * performed.
2773d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
2783d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * @param steps indicates the number of injected move steps into the system. Steps are
279467cca7d25dbbf13c14cfd8c2ad38ab8eaf56bdaAdam Momtaz     * injected about 5ms apart. So a 100 steps may take about 1/2 second to complete.
2803d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * @return true if successful
281e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @throws UiObjectNotFoundException
282dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
283e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
284e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    public boolean swipeLeft(int steps) throws UiObjectNotFoundException {
285f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine        Tracer.trace(steps);
2863d50587be8ff021369c90554d814839335b445b0Adam Momtaz        Rect rect = getVisibleBounds();
287e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        if(rect.width() <= SWIPE_MARGIN_LIMIT * 2)
288e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            return false; // too small to swipe
289e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        return getInteractionController().swipe(rect.right - SWIPE_MARGIN_LIMIT,
290e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                rect.centerY(), rect.left + SWIPE_MARGIN_LIMIT, rect.centerY(), steps);
291e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
292e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
293e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
294e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * Perform the action on the UI element that is represented by this object. Also see
2951893caed0ad4e73b0676f206282d490c2d345316Thanh Le     * {@link UiScrollable#scrollToBeginning(int)}, {@link UiScrollable#scrollToEnd(int)},
2961893caed0ad4e73b0676f206282d490c2d345316Thanh Le     * {@link UiScrollable#scrollBackward()}, {@link UiScrollable#scrollForward()}. This method will
2971893caed0ad4e73b0676f206282d490c2d345316Thanh Le     * perform the swipe gesture over any surface. The targeted UI element does not need to have the
2981893caed0ad4e73b0676f206282d490c2d345316Thanh Le     * attribute <code>scrollable</code> set to <code>true</code> for this operation to be
2991893caed0ad4e73b0676f206282d490c2d345316Thanh Le     * performed.
3003d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
3013d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * @param steps indicates the number of injected move steps into the system. Steps are
302467cca7d25dbbf13c14cfd8c2ad38ab8eaf56bdaAdam Momtaz     * injected about 5ms apart. So a 100 steps may take about 1/2 second to complete.
3033d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * @return true if successful
304e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @throws UiObjectNotFoundException
305dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
306e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
307e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    public boolean swipeRight(int steps) throws UiObjectNotFoundException {
308f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine        Tracer.trace(steps);
3093d50587be8ff021369c90554d814839335b445b0Adam Momtaz        Rect rect = getVisibleBounds();
310e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        if(rect.width() <= SWIPE_MARGIN_LIMIT * 2)
311e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            return false; // too small to swipe
312e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        return getInteractionController().swipe(rect.left + SWIPE_MARGIN_LIMIT,
313e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                rect.centerY(), rect.right - SWIPE_MARGIN_LIMIT, rect.centerY(), steps);
314e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
315e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
316e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
3173d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * Finds the visible bounds of a partially visible UI element
3183d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
319e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @param node
3207f38ef08d07295967b905a61b2356ff6cdf31159Adam Momtaz     * @return null if node is null, else a Rect containing visible bounds
321e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
322e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    private Rect getVisibleBounds(AccessibilityNodeInfo node) {
323e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        if (node == null) {
324e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            return null;
325e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
326e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
327e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        // targeted node's bounds
32823296fc6448cd265fbb45c1fd9041976ae0da274Guang Zhu        int w = UiDevice.getInstance().getDisplayWidth();
32923296fc6448cd265fbb45c1fd9041976ae0da274Guang Zhu        int h = UiDevice.getInstance().getDisplayHeight();
33023296fc6448cd265fbb45c1fd9041976ae0da274Guang Zhu        Rect nodeRect = AccessibilityNodeInfoHelper.getVisibleBoundsInScreen(node, w, h);
331e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
332e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        // is the targeted node within a scrollable container?
333e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        AccessibilityNodeInfo scrollableParentNode = getScrollableParent(node);
334e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        if(scrollableParentNode == null) {
335e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            // nothing to adjust for so return the node's Rect as is
336e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            return nodeRect;
337e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
338e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
339e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        // Scrollable parent's visible bounds
3407f38ef08d07295967b905a61b2356ff6cdf31159Adam Momtaz        Rect parentRect = AccessibilityNodeInfoHelper
34123296fc6448cd265fbb45c1fd9041976ae0da274Guang Zhu                .getVisibleBoundsInScreen(scrollableParentNode, w, h);
342e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        // adjust for partial clipping of targeted by parent node if required
343e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        nodeRect.intersect(parentRect);
344e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        return nodeRect;
345e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
346e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
347e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
3487f38ef08d07295967b905a61b2356ff6cdf31159Adam Momtaz     * Walk the hierarchy up to find a scrollable parent. A scrollable parent
3497f38ef08d07295967b905a61b2356ff6cdf31159Adam Momtaz     * indicates that this node may be in a content where it is partially
3507f38ef08d07295967b905a61b2356ff6cdf31159Adam Momtaz     * visible due to scrolling. its clickable center maybe invisible and
3517f38ef08d07295967b905a61b2356ff6cdf31159Adam Momtaz     * adjustments should be made to the click coordinates.
3523d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
353e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @param node
3541893caed0ad4e73b0676f206282d490c2d345316Thanh Le     * @return The accessibility node info.
355e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
356e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    private AccessibilityNodeInfo getScrollableParent(AccessibilityNodeInfo node) {
357e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        AccessibilityNodeInfo parent = node;
358e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        while(parent != null) {
359e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            parent = parent.getParent();
360e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            if (parent != null && parent.isScrollable()) {
361e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                return parent;
362e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            }
363e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
364e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        return null;
365e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
366e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
367e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
3683d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * Performs a click at the center of the visible bounds of the UI element represented
36946d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * by this UiObject.
3703d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
371e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @return true id successful else false
372e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @throws UiObjectNotFoundException
373dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
374e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
375e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    public boolean click() throws UiObjectNotFoundException {
376f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine        Tracer.trace();
3770d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz        AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout());
378e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        if(node == null) {
379e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            throw new UiObjectNotFoundException(getSelector().toString());
380e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
381e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        Rect rect = getVisibleBounds(node);
3820d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz        return getInteractionController().clickAndSync(rect.centerX(), rect.centerY(),
3830d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz                mConfig.getActionAcknowledgmentTimeout());
384e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
385e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
386e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
3873d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * See {@link #clickAndWaitForNewWindow(long)}
388a46ac3504426564954292b13380120e8cc6b1527Adam Momtaz     * This method is intended to reliably wait for window transitions that would typically take
389a46ac3504426564954292b13380120e8cc6b1527Adam Momtaz     * longer than the usual default timeouts.
3903d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
3913d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * @return true if the event was triggered, else false
3923d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * @throws UiObjectNotFoundException
393dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
3943d50587be8ff021369c90554d814839335b445b0Adam Momtaz     */
395e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    public boolean clickAndWaitForNewWindow() throws UiObjectNotFoundException {
396f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine        Tracer.trace();
397e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        return clickAndWaitForNewWindow(WAIT_FOR_WINDOW_TMEOUT);
398e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
399e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
400e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
40146d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * Performs a click at the center of the visible bounds of the UI element represented
40246d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * by this UiObject and waits for window transitions.
40346d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     *
4043d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * This method differ from {@link UiObject#click()} only in that this method waits for a
40546d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * a new window transition as a result of the click. Some examples of a window transition:
406e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * <li>launching a new activity</li>
407e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * <li>bringing up a pop-up menu</li>
408e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * <li>bringing up a dialog</li>
409e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     *
4103d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * @param timeout timeout before giving up on waiting for a new window
411e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @return true if the event was triggered, else false
412e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @throws UiObjectNotFoundException
413dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
414e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
415e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    public boolean clickAndWaitForNewWindow(long timeout) throws UiObjectNotFoundException {
416f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine        Tracer.trace(timeout);
4170d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz        AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout());
418e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        if(node == null) {
419e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            throw new UiObjectNotFoundException(getSelector().toString());
420e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
421e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        Rect rect = getVisibleBounds(node);
4220d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz        return getInteractionController().clickAndWaitForNewWindow(rect.centerX(), rect.centerY(),
4230d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz                mConfig.getActionAcknowledgmentTimeout());
424e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
425e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
426e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
4273d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * Clicks the top and left corner of the UI element
4283d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
429e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @return true on success
4301893caed0ad4e73b0676f206282d490c2d345316Thanh Le     * @throws UiObjectNotFoundException
431dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
432e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
433e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    public boolean clickTopLeft() throws UiObjectNotFoundException {
434f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine        Tracer.trace();
4350d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz        AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout());
436e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        if(node == null) {
437e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            throw new UiObjectNotFoundException(getSelector().toString());
438e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
439e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        Rect rect = getVisibleBounds(node);
4401dc7d12406947faaee8454c6efb2a0631f5da573Adam Momtaz        return getInteractionController().clickNoSync(rect.left + 5, rect.top + 5);
441e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
442e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
443e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
4443d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * Long clicks bottom and right corner of the UI element
4453d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
446e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @return true if operation was successful
447e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @throws UiObjectNotFoundException
448dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
449e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
450e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    public boolean longClickBottomRight() throws UiObjectNotFoundException  {
451f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine        Tracer.trace();
4520d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz        AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout());
453e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        if(node == null) {
454e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            throw new UiObjectNotFoundException(getSelector().toString());
455e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
456e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        Rect rect = getVisibleBounds(node);
4571dc7d12406947faaee8454c6efb2a0631f5da573Adam Momtaz        return getInteractionController().longTapNoSync(rect.right - 5, rect.bottom - 5);
458e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
459e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
460e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
4613d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * Clicks the bottom and right corner of the UI element
4623d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
463e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @return true on success
4641893caed0ad4e73b0676f206282d490c2d345316Thanh Le     * @throws UiObjectNotFoundException
465dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
466e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
467e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    public boolean clickBottomRight() throws UiObjectNotFoundException {
468f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine        Tracer.trace();
4690d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz        AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout());
470e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        if(node == null) {
471e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            throw new UiObjectNotFoundException(getSelector().toString());
472e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
473e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        Rect rect = getVisibleBounds(node);
4741dc7d12406947faaee8454c6efb2a0631f5da573Adam Momtaz        return getInteractionController().clickNoSync(rect.right - 5, rect.bottom - 5);
475e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
476e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
477e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
4783d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * Long clicks the center of the visible bounds of the UI element
4793d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
480e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @return true if operation was successful
481e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @throws UiObjectNotFoundException
482dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
483e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
484e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    public boolean longClick() throws UiObjectNotFoundException  {
485f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine        Tracer.trace();
4860d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz        AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout());
487e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        if(node == null) {
488e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            throw new UiObjectNotFoundException(getSelector().toString());
489e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
490e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        Rect rect = getVisibleBounds(node);
4911dc7d12406947faaee8454c6efb2a0631f5da573Adam Momtaz        return getInteractionController().longTapNoSync(rect.centerX(), rect.centerY());
492e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
493e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
494e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
4953d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * Long clicks on the top and left corner of the UI element
4963d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
497e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @return true if operation was successful
498e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @throws UiObjectNotFoundException
499dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
500e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
501e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    public boolean longClickTopLeft() throws UiObjectNotFoundException {
502f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine        Tracer.trace();
5030d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz        AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout());
504e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        if(node == null) {
505e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            throw new UiObjectNotFoundException(getSelector().toString());
506e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
507e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        Rect rect = getVisibleBounds(node);
5081dc7d12406947faaee8454c6efb2a0631f5da573Adam Momtaz        return getInteractionController().longTapNoSync(rect.left + 5, rect.top + 5);
509e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
510e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
511e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
5123d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * Reads the <code>text</code> property of the UI element
5133d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
514e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @return text value of the current node represented by this UiObject
515e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @throws UiObjectNotFoundException if no match could be found
516dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
517e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
518e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    public String getText() throws UiObjectNotFoundException {
519f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine        Tracer.trace();
5200d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz        AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout());
521e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        if(node == null) {
522e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            throw new UiObjectNotFoundException(getSelector().toString());
523e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
524e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        String retVal = safeStringReturn(node.getText());
525e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        Log.d(LOG_TAG, String.format("getText() = %s", retVal));
526e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        return retVal;
527e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
528e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
529e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
53097835f3a7c80b147136c44c175eb9e6a4261fd92Adam Momtaz     * Reads the <code>className</code> property of the UI element
53197835f3a7c80b147136c44c175eb9e6a4261fd92Adam Momtaz     *
53297835f3a7c80b147136c44c175eb9e6a4261fd92Adam Momtaz     * @return class name of the current node represented by this UiObject
53397835f3a7c80b147136c44c175eb9e6a4261fd92Adam Momtaz     * @throws UiObjectNotFoundException if no match could be found
53497835f3a7c80b147136c44c175eb9e6a4261fd92Adam Momtaz     * @since API Level 18
53597835f3a7c80b147136c44c175eb9e6a4261fd92Adam Momtaz     */
53697835f3a7c80b147136c44c175eb9e6a4261fd92Adam Momtaz    public String getClassName() throws UiObjectNotFoundException {
53797835f3a7c80b147136c44c175eb9e6a4261fd92Adam Momtaz        Tracer.trace();
5380d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz        AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout());
53997835f3a7c80b147136c44c175eb9e6a4261fd92Adam Momtaz        if(node == null) {
54097835f3a7c80b147136c44c175eb9e6a4261fd92Adam Momtaz            throw new UiObjectNotFoundException(getSelector().toString());
54197835f3a7c80b147136c44c175eb9e6a4261fd92Adam Momtaz        }
54297835f3a7c80b147136c44c175eb9e6a4261fd92Adam Momtaz        String retVal = safeStringReturn(node.getClassName());
54397835f3a7c80b147136c44c175eb9e6a4261fd92Adam Momtaz        Log.d(LOG_TAG, String.format("getClassName() = %s", retVal));
54497835f3a7c80b147136c44c175eb9e6a4261fd92Adam Momtaz        return retVal;
54597835f3a7c80b147136c44c175eb9e6a4261fd92Adam Momtaz    }
54697835f3a7c80b147136c44c175eb9e6a4261fd92Adam Momtaz
54797835f3a7c80b147136c44c175eb9e6a4261fd92Adam Momtaz    /**
5483d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * Reads the <code>content_desc</code> property of the UI element
5493d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
550e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @return value of node attribute "content_desc"
551e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @throws UiObjectNotFoundException
552dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
553e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
554e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    public String getContentDescription() throws UiObjectNotFoundException {
555f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine        Tracer.trace();
5560d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz        AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout());
557e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        if(node == null) {
558e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            throw new UiObjectNotFoundException(getSelector().toString());
559e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
560e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        return safeStringReturn(node.getContentDescription());
561e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
562e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
563e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
56446d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * Sets the text in an editable field, after clearing the field's content.
56546d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     *
56646d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * The {@link UiSelector} selector of this object must reference a UI element that is editable.
56746d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     *
56846d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * When you call this method, the method first simulates a {@link #click()} on
56946d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * editable field to set focus. The method then clears the field's contents
57046d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * and injects your specified text into the field.
5713d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
57246d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * If you want to capture the original contents of the field, call {@link #getText()} first.
57346d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * You can then modify the text and use this method to update the field.
57446d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     *
57546d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * @param text string to set
576e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @return true if operation is successful
577e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @throws UiObjectNotFoundException
578dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
579e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
580e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    public boolean setText(String text) throws UiObjectNotFoundException {
581f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine        Tracer.trace(text);
582e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        clearTextField();
583e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        return getInteractionController().sendText(text);
584e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
585e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
586e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
58746d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * Clears the existing text contents in an editable field.
58846d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     *
58946d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * The {@link UiSelector} of this object must reference a UI element that is editable.
59046d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     *
59146d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * When you call this method, the method first sets focus at the start edge of the field.
59246d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * The method then simulates a long-press to select the existing text, and deletes the
59346d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * selected text.
59446d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     *
59546d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * If a "Select-All" option is displayed, the method will automatically attempt to use it
59646d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * to ensure full text selection.
59746d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     *
59846d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * Note that it is possible that not all the text in the field is selected; for example,
59946d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * if the text contains separators such as spaces, slashes, at symbol etc.
60046d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * Also, not all editable fields support the long-press functionality.
60146d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     *
602e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @throws UiObjectNotFoundException
603dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
604e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
605e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    public void clearTextField() throws UiObjectNotFoundException {
606f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine        Tracer.trace();
607e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        // long click left + center
6080d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz        AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout());
609e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        if(node == null) {
610e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            throw new UiObjectNotFoundException(getSelector().toString());
611e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
612e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        Rect rect = getVisibleBounds(node);
6131dc7d12406947faaee8454c6efb2a0631f5da573Adam Momtaz        getInteractionController().longTapNoSync(rect.left + 20, rect.centerY());
614e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        // check if the edit menu is open
6154ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz        UiObject selectAll = new UiObject(new UiSelector().descriptionContains("Select all"));
616e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        if(selectAll.waitForExists(50))
617e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            selectAll.click();
618e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        // wait for the selection
619e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        SystemClock.sleep(250);
620e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        // delete it
621e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        getInteractionController().sendKey(KeyEvent.KEYCODE_DEL, 0);
622e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
623e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
624e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
6253d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * Check if the UI element's <code>checked</code> property is currently true
6263d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
627e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @return true if it is else false
628dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
629e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
630e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    public boolean isChecked() throws UiObjectNotFoundException {
631f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine        Tracer.trace();
6320d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz        AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout());
633e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        if(node == null) {
634e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            throw new UiObjectNotFoundException(getSelector().toString());
635e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
636e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        return node.isChecked();
637e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
638e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
639e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
6403d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * Check if the UI element's <code>selected</code> property is currently true
6413d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
642e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @return true if it is else false
643e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @throws UiObjectNotFoundException
644dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
645e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
646e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    public boolean isSelected() throws UiObjectNotFoundException {
647f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine        Tracer.trace();
6480d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz        AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout());
649e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        if(node == null) {
650e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            throw new UiObjectNotFoundException(getSelector().toString());
651e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
652e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        return node.isSelected();
653e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
654e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
655e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
6563d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * Check if the UI element's <code>checkable</code> property is currently true
6573d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
658e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @return true if it is else false
659e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @throws UiObjectNotFoundException
660dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
661e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
662e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    public boolean isCheckable() throws UiObjectNotFoundException {
663f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine        Tracer.trace();
6640d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz        AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout());
665e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        if(node == null) {
666e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            throw new UiObjectNotFoundException(getSelector().toString());
667e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
668e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        return node.isCheckable();
669e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
670e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
671e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
6723d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * Check if the UI element's <code>enabled</code> property is currently true
6733d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
674e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @return true if it is else false
675e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @throws UiObjectNotFoundException
676dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
677e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
678e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    public boolean isEnabled() throws UiObjectNotFoundException {
679f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine        Tracer.trace();
6800d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz        AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout());
681e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        if(node == null) {
682e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            throw new UiObjectNotFoundException(getSelector().toString());
683e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
684e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        return node.isEnabled();
685e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
686e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
687e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
6883d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * Check if the UI element's <code>clickable</code> property is currently true
6893d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
690e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @return true if it is else false
691e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @throws UiObjectNotFoundException
692dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
693e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
694e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    public boolean isClickable() throws UiObjectNotFoundException {
695f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine        Tracer.trace();
6960d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz        AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout());
697e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        if(node == null) {
698e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            throw new UiObjectNotFoundException(getSelector().toString());
699e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
700e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        return node.isClickable();
701e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
702e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
703e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
7043d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * Check if the UI element's <code>focused</code> property is currently true
7053d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
706e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @return true if it is else false
707e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @throws UiObjectNotFoundException
708dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
709e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
710e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    public boolean isFocused() throws UiObjectNotFoundException {
711f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine        Tracer.trace();
7120d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz        AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout());
713e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        if(node == null) {
714e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            throw new UiObjectNotFoundException(getSelector().toString());
715e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
716e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        return node.isFocused();
717e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
718e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
719e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
7203d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * Check if the UI element's <code>focusable</code> property is currently true
7213d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
722e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @return true if it is else false
723e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @throws UiObjectNotFoundException
724dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
725e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
726e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    public boolean isFocusable() throws UiObjectNotFoundException {
727f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine        Tracer.trace();
7280d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz        AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout());
729e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        if(node == null) {
730e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            throw new UiObjectNotFoundException(getSelector().toString());
731e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
732e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        return node.isFocusable();
733e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
734e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
735e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
7363d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * Check if the UI element's <code>scrollable</code> property is currently true
7373d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
738e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @return true if it is else false
739e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @throws UiObjectNotFoundException
740dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
741e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
742e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    public boolean isScrollable() throws UiObjectNotFoundException {
743f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine        Tracer.trace();
7440d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz        AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout());
745e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        if(node == null) {
746e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            throw new UiObjectNotFoundException(getSelector().toString());
747e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
748e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        return node.isScrollable();
749e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
750e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
751e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
7523d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * Check if the UI element's <code>long-clickable</code> property is currently true
7533d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
754e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @return true if it is else false
755e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @throws UiObjectNotFoundException
756dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
757e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
758e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    public boolean isLongClickable() throws UiObjectNotFoundException {
759f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine        Tracer.trace();
7600d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz        AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout());
761e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        if(node == null) {
762e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            throw new UiObjectNotFoundException(getSelector().toString());
763e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
764e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        return node.isLongClickable();
765e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
766e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
767e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
7683d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * Reads the UI element's <code>package</code> property
7693d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
7703d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * @return true if it is else false
771e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @throws UiObjectNotFoundException
772dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
773e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
774e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    public String getPackageName() throws UiObjectNotFoundException {
775f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine        Tracer.trace();
7760d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz        AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout());
777e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        if(node == null) {
778e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            throw new UiObjectNotFoundException(getSelector().toString());
779e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
780e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        return safeStringReturn(node.getPackageName());
781e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
782e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
783e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
78446d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * Returns the visible bounds of the UI element.
78546d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     *
78646d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * If a portion of the UI element is visible, only the bounds of the visible portion are
78746d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * reported.
7883d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
789e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @return Rect
790e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @throws UiObjectNotFoundException
7911893caed0ad4e73b0676f206282d490c2d345316Thanh Le     * @see {@link #getBounds()}
79279693ede92636fe6f3a6ec4dc049a438fd9504ffGuang Zhu     * @since API Level 17
793e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
7943d50587be8ff021369c90554d814839335b445b0Adam Momtaz    public Rect getVisibleBounds() throws UiObjectNotFoundException {
795f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine        Tracer.trace();
7960d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz        AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout());
797e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        if(node == null) {
798e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            throw new UiObjectNotFoundException(getSelector().toString());
799e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
800e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        return getVisibleBounds(node);
801e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
802e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
803e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
80446d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * Returns the UI element's <code>bounds</code> property. See {@link #getVisibleBounds()}
8053d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
8063d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * @return Rect
8073d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * @throws UiObjectNotFoundException
808dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
8093d50587be8ff021369c90554d814839335b445b0Adam Momtaz     */
8103d50587be8ff021369c90554d814839335b445b0Adam Momtaz    public Rect getBounds() throws UiObjectNotFoundException {
811f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine        Tracer.trace();
8120d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz        AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout());
8133d50587be8ff021369c90554d814839335b445b0Adam Momtaz        if(node == null) {
8143d50587be8ff021369c90554d814839335b445b0Adam Momtaz            throw new UiObjectNotFoundException(getSelector().toString());
8153d50587be8ff021369c90554d814839335b445b0Adam Momtaz        }
8163d50587be8ff021369c90554d814839335b445b0Adam Momtaz        Rect nodeRect = new Rect();
8173d50587be8ff021369c90554d814839335b445b0Adam Momtaz        node.getBoundsInScreen(nodeRect);
8183d50587be8ff021369c90554d814839335b445b0Adam Momtaz
8193d50587be8ff021369c90554d814839335b445b0Adam Momtaz        return nodeRect;
8203d50587be8ff021369c90554d814839335b445b0Adam Momtaz    }
8213d50587be8ff021369c90554d814839335b445b0Adam Momtaz
8223d50587be8ff021369c90554d814839335b445b0Adam Momtaz    /**
82346d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * Waits a specified length of time for a UI element to become visible.
82446d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     *
82546d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * This method waits until the UI element becomes visible on the display, or
82646d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * until the timeout has elapsed. You can use this method in situations where
82746d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * the content that you want to select is not immediately displayed.
8283d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
82946d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * @param timeout the amount of time to wait (in milliseconds)
83046d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * @return true if the UI element is displayed, else false if timeout elapsed while waiting
831dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
832e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
833e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    public boolean waitForExists(long timeout) {
834f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine        Tracer.trace(timeout);
835e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        if(findAccessibilityNodeInfo(timeout) != null) {
836e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            return true;
837e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
838e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        return false;
839e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
840e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
841e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
84246d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * Waits a specified length of time for a UI element to become undetectable.
8433d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
84446d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * This method waits until a UI element is no longer matchable, or until the
84546d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * timeout has elapsed.
84646d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     *
84746d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * A UI element becomes undetectable when the {@link UiSelector} of the object is
84846d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * unable to find a match because the element has either changed its state or is no
84946d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * longer displayed.
85046d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     *
85146d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * You can use this method when attempting to wait for some long operation
85246d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * to compete, such as downloading a large file or connecting to a remote server.
85346d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     *
85446d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * @param timeout time to wait (in milliseconds)
85546d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * @return true if the element is gone before timeout elapsed, else false if timeout elapsed
85646d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * but a matching element is still found.
857dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
858e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
859e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    public boolean waitUntilGone(long timeout) {
860f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine        Tracer.trace(timeout);
861e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        long startMills = SystemClock.uptimeMillis();
862e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        long currentMills = 0;
863e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        while (currentMills <= timeout) {
864e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            if(findAccessibilityNodeInfo(0) == null)
865e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                return true;
866e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            currentMills = SystemClock.uptimeMillis() - startMills;
867e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            if(timeout > 0)
868e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                SystemClock.sleep(WAIT_FOR_SELECTOR_POLL);
869e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
870e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        return false;
871e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
872e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
873e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
87446d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * Check if UI element exists.
87546d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     *
876e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * This methods performs a {@link #waitForExists(long)} with zero timeout. This
877e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * basically returns immediately whether the UI element represented by this UiObject
878e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * exists or not. If you need to wait longer for this UI element, then see
879e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * {@link #waitForExists(long)}.
8803d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
881e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @return true if the UI element represented by this UiObject does exist
882dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
883e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
884e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    public boolean exists() {
885f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine        Tracer.trace();
886e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        return waitForExists(0);
887e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
888e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
889e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    private String safeStringReturn(CharSequence cs) {
890e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        if(cs == null)
891e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            return "";
892e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        return cs.toString();
893e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
894c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz
895c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz    /**
896c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz     * PinchOut generates a 2 pointer gesture where each pointer is moving from the center out
897c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz     * away from each other diagonally towards the edges of the current UI element represented by
898c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz     * this UiObject.
899c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz     * @param percent of the object's diagonal length to use for the pinch
900c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz     * @param steps indicates the number of injected move steps into the system. Steps are
901c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz     * injected about 5ms apart. So a 100 steps may take about 1/2 second to complete.
9021078ab1070411af45d5e8ec3b56abec6789e7722Guang Zhu     * @return <code>true</code> if all touch events for this gesture are injected successfully,
9031078ab1070411af45d5e8ec3b56abec6789e7722Guang Zhu     *          <code>false</code> otherwise
904c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz     * @throws UiObjectNotFoundException
905c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz     * @since API Level 18
906c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz     */
9071078ab1070411af45d5e8ec3b56abec6789e7722Guang Zhu    public boolean pinchOut(int percent, int steps) throws UiObjectNotFoundException {
908c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        // make value between 1 and 100
909c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        percent = (percent < 0) ? 1 : (percent > 100) ? 100 : percent;
910c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        float percentage = percent / 100f;
911c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz
9120d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz        AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout());
913c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        if (node == null) {
914c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz            throw new UiObjectNotFoundException(getSelector().toString());
915c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        }
916c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz
917c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        Rect rect = getVisibleBounds(node);
918c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        if (rect.width() <= FINGER_TOUCH_HALF_WIDTH * 2)
919c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz            throw new IllegalStateException("Object width is too small for operation");
920c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz
921c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        // start from the same point at the center of the control
922c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        Point startPoint1 = new Point(rect.centerX() - FINGER_TOUCH_HALF_WIDTH, rect.centerY());
923c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        Point startPoint2 = new Point(rect.centerX() + FINGER_TOUCH_HALF_WIDTH, rect.centerY());
924c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz
925c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        // End at the top-left and bottom-right corners of the control
926c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        Point endPoint1 = new Point(rect.centerX() - (int)((rect.width()/2) * percentage),
927c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz                rect.centerY());
928c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        Point endPoint2 = new Point(rect.centerX() + (int)((rect.width()/2) * percentage),
929c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz                rect.centerY());
930c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz
9311078ab1070411af45d5e8ec3b56abec6789e7722Guang Zhu        return performTwoPointerGesture(startPoint1, startPoint2, endPoint1, endPoint2, steps);
932c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz    }
933c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz
934c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz    /**
935c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz     * PinchIn generates a 2 pointer gesture where each pointer is moving towards the other
936c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz     * diagonally from the edges of the current UI element represented by this UiObject, until the
937c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz     * center.
938c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz     * @param percent of the object's diagonal length to use for the pinch
939c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz     * @param steps indicates the number of injected move steps into the system. Steps are
940c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz     * injected about 5ms apart. So a 100 steps may take about 1/2 second to complete.
9411078ab1070411af45d5e8ec3b56abec6789e7722Guang Zhu     * @return <code>true</code> if all touch events for this gesture are injected successfully,
9421078ab1070411af45d5e8ec3b56abec6789e7722Guang Zhu     *          <code>false</code> otherwise
943c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz     * @throws UiObjectNotFoundException
944c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz     * @since API Level 18
945c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz     */
9461078ab1070411af45d5e8ec3b56abec6789e7722Guang Zhu    public boolean pinchIn(int percent, int steps) throws UiObjectNotFoundException {
947c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        // make value between 1 and 100
948c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        percent = (percent < 0) ? 0 : (percent > 100) ? 100 : percent;
949c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        float percentage = percent / 100f;
950c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz
9510d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz        AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout());
952c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        if (node == null) {
953c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz            throw new UiObjectNotFoundException(getSelector().toString());
954c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        }
955c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz
956c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        Rect rect = getVisibleBounds(node);
957c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        if (rect.width() <= FINGER_TOUCH_HALF_WIDTH * 2)
958c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz            throw new IllegalStateException("Object width is too small for operation");
959c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz
960c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        Point startPoint1 = new Point(rect.centerX() - (int)((rect.width()/2) * percentage),
961c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz                rect.centerY());
962c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        Point startPoint2 = new Point(rect.centerX() + (int)((rect.width()/2) * percentage),
963c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz                rect.centerY());
964c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz
965c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        Point endPoint1 = new Point(rect.centerX() - FINGER_TOUCH_HALF_WIDTH, rect.centerY());
966c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        Point endPoint2 = new Point(rect.centerX() + FINGER_TOUCH_HALF_WIDTH, rect.centerY());
967c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz
9681078ab1070411af45d5e8ec3b56abec6789e7722Guang Zhu        return performTwoPointerGesture(startPoint1, startPoint2, endPoint1, endPoint2, steps);
969c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz    }
970c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz
971c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz    /**
972c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz     * Generates a 2 pointer gesture from an arbitrary starting and ending points.
973c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz     *
974c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz     * @param startPoint1 start point of pointer 1
975c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz     * @param startPoint2 start point of pointer 2
976c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz     * @param endPoint1 end point of pointer 1
977c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz     * @param endPoint2 end point of pointer 2
978c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz     * @param steps indicates the number of injected move steps into the system. Steps are
979c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz     * injected about 5ms apart. So a 100 steps may take about 1/2 second to complete.
9801078ab1070411af45d5e8ec3b56abec6789e7722Guang Zhu     * @return <code>true</code> if all touch events for this gesture are injected successfully,
9811078ab1070411af45d5e8ec3b56abec6789e7722Guang Zhu     *          <code>false</code> otherwise
982c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz     * @since API Level 18
983c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz     */
9841078ab1070411af45d5e8ec3b56abec6789e7722Guang Zhu    public boolean performTwoPointerGesture(Point startPoint1, Point startPoint2, Point endPoint1,
985c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz            Point endPoint2, int steps) {
986c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz
987c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        // avoid a divide by zero
988c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        if(steps == 0)
989c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz            steps = 1;
990c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz
991c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        final float stepX1 = (endPoint1.x - startPoint1.x) / steps;
992c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        final float stepY1 = (endPoint1.y - startPoint1.y) / steps;
993c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        final float stepX2 = (endPoint2.x - startPoint2.x) / steps;
994c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        final float stepY2 = (endPoint2.y - startPoint2.y) / steps;
995c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz
996c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        int eventX1, eventY1, eventX2, eventY2;
997c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        eventX1 = startPoint1.x;
998c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        eventY1 = startPoint1.y;
999c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        eventX2 = startPoint2.x;
1000c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        eventY2 = startPoint2.y;
1001c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz
1002c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        // allocate for steps plus first down and last up
1003c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        PointerCoords[] points1 = new PointerCoords[steps + 2];
1004c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        PointerCoords[] points2 = new PointerCoords[steps + 2];
1005c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz
1006c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        // Include the first and last touch downs in the arrays of steps
1007c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        for (int i = 0; i < steps + 1; i++) {
1008c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz            PointerCoords p1 = new PointerCoords();
1009c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz            p1.x = eventX1;
1010c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz            p1.y = eventY1;
1011c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz            p1.pressure = 1;
1012c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz            p1.size = 1;
1013c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz            points1[i] = p1;
1014c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz
1015c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz            PointerCoords p2 = new PointerCoords();
1016c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz            p2.x = eventX2;
1017c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz            p2.y = eventY2;
1018c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz            p2.pressure = 1;
1019c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz            p2.size = 1;
1020c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz            points2[i] = p2;
1021c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz
1022c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz            eventX1 += stepX1;
1023c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz            eventY1 += stepY1;
1024c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz            eventX2 += stepX2;
1025c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz            eventY2 += stepY2;
1026c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        }
1027c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz
1028c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        // ending pointers coordinates
1029c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        PointerCoords p1 = new PointerCoords();
1030c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        p1.x = endPoint1.x;
1031c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        p1.y = endPoint1.y;
1032c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        p1.pressure = 1;
1033c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        p1.size = 1;
1034c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        points1[steps + 1] = p1;
1035c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz
1036c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        PointerCoords p2 = new PointerCoords();
1037c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        p2.x = endPoint2.x;
1038c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        p2.y = endPoint2.y;
1039c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        p2.pressure = 1;
1040c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        p2.size = 1;
1041c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        points2[steps + 1] = p2;
1042c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz
10431078ab1070411af45d5e8ec3b56abec6789e7722Guang Zhu        return performMultiPointerGesture(points1, points2);
1044c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz    }
1045c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz
1046c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz    /**
1047c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz     * Performs a multi-touch gesture
1048c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz     *
1049c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz     * Takes a series of touch coordinates for at least 2 pointers. Each pointer must have
1050c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz     * all of its touch steps defined in an array of {@link PointerCoords}. By having the ability
1051c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz     * to specify the touch points along the path of a pointer, the caller is able to specify
1052c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz     * complex gestures like circles, irregular shapes etc, where each pointer may take a
1053c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz     * different path.
1054c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz     *
1055c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz     * To create a single point on a pointer's touch path
1056c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz     * <code>
1057c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz     *       PointerCoords p = new PointerCoords();
1058c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz     *       p.x = stepX;
1059c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz     *       p.y = stepY;
1060c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz     *       p.pressure = 1;
1061c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz     *       p.size = 1;
1062c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz     * </code>
1063c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz     * @param touches each array of {@link PointerCoords} constitute a single pointer's touch path.
1064c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz     *        Multiple {@link PointerCoords} arrays constitute multiple pointers, each with its own
1065c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz     *        path. Each {@link PointerCoords} in an array constitute a point on a pointer's path.
10661078ab1070411af45d5e8ec3b56abec6789e7722Guang Zhu     * @return <code>true</code> if all touch events for this gesture are injected successfully,
10671078ab1070411af45d5e8ec3b56abec6789e7722Guang Zhu     *          <code>false</code> otherwise
1068c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz     * @since API Level 18
1069c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz     */
10701078ab1070411af45d5e8ec3b56abec6789e7722Guang Zhu    public boolean performMultiPointerGesture(PointerCoords[] ...touches) {
10711078ab1070411af45d5e8ec3b56abec6789e7722Guang Zhu        return getInteractionController().performMultiPointerGesture(touches);
1072c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz    }
1073b4671570eb1caa88c7b6042f81f1ca3a2cb6a916Guang Zhu}
1074