UiObject.java revision 46fcf070655a908e4ffaf93fe0d2b7be21bb004b
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;
68e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
690d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz    private final Configurator mConfig = Configurator.getInstance();
700d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz
71e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
723d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * Constructs a UiObject to represent a specific UI element matched by the specified
733d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * {@link UiSelector} selector properties.
74e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @param selector
75dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
76e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
774ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz    public UiObject(UiSelector selector) {
78e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        mSelector = selector;
79e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
80e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
81e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
823d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * Debugging helper. A test can dump the properties of a selector as a string
833d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * to its logs if needed. <code>getSelector().toString();</code>
843d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
854ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz     * @return {@link UiSelector}
86dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
87e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
884ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz    public final UiSelector getSelector() {
89f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine        Tracer.trace();
904ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz        return new UiSelector(mSelector);
91e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
92e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
93e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
943d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * Retrieves the {@link QueryController} to translate a {@link UiSelector} selector
953d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * into an {@link AccessibilityNodeInfo}.
963d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
97e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @return {@link QueryController}
98e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
99ddc1008f06fd2a875037026490ce1f848a442572Guang Zhu    QueryController getQueryController() {
10046fcf070655a908e4ffaf93fe0d2b7be21bb004bGuang Zhu        return UiDevice.getInstance().getAutomatorBridge().getQueryController();
101e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
102e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
103e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
1043d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * Retrieves the {@link InteractionController} to perform finger actions such as tapping,
1053d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * swiping or entering text.
1063d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
107e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @return {@link InteractionController}
108e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
109ddc1008f06fd2a875037026490ce1f848a442572Guang Zhu    InteractionController getInteractionController() {
11046fcf070655a908e4ffaf93fe0d2b7be21bb004bGuang Zhu        return UiDevice.getInstance().getAutomatorBridge().getInteractionController();
111e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
112e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
113e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
1143d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * Creates a new UiObject representing a child UI element of the element currently represented
1153d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * by this UiObject.
1163d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
1173d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * @param selector for UI element to match
1183d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * @return a new UiObject representing the matched UI element
119dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
120e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
1214ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz    public UiObject getChild(UiSelector selector) throws UiObjectNotFoundException {
122f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine        Tracer.trace(selector);
1234ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz        return new UiObject(getSelector().childSelector(selector));
124e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
125e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
126e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
1273d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * Creates a new UiObject representing a child UI element from the parent element currently
1283d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * represented by this object. Essentially this is starting the search from the parent
1293d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * element and can also be used to find sibling UI elements to the one currently represented
1303d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * by this UiObject.
1313d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
1323d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * @param selector for the UI element to match
1333d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * @return a new UiObject representing the matched UI element
134e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @throws UiObjectNotFoundException
135dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
136e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
1374ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz    public UiObject getFromParent(UiSelector selector) throws UiObjectNotFoundException {
138f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine        Tracer.trace(selector);
1394ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz        return new UiObject(getSelector().fromParent(selector));
140e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
141e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
142e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
1433d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * Counts the child UI elements immediately under the UI element currently represented by
144e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * this UiObject.
1453d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
146e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @return the count of child UI elements.
147e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @throws UiObjectNotFoundException
148dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
149e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
150e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    public int getChildCount() throws UiObjectNotFoundException {
151f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine        Tracer.trace();
1520d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz        AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout());
153e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        if(node == null) {
154e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            throw new UiObjectNotFoundException(getSelector().toString());
155e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
156e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        return node.getChildCount();
157e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
158e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
159e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
1603d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * Uses the member UiSelector properties to find a matching UI element reported in
1613d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * the accessibility hierarchy.
1623d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
163e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @param timeout in milliseconds
164e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @return AccessibilityNodeInfo if found else null
165dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
166e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
167e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    protected AccessibilityNodeInfo findAccessibilityNodeInfo(long timeout) {
168e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        AccessibilityNodeInfo node = null;
169bb36257f15f090966e2aeb9fd4f092e1a54722b1Adam Momtaz        long startMills = SystemClock.uptimeMillis();
170bb36257f15f090966e2aeb9fd4f092e1a54722b1Adam Momtaz        long currentMills = 0;
171bb36257f15f090966e2aeb9fd4f092e1a54722b1Adam Momtaz        while (currentMills <= timeout) {
172e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            node = getQueryController().findAccessibilityNodeInfo(getSelector());
173bb36257f15f090966e2aeb9fd4f092e1a54722b1Adam Momtaz            if (node != null) {
174bb36257f15f090966e2aeb9fd4f092e1a54722b1Adam Momtaz                break;
175bb36257f15f090966e2aeb9fd4f092e1a54722b1Adam Momtaz            } else {
176bb36257f15f090966e2aeb9fd4f092e1a54722b1Adam Momtaz                // does nothing if we're reentering another runWatchers()
177bb36257f15f090966e2aeb9fd4f092e1a54722b1Adam Momtaz                UiDevice.getInstance().runWatchers();
178bb36257f15f090966e2aeb9fd4f092e1a54722b1Adam Momtaz            }
179bb36257f15f090966e2aeb9fd4f092e1a54722b1Adam Momtaz            currentMills = SystemClock.uptimeMillis() - startMills;
180bb36257f15f090966e2aeb9fd4f092e1a54722b1Adam Momtaz            if(timeout > 0) {
181bb36257f15f090966e2aeb9fd4f092e1a54722b1Adam Momtaz                SystemClock.sleep(WAIT_FOR_SELECTOR_POLL);
182e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            }
183e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
184e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        return node;
185e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
186e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
187e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
1888d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz     * Performs a drag of this object to a destination UiObject. Note that the number of steps
1898d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz     * used can influence the drag speed and varying speeds may impact the results. Consider
1908d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz     * evaluating different speeds when testing this method.
1918d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz     *
1928d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz     * @param destObj
1938d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz     * @param steps usually 40 steps. More or less to change the speed.
1948d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz     * @return true of successful
1958d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz     * @throws UiObjectNotFoundException
1968d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz     * @since API Level 18
1978d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz     */
1988d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz    public boolean dragTo(UiObject destObj, int steps) throws UiObjectNotFoundException {
1998d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz        Rect srcRect = getVisibleBounds();
2008d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz        Rect dstRect = destObj.getVisibleBounds();
2018d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz        return getInteractionController().swipe(srcRect.centerX(), srcRect.centerY(),
2028d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz                dstRect.centerX(), dstRect.centerY(), steps, true);
2038d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz    }
2048d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz
2058d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz    /**
2068d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz     * Performs a drag of this object to arbitrary coordinates. Note that the number of steps
2078d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz     * used will influence the drag speed and varying speeds may impact the results. Consider
2088d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz     * evaluating different speeds when testing this method.
2098d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz     *
2108d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz     * @param destX
2118d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz     * @param destY
2128d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz     * @param steps
2138d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz     * @return true of successful
2148d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz     * @throws UiObjectNotFoundException
2158d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz     * @since API Level 18
2168d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz     */
2178d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz    public boolean dragTo(int destX, int destY, int steps) throws UiObjectNotFoundException {
2188d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz        Rect srcRect = getVisibleBounds();
2198d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz        return getInteractionController().swipe(srcRect.centerX(), srcRect.centerY(), destX, destY,
2208d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz                steps, true);
2218d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz    }
2228d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz
2238d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz    /**
2243d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * Perform the action on the UI element that is represented by this UiObject. Also see
2251893caed0ad4e73b0676f206282d490c2d345316Thanh Le     * {@link UiScrollable#scrollToBeginning(int)}, {@link UiScrollable#scrollToEnd(int)},
2261893caed0ad4e73b0676f206282d490c2d345316Thanh Le     * {@link UiScrollable#scrollBackward()}, {@link UiScrollable#scrollForward()}.
2273d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
228467cca7d25dbbf13c14cfd8c2ad38ab8eaf56bdaAdam Momtaz     * @param steps indicates the number of injected move steps into the system. Steps are
229467cca7d25dbbf13c14cfd8c2ad38ab8eaf56bdaAdam Momtaz     * injected about 5ms apart. So a 100 steps may take about 1/2 second to complete.
2303d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * @return true of successful
231e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @throws UiObjectNotFoundException
232dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
233e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
234e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    public boolean swipeUp(int steps) throws UiObjectNotFoundException {
235f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine        Tracer.trace(steps);
2363d50587be8ff021369c90554d814839335b445b0Adam Momtaz        Rect rect = getVisibleBounds();
237e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        if(rect.height() <= SWIPE_MARGIN_LIMIT * 2)
238e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            return false; // too small to swipe
239e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        return getInteractionController().swipe(rect.centerX(),
240e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                rect.bottom - SWIPE_MARGIN_LIMIT, rect.centerX(), rect.top + SWIPE_MARGIN_LIMIT,
241e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                steps);
242e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
243e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
244e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
245e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * Perform the action on the UI element that is represented by this object, Also see
2461893caed0ad4e73b0676f206282d490c2d345316Thanh Le     * {@link UiScrollable#scrollToBeginning(int)}, {@link UiScrollable#scrollToEnd(int)},
2471893caed0ad4e73b0676f206282d490c2d345316Thanh Le     * {@link UiScrollable#scrollBackward()}, {@link UiScrollable#scrollForward()}. This method will
2481893caed0ad4e73b0676f206282d490c2d345316Thanh Le     * perform the swipe gesture over any surface.  The targeted UI element does not need to have
2491893caed0ad4e73b0676f206282d490c2d345316Thanh Le     * the attribute <code>scrollable</code> set to <code>true</code> for this operation to be
2501893caed0ad4e73b0676f206282d490c2d345316Thanh Le     * performed.
2513d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
2523d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * @param steps indicates the number of injected move steps into the system. Steps are
253467cca7d25dbbf13c14cfd8c2ad38ab8eaf56bdaAdam Momtaz     * injected about 5ms apart. So a 100 steps may take about 1/2 second to complete.
2543d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * @return true if successful
255e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @throws UiObjectNotFoundException
256dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
257e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
258e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    public boolean swipeDown(int steps) throws UiObjectNotFoundException {
259f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine        Tracer.trace(steps);
2603d50587be8ff021369c90554d814839335b445b0Adam Momtaz        Rect rect = getVisibleBounds();
261e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        if(rect.height() <= SWIPE_MARGIN_LIMIT * 2)
262e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            return false; // too small to swipe
263e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        return getInteractionController().swipe(rect.centerX(),
264e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                rect.top + SWIPE_MARGIN_LIMIT, rect.centerX(),
265e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                rect.bottom - SWIPE_MARGIN_LIMIT, steps);
266e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
267e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
268e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
269e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * Perform the action on the UI element that is represented by this object. Also see
2701893caed0ad4e73b0676f206282d490c2d345316Thanh Le     * {@link UiScrollable#scrollToBeginning(int)}, {@link UiScrollable#scrollToEnd(int)},
2711893caed0ad4e73b0676f206282d490c2d345316Thanh Le     * {@link UiScrollable#scrollBackward()}, {@link UiScrollable#scrollForward()}. This method will
2721893caed0ad4e73b0676f206282d490c2d345316Thanh Le     * perform the swipe gesture over any surface. The targeted UI element does not need to have the
2731893caed0ad4e73b0676f206282d490c2d345316Thanh Le     * attribute <code>scrollable</code> set to <code>true</code> for this operation to be
2741893caed0ad4e73b0676f206282d490c2d345316Thanh Le     * performed.
2753d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
2763d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * @param steps indicates the number of injected move steps into the system. Steps are
277467cca7d25dbbf13c14cfd8c2ad38ab8eaf56bdaAdam Momtaz     * injected about 5ms apart. So a 100 steps may take about 1/2 second to complete.
2783d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * @return true if successful
279e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @throws UiObjectNotFoundException
280dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
281e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
282e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    public boolean swipeLeft(int steps) throws UiObjectNotFoundException {
283f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine        Tracer.trace(steps);
2843d50587be8ff021369c90554d814839335b445b0Adam Momtaz        Rect rect = getVisibleBounds();
285e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        if(rect.width() <= SWIPE_MARGIN_LIMIT * 2)
286e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            return false; // too small to swipe
287e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        return getInteractionController().swipe(rect.right - SWIPE_MARGIN_LIMIT,
288e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                rect.centerY(), rect.left + SWIPE_MARGIN_LIMIT, rect.centerY(), steps);
289e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
290e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
291e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
292e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * Perform the action on the UI element that is represented by this object. Also see
2931893caed0ad4e73b0676f206282d490c2d345316Thanh Le     * {@link UiScrollable#scrollToBeginning(int)}, {@link UiScrollable#scrollToEnd(int)},
2941893caed0ad4e73b0676f206282d490c2d345316Thanh Le     * {@link UiScrollable#scrollBackward()}, {@link UiScrollable#scrollForward()}. This method will
2951893caed0ad4e73b0676f206282d490c2d345316Thanh Le     * perform the swipe gesture over any surface. The targeted UI element does not need to have the
2961893caed0ad4e73b0676f206282d490c2d345316Thanh Le     * attribute <code>scrollable</code> set to <code>true</code> for this operation to be
2971893caed0ad4e73b0676f206282d490c2d345316Thanh Le     * performed.
2983d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
2993d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * @param steps indicates the number of injected move steps into the system. Steps are
300467cca7d25dbbf13c14cfd8c2ad38ab8eaf56bdaAdam Momtaz     * injected about 5ms apart. So a 100 steps may take about 1/2 second to complete.
3013d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * @return true if successful
302e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @throws UiObjectNotFoundException
303dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
304e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
305e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    public boolean swipeRight(int steps) throws UiObjectNotFoundException {
306f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine        Tracer.trace(steps);
3073d50587be8ff021369c90554d814839335b445b0Adam Momtaz        Rect rect = getVisibleBounds();
308e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        if(rect.width() <= SWIPE_MARGIN_LIMIT * 2)
309e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            return false; // too small to swipe
310e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        return getInteractionController().swipe(rect.left + SWIPE_MARGIN_LIMIT,
311e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                rect.centerY(), rect.right - SWIPE_MARGIN_LIMIT, rect.centerY(), steps);
312e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
313e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
314e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
3153d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * Finds the visible bounds of a partially visible UI element
3163d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
317e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @param node
3187f38ef08d07295967b905a61b2356ff6cdf31159Adam Momtaz     * @return null if node is null, else a Rect containing visible bounds
319e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
320e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    private Rect getVisibleBounds(AccessibilityNodeInfo node) {
321e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        if (node == null) {
322e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            return null;
323e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
324e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
325e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        // targeted node's bounds
32623296fc6448cd265fbb45c1fd9041976ae0da274Guang Zhu        int w = UiDevice.getInstance().getDisplayWidth();
32723296fc6448cd265fbb45c1fd9041976ae0da274Guang Zhu        int h = UiDevice.getInstance().getDisplayHeight();
32823296fc6448cd265fbb45c1fd9041976ae0da274Guang Zhu        Rect nodeRect = AccessibilityNodeInfoHelper.getVisibleBoundsInScreen(node, w, h);
329e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
330e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        // is the targeted node within a scrollable container?
331e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        AccessibilityNodeInfo scrollableParentNode = getScrollableParent(node);
332e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        if(scrollableParentNode == null) {
333e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            // nothing to adjust for so return the node's Rect as is
334e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            return nodeRect;
335e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
336e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
337e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        // Scrollable parent's visible bounds
3387f38ef08d07295967b905a61b2356ff6cdf31159Adam Momtaz        Rect parentRect = AccessibilityNodeInfoHelper
33923296fc6448cd265fbb45c1fd9041976ae0da274Guang Zhu                .getVisibleBoundsInScreen(scrollableParentNode, w, h);
340e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        // adjust for partial clipping of targeted by parent node if required
341e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        nodeRect.intersect(parentRect);
342e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        return nodeRect;
343e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
344e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
345e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
3467f38ef08d07295967b905a61b2356ff6cdf31159Adam Momtaz     * Walk the hierarchy up to find a scrollable parent. A scrollable parent
3477f38ef08d07295967b905a61b2356ff6cdf31159Adam Momtaz     * indicates that this node may be in a content where it is partially
3487f38ef08d07295967b905a61b2356ff6cdf31159Adam Momtaz     * visible due to scrolling. its clickable center maybe invisible and
3497f38ef08d07295967b905a61b2356ff6cdf31159Adam Momtaz     * adjustments should be made to the click coordinates.
3503d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
351e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @param node
3521893caed0ad4e73b0676f206282d490c2d345316Thanh Le     * @return The accessibility node info.
353e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
354e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    private AccessibilityNodeInfo getScrollableParent(AccessibilityNodeInfo node) {
355e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        AccessibilityNodeInfo parent = node;
356e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        while(parent != null) {
357e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            parent = parent.getParent();
358e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            if (parent != null && parent.isScrollable()) {
359e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                return parent;
360e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            }
361e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
362e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        return null;
363e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
364e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
365e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
3663d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * Performs a click at the center of the visible bounds of the UI element represented
36746d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * by this UiObject.
3683d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
369e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @return true id successful else false
370e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @throws UiObjectNotFoundException
371dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
372e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
373e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    public boolean click() throws UiObjectNotFoundException {
374f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine        Tracer.trace();
3750d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz        AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout());
376e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        if(node == null) {
377e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            throw new UiObjectNotFoundException(getSelector().toString());
378e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
379e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        Rect rect = getVisibleBounds(node);
3800d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz        return getInteractionController().clickAndSync(rect.centerX(), rect.centerY(),
3810d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz                mConfig.getActionAcknowledgmentTimeout());
382e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
383e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
384e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
3853d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * See {@link #clickAndWaitForNewWindow(long)}
386a46ac3504426564954292b13380120e8cc6b1527Adam Momtaz     * This method is intended to reliably wait for window transitions that would typically take
387a46ac3504426564954292b13380120e8cc6b1527Adam Momtaz     * longer than the usual default timeouts.
3883d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
3893d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * @return true if the event was triggered, else false
3903d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * @throws UiObjectNotFoundException
391dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
3923d50587be8ff021369c90554d814839335b445b0Adam Momtaz     */
393e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    public boolean clickAndWaitForNewWindow() throws UiObjectNotFoundException {
394f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine        Tracer.trace();
395e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        return clickAndWaitForNewWindow(WAIT_FOR_WINDOW_TMEOUT);
396e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
397e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
398e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
39946d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * Performs a click at the center of the visible bounds of the UI element represented
40046d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * by this UiObject and waits for window transitions.
40146d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     *
4023d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * This method differ from {@link UiObject#click()} only in that this method waits for a
40346d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * a new window transition as a result of the click. Some examples of a window transition:
404e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * <li>launching a new activity</li>
405e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * <li>bringing up a pop-up menu</li>
406e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * <li>bringing up a dialog</li>
407e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     *
4083d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * @param timeout timeout before giving up on waiting for a new window
409e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @return true if the event was triggered, else false
410e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @throws UiObjectNotFoundException
411dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
412e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
413e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    public boolean clickAndWaitForNewWindow(long timeout) throws UiObjectNotFoundException {
414f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine        Tracer.trace(timeout);
4150d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz        AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout());
416e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        if(node == null) {
417e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            throw new UiObjectNotFoundException(getSelector().toString());
418e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
419e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        Rect rect = getVisibleBounds(node);
4200d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz        return getInteractionController().clickAndWaitForNewWindow(rect.centerX(), rect.centerY(),
4210d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz                mConfig.getActionAcknowledgmentTimeout());
422e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
423e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
424e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
4253d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * Clicks the top and left corner of the UI element
4263d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
427e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @return true on success
4281893caed0ad4e73b0676f206282d490c2d345316Thanh Le     * @throws UiObjectNotFoundException
429dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
430e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
431e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    public boolean clickTopLeft() throws UiObjectNotFoundException {
432f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine        Tracer.trace();
4330d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz        AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout());
434e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        if(node == null) {
435e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            throw new UiObjectNotFoundException(getSelector().toString());
436e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
437e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        Rect rect = getVisibleBounds(node);
4381dc7d12406947faaee8454c6efb2a0631f5da573Adam Momtaz        return getInteractionController().clickNoSync(rect.left + 5, rect.top + 5);
439e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
440e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
441e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
4423d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * Long clicks bottom and right corner of the UI element
4433d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
444e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @return true if operation was successful
445e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @throws UiObjectNotFoundException
446dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
447e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
448e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    public boolean longClickBottomRight() throws UiObjectNotFoundException  {
449f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine        Tracer.trace();
4500d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz        AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout());
451e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        if(node == null) {
452e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            throw new UiObjectNotFoundException(getSelector().toString());
453e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
454e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        Rect rect = getVisibleBounds(node);
4551dc7d12406947faaee8454c6efb2a0631f5da573Adam Momtaz        return getInteractionController().longTapNoSync(rect.right - 5, rect.bottom - 5);
456e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
457e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
458e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
4593d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * Clicks the bottom and right corner of the UI element
4603d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
461e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @return true on success
4621893caed0ad4e73b0676f206282d490c2d345316Thanh Le     * @throws UiObjectNotFoundException
463dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
464e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
465e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    public boolean clickBottomRight() throws UiObjectNotFoundException {
466f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine        Tracer.trace();
4670d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz        AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout());
468e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        if(node == null) {
469e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            throw new UiObjectNotFoundException(getSelector().toString());
470e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
471e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        Rect rect = getVisibleBounds(node);
4721dc7d12406947faaee8454c6efb2a0631f5da573Adam Momtaz        return getInteractionController().clickNoSync(rect.right - 5, rect.bottom - 5);
473e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
474e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
475e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
4763d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * Long clicks the center of the visible bounds of the UI element
4773d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
478e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @return true if operation was successful
479e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @throws UiObjectNotFoundException
480dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
481e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
482e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    public boolean longClick() throws UiObjectNotFoundException  {
483f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine        Tracer.trace();
4840d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz        AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout());
485e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        if(node == null) {
486e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            throw new UiObjectNotFoundException(getSelector().toString());
487e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
488e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        Rect rect = getVisibleBounds(node);
4891dc7d12406947faaee8454c6efb2a0631f5da573Adam Momtaz        return getInteractionController().longTapNoSync(rect.centerX(), rect.centerY());
490e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
491e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
492e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
4933d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * Long clicks on the top and left corner of the UI element
4943d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
495e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @return true if operation was successful
496e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @throws UiObjectNotFoundException
497dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
498e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
499e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    public boolean longClickTopLeft() throws UiObjectNotFoundException {
500f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine        Tracer.trace();
5010d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz        AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout());
502e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        if(node == null) {
503e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            throw new UiObjectNotFoundException(getSelector().toString());
504e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
505e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        Rect rect = getVisibleBounds(node);
5061dc7d12406947faaee8454c6efb2a0631f5da573Adam Momtaz        return getInteractionController().longTapNoSync(rect.left + 5, rect.top + 5);
507e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
508e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
509e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
5103d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * Reads the <code>text</code> property of the UI element
5113d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
512e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @return text value of the current node represented by this UiObject
513e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @throws UiObjectNotFoundException if no match could be found
514dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
515e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
516e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    public String getText() throws UiObjectNotFoundException {
517f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine        Tracer.trace();
5180d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz        AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout());
519e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        if(node == null) {
520e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            throw new UiObjectNotFoundException(getSelector().toString());
521e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
522e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        String retVal = safeStringReturn(node.getText());
523e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        Log.d(LOG_TAG, String.format("getText() = %s", retVal));
524e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        return retVal;
525e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
526e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
527e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
52897835f3a7c80b147136c44c175eb9e6a4261fd92Adam Momtaz     * Reads the <code>className</code> property of the UI element
52997835f3a7c80b147136c44c175eb9e6a4261fd92Adam Momtaz     *
53097835f3a7c80b147136c44c175eb9e6a4261fd92Adam Momtaz     * @return class name of the current node represented by this UiObject
53197835f3a7c80b147136c44c175eb9e6a4261fd92Adam Momtaz     * @throws UiObjectNotFoundException if no match could be found
53297835f3a7c80b147136c44c175eb9e6a4261fd92Adam Momtaz     * @since API Level 18
53397835f3a7c80b147136c44c175eb9e6a4261fd92Adam Momtaz     */
53497835f3a7c80b147136c44c175eb9e6a4261fd92Adam Momtaz    public String getClassName() throws UiObjectNotFoundException {
53597835f3a7c80b147136c44c175eb9e6a4261fd92Adam Momtaz        Tracer.trace();
5360d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz        AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout());
53797835f3a7c80b147136c44c175eb9e6a4261fd92Adam Momtaz        if(node == null) {
53897835f3a7c80b147136c44c175eb9e6a4261fd92Adam Momtaz            throw new UiObjectNotFoundException(getSelector().toString());
53997835f3a7c80b147136c44c175eb9e6a4261fd92Adam Momtaz        }
54097835f3a7c80b147136c44c175eb9e6a4261fd92Adam Momtaz        String retVal = safeStringReturn(node.getClassName());
54197835f3a7c80b147136c44c175eb9e6a4261fd92Adam Momtaz        Log.d(LOG_TAG, String.format("getClassName() = %s", retVal));
54297835f3a7c80b147136c44c175eb9e6a4261fd92Adam Momtaz        return retVal;
54397835f3a7c80b147136c44c175eb9e6a4261fd92Adam Momtaz    }
54497835f3a7c80b147136c44c175eb9e6a4261fd92Adam Momtaz
54597835f3a7c80b147136c44c175eb9e6a4261fd92Adam Momtaz    /**
5463d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * Reads the <code>content_desc</code> property of the UI element
5473d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
548e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @return value of node attribute "content_desc"
549e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @throws UiObjectNotFoundException
550dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
551e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
552e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    public String getContentDescription() throws UiObjectNotFoundException {
553f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine        Tracer.trace();
5540d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz        AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout());
555e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        if(node == null) {
556e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            throw new UiObjectNotFoundException(getSelector().toString());
557e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
558e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        return safeStringReturn(node.getContentDescription());
559e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
560e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
561e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
56246d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * Sets the text in an editable field, after clearing the field's content.
56346d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     *
56446d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * The {@link UiSelector} selector of this object must reference a UI element that is editable.
56546d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     *
56646d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * When you call this method, the method first simulates a {@link #click()} on
56746d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * editable field to set focus. The method then clears the field's contents
56846d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * and injects your specified text into the field.
5693d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
57046d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * If you want to capture the original contents of the field, call {@link #getText()} first.
57146d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * You can then modify the text and use this method to update the field.
57246d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     *
57346d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * @param text string to set
574e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @return true if operation is successful
575e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @throws UiObjectNotFoundException
576dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
577e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
578e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    public boolean setText(String text) throws UiObjectNotFoundException {
579f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine        Tracer.trace(text);
580e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        clearTextField();
581e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        return getInteractionController().sendText(text);
582e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
583e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
584e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
58546d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * Clears the existing text contents in an editable field.
58646d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     *
58746d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * The {@link UiSelector} of this object must reference a UI element that is editable.
58846d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     *
58946d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * When you call this method, the method first sets focus at the start edge of the field.
59046d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * The method then simulates a long-press to select the existing text, and deletes the
59146d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * selected text.
59246d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     *
59346d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * If a "Select-All" option is displayed, the method will automatically attempt to use it
59446d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * to ensure full text selection.
59546d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     *
59646d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * Note that it is possible that not all the text in the field is selected; for example,
59746d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * if the text contains separators such as spaces, slashes, at symbol etc.
59846d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * Also, not all editable fields support the long-press functionality.
59946d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     *
600e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @throws UiObjectNotFoundException
601dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
602e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
603e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    public void clearTextField() throws UiObjectNotFoundException {
604f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine        Tracer.trace();
605e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        // long click left + center
6060d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz        AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout());
607e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        if(node == null) {
608e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            throw new UiObjectNotFoundException(getSelector().toString());
609e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
610e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        Rect rect = getVisibleBounds(node);
6111dc7d12406947faaee8454c6efb2a0631f5da573Adam Momtaz        getInteractionController().longTapNoSync(rect.left + 20, rect.centerY());
612e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        // check if the edit menu is open
6134ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz        UiObject selectAll = new UiObject(new UiSelector().descriptionContains("Select all"));
614e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        if(selectAll.waitForExists(50))
615e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            selectAll.click();
616e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        // wait for the selection
617e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        SystemClock.sleep(250);
618e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        // delete it
619e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        getInteractionController().sendKey(KeyEvent.KEYCODE_DEL, 0);
620e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
621e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
622e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
6233d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * Check if the UI element's <code>checked</code> property is currently true
6243d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
625e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @return true if it is else false
626dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
627e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
628e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    public boolean isChecked() throws UiObjectNotFoundException {
629f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine        Tracer.trace();
6300d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz        AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout());
631e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        if(node == null) {
632e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            throw new UiObjectNotFoundException(getSelector().toString());
633e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
634e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        return node.isChecked();
635e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
636e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
637e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
6383d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * Check if the UI element's <code>selected</code> property is currently true
6393d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
640e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @return true if it is else false
641e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @throws UiObjectNotFoundException
642dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
643e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
644e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    public boolean isSelected() throws UiObjectNotFoundException {
645f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine        Tracer.trace();
6460d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz        AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout());
647e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        if(node == null) {
648e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            throw new UiObjectNotFoundException(getSelector().toString());
649e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
650e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        return node.isSelected();
651e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
652e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
653e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
6543d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * Check if the UI element's <code>checkable</code> property is currently true
6553d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
656e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @return true if it is else false
657e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @throws UiObjectNotFoundException
658dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
659e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
660e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    public boolean isCheckable() throws UiObjectNotFoundException {
661f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine        Tracer.trace();
6620d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz        AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout());
663e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        if(node == null) {
664e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            throw new UiObjectNotFoundException(getSelector().toString());
665e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
666e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        return node.isCheckable();
667e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
668e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
669e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
6703d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * Check if the UI element's <code>enabled</code> property is currently true
6713d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
672e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @return true if it is else false
673e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @throws UiObjectNotFoundException
674dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
675e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
676e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    public boolean isEnabled() throws UiObjectNotFoundException {
677f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine        Tracer.trace();
6780d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz        AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout());
679e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        if(node == null) {
680e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            throw new UiObjectNotFoundException(getSelector().toString());
681e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
682e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        return node.isEnabled();
683e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
684e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
685e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
6863d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * Check if the UI element's <code>clickable</code> property is currently true
6873d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
688e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @return true if it is else false
689e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @throws UiObjectNotFoundException
690dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
691e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
692e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    public boolean isClickable() throws UiObjectNotFoundException {
693f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine        Tracer.trace();
6940d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz        AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout());
695e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        if(node == null) {
696e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            throw new UiObjectNotFoundException(getSelector().toString());
697e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
698e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        return node.isClickable();
699e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
700e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
701e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
7023d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * Check if the UI element's <code>focused</code> property is currently true
7033d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
704e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @return true if it is else false
705e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @throws UiObjectNotFoundException
706dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
707e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
708e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    public boolean isFocused() throws UiObjectNotFoundException {
709f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine        Tracer.trace();
7100d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz        AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout());
711e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        if(node == null) {
712e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            throw new UiObjectNotFoundException(getSelector().toString());
713e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
714e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        return node.isFocused();
715e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
716e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
717e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
7183d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * Check if the UI element's <code>focusable</code> property is currently true
7193d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
720e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @return true if it is else false
721e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @throws UiObjectNotFoundException
722dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
723e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
724e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    public boolean isFocusable() throws UiObjectNotFoundException {
725f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine        Tracer.trace();
7260d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz        AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout());
727e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        if(node == null) {
728e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            throw new UiObjectNotFoundException(getSelector().toString());
729e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
730e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        return node.isFocusable();
731e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
732e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
733e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
7343d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * Check if the UI element's <code>scrollable</code> property is currently true
7353d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
736e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @return true if it is else false
737e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @throws UiObjectNotFoundException
738dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
739e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
740e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    public boolean isScrollable() throws UiObjectNotFoundException {
741f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine        Tracer.trace();
7420d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz        AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout());
743e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        if(node == null) {
744e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            throw new UiObjectNotFoundException(getSelector().toString());
745e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
746e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        return node.isScrollable();
747e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
748e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
749e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
7503d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * Check if the UI element's <code>long-clickable</code> property is currently true
7513d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
752e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @return true if it is else false
753e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @throws UiObjectNotFoundException
754dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
755e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
756e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    public boolean isLongClickable() throws UiObjectNotFoundException {
757f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine        Tracer.trace();
7580d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz        AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout());
759e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        if(node == null) {
760e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            throw new UiObjectNotFoundException(getSelector().toString());
761e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
762e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        return node.isLongClickable();
763e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
764e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
765e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
7663d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * Reads the UI element's <code>package</code> property
7673d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
7683d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * @return true if it is else false
769e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @throws UiObjectNotFoundException
770dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
771e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
772e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    public String getPackageName() throws UiObjectNotFoundException {
773f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine        Tracer.trace();
7740d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz        AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout());
775e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        if(node == null) {
776e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            throw new UiObjectNotFoundException(getSelector().toString());
777e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
778e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        return safeStringReturn(node.getPackageName());
779e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
780e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
781e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
78246d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * Returns the visible bounds of the UI element.
78346d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     *
78446d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * If a portion of the UI element is visible, only the bounds of the visible portion are
78546d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * reported.
7863d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
787e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @return Rect
788e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @throws UiObjectNotFoundException
7891893caed0ad4e73b0676f206282d490c2d345316Thanh Le     * @see {@link #getBounds()}
79079693ede92636fe6f3a6ec4dc049a438fd9504ffGuang Zhu     * @since API Level 17
791e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
7923d50587be8ff021369c90554d814839335b445b0Adam Momtaz    public Rect getVisibleBounds() throws UiObjectNotFoundException {
793f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine        Tracer.trace();
7940d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz        AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout());
795e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        if(node == null) {
796e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            throw new UiObjectNotFoundException(getSelector().toString());
797e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
798e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        return getVisibleBounds(node);
799e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
800e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
801e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
80246d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * Returns the UI element's <code>bounds</code> property. See {@link #getVisibleBounds()}
8033d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
8043d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * @return Rect
8053d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * @throws UiObjectNotFoundException
806dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
8073d50587be8ff021369c90554d814839335b445b0Adam Momtaz     */
8083d50587be8ff021369c90554d814839335b445b0Adam Momtaz    public Rect getBounds() throws UiObjectNotFoundException {
809f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine        Tracer.trace();
8100d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz        AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout());
8113d50587be8ff021369c90554d814839335b445b0Adam Momtaz        if(node == null) {
8123d50587be8ff021369c90554d814839335b445b0Adam Momtaz            throw new UiObjectNotFoundException(getSelector().toString());
8133d50587be8ff021369c90554d814839335b445b0Adam Momtaz        }
8143d50587be8ff021369c90554d814839335b445b0Adam Momtaz        Rect nodeRect = new Rect();
8153d50587be8ff021369c90554d814839335b445b0Adam Momtaz        node.getBoundsInScreen(nodeRect);
8163d50587be8ff021369c90554d814839335b445b0Adam Momtaz
8173d50587be8ff021369c90554d814839335b445b0Adam Momtaz        return nodeRect;
8183d50587be8ff021369c90554d814839335b445b0Adam Momtaz    }
8193d50587be8ff021369c90554d814839335b445b0Adam Momtaz
8203d50587be8ff021369c90554d814839335b445b0Adam Momtaz    /**
82146d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * Waits a specified length of time for a UI element to become visible.
82246d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     *
82346d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * This method waits until the UI element becomes visible on the display, or
82446d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * until the timeout has elapsed. You can use this method in situations where
82546d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * the content that you want to select is not immediately displayed.
8263d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
82746d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * @param timeout the amount of time to wait (in milliseconds)
82846d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * @return true if the UI element is displayed, else false if timeout elapsed while waiting
829dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
830e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
831e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    public boolean waitForExists(long timeout) {
832f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine        Tracer.trace(timeout);
833e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        if(findAccessibilityNodeInfo(timeout) != null) {
834e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            return true;
835e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
836e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        return false;
837e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
838e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
839e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
84046d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * Waits a specified length of time for a UI element to become undetectable.
8413d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
84246d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * This method waits until a UI element is no longer matchable, or until the
84346d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * timeout has elapsed.
84446d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     *
84546d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * A UI element becomes undetectable when the {@link UiSelector} of the object is
84646d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * unable to find a match because the element has either changed its state or is no
84746d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * longer displayed.
84846d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     *
84946d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * You can use this method when attempting to wait for some long operation
85046d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * to compete, such as downloading a large file or connecting to a remote server.
85146d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     *
85246d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * @param timeout time to wait (in milliseconds)
85346d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * @return true if the element is gone before timeout elapsed, else false if timeout elapsed
85446d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * but a matching element is still found.
855dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
856e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
857e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    public boolean waitUntilGone(long timeout) {
858f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine        Tracer.trace(timeout);
859e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        long startMills = SystemClock.uptimeMillis();
860e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        long currentMills = 0;
861e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        while (currentMills <= timeout) {
862e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            if(findAccessibilityNodeInfo(0) == null)
863e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                return true;
864e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            currentMills = SystemClock.uptimeMillis() - startMills;
865e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            if(timeout > 0)
866e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                SystemClock.sleep(WAIT_FOR_SELECTOR_POLL);
867e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
868e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        return false;
869e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
870e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
871e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
87246d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * Check if UI element exists.
87346d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     *
874e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * This methods performs a {@link #waitForExists(long)} with zero timeout. This
875e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * basically returns immediately whether the UI element represented by this UiObject
876e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * exists or not. If you need to wait longer for this UI element, then see
877e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * {@link #waitForExists(long)}.
8783d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
879e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @return true if the UI element represented by this UiObject does exist
880dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
881e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
882e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    public boolean exists() {
883f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine        Tracer.trace();
884e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        return waitForExists(0);
885e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
886e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
887e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    private String safeStringReturn(CharSequence cs) {
888e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        if(cs == null)
889e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            return "";
890e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        return cs.toString();
891e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
892c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz
893c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz    /**
894c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz     * PinchOut generates a 2 pointer gesture where each pointer is moving from the center out
895c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz     * away from each other diagonally towards the edges of the current UI element represented by
896c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz     * this UiObject.
897c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz     * @param percent of the object's diagonal length to use for the pinch
898c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz     * @param steps indicates the number of injected move steps into the system. Steps are
899c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz     * injected about 5ms apart. So a 100 steps may take about 1/2 second to complete.
9001078ab1070411af45d5e8ec3b56abec6789e7722Guang Zhu     * @return <code>true</code> if all touch events for this gesture are injected successfully,
9011078ab1070411af45d5e8ec3b56abec6789e7722Guang Zhu     *          <code>false</code> otherwise
902c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz     * @throws UiObjectNotFoundException
903c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz     * @since API Level 18
904c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz     */
9051078ab1070411af45d5e8ec3b56abec6789e7722Guang Zhu    public boolean pinchOut(int percent, int steps) throws UiObjectNotFoundException {
906c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        // make value between 1 and 100
907c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        percent = (percent < 0) ? 1 : (percent > 100) ? 100 : percent;
908c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        float percentage = percent / 100f;
909c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz
9100d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz        AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout());
911c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        if (node == null) {
912c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz            throw new UiObjectNotFoundException(getSelector().toString());
913c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        }
914c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz
915c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        Rect rect = getVisibleBounds(node);
916c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        if (rect.width() <= FINGER_TOUCH_HALF_WIDTH * 2)
917c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz            throw new IllegalStateException("Object width is too small for operation");
918c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz
919c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        // start from the same point at the center of the control
920c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        Point startPoint1 = new Point(rect.centerX() - FINGER_TOUCH_HALF_WIDTH, rect.centerY());
921c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        Point startPoint2 = new Point(rect.centerX() + FINGER_TOUCH_HALF_WIDTH, rect.centerY());
922c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz
923c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        // End at the top-left and bottom-right corners of the control
924c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        Point endPoint1 = new Point(rect.centerX() - (int)((rect.width()/2) * percentage),
925c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz                rect.centerY());
926c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        Point endPoint2 = new Point(rect.centerX() + (int)((rect.width()/2) * percentage),
927c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz                rect.centerY());
928c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz
9291078ab1070411af45d5e8ec3b56abec6789e7722Guang Zhu        return performTwoPointerGesture(startPoint1, startPoint2, endPoint1, endPoint2, steps);
930c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz    }
931c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz
932c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz    /**
933c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz     * PinchIn generates a 2 pointer gesture where each pointer is moving towards the other
934c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz     * diagonally from the edges of the current UI element represented by this UiObject, until the
935c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz     * center.
936c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz     * @param percent of the object's diagonal length to use for the pinch
937c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz     * @param steps indicates the number of injected move steps into the system. Steps are
938c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz     * injected about 5ms apart. So a 100 steps may take about 1/2 second to complete.
9391078ab1070411af45d5e8ec3b56abec6789e7722Guang Zhu     * @return <code>true</code> if all touch events for this gesture are injected successfully,
9401078ab1070411af45d5e8ec3b56abec6789e7722Guang Zhu     *          <code>false</code> otherwise
941c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz     * @throws UiObjectNotFoundException
942c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz     * @since API Level 18
943c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz     */
9441078ab1070411af45d5e8ec3b56abec6789e7722Guang Zhu    public boolean pinchIn(int percent, int steps) throws UiObjectNotFoundException {
945c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        // make value between 1 and 100
946c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        percent = (percent < 0) ? 0 : (percent > 100) ? 100 : percent;
947c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        float percentage = percent / 100f;
948c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz
9490d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz        AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout());
950c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        if (node == null) {
951c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz            throw new UiObjectNotFoundException(getSelector().toString());
952c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        }
953c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz
954c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        Rect rect = getVisibleBounds(node);
955c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        if (rect.width() <= FINGER_TOUCH_HALF_WIDTH * 2)
956c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz            throw new IllegalStateException("Object width is too small for operation");
957c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz
958c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        Point startPoint1 = new Point(rect.centerX() - (int)((rect.width()/2) * percentage),
959c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz                rect.centerY());
960c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        Point startPoint2 = new Point(rect.centerX() + (int)((rect.width()/2) * percentage),
961c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz                rect.centerY());
962c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz
963c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        Point endPoint1 = new Point(rect.centerX() - FINGER_TOUCH_HALF_WIDTH, rect.centerY());
964c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        Point endPoint2 = new Point(rect.centerX() + FINGER_TOUCH_HALF_WIDTH, rect.centerY());
965c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz
9661078ab1070411af45d5e8ec3b56abec6789e7722Guang Zhu        return performTwoPointerGesture(startPoint1, startPoint2, endPoint1, endPoint2, steps);
967c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz    }
968c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz
969c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz    /**
970c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz     * Generates a 2 pointer gesture from an arbitrary starting and ending points.
971c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz     *
972c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz     * @param startPoint1 start point of pointer 1
973c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz     * @param startPoint2 start point of pointer 2
974c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz     * @param endPoint1 end point of pointer 1
975c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz     * @param endPoint2 end point of pointer 2
976c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz     * @param steps indicates the number of injected move steps into the system. Steps are
977c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz     * injected about 5ms apart. So a 100 steps may take about 1/2 second to complete.
9781078ab1070411af45d5e8ec3b56abec6789e7722Guang Zhu     * @return <code>true</code> if all touch events for this gesture are injected successfully,
9791078ab1070411af45d5e8ec3b56abec6789e7722Guang Zhu     *          <code>false</code> otherwise
980c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz     * @since API Level 18
981c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz     */
9821078ab1070411af45d5e8ec3b56abec6789e7722Guang Zhu    public boolean performTwoPointerGesture(Point startPoint1, Point startPoint2, Point endPoint1,
983c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz            Point endPoint2, int steps) {
984c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz
985c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        // avoid a divide by zero
986c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        if(steps == 0)
987c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz            steps = 1;
988c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz
989c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        final float stepX1 = (endPoint1.x - startPoint1.x) / steps;
990c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        final float stepY1 = (endPoint1.y - startPoint1.y) / steps;
991c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        final float stepX2 = (endPoint2.x - startPoint2.x) / steps;
992c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        final float stepY2 = (endPoint2.y - startPoint2.y) / steps;
993c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz
994c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        int eventX1, eventY1, eventX2, eventY2;
995c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        eventX1 = startPoint1.x;
996c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        eventY1 = startPoint1.y;
997c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        eventX2 = startPoint2.x;
998c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        eventY2 = startPoint2.y;
999c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz
1000c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        // allocate for steps plus first down and last up
1001c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        PointerCoords[] points1 = new PointerCoords[steps + 2];
1002c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        PointerCoords[] points2 = new PointerCoords[steps + 2];
1003c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz
1004c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        // Include the first and last touch downs in the arrays of steps
1005c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        for (int i = 0; i < steps + 1; i++) {
1006c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz            PointerCoords p1 = new PointerCoords();
1007c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz            p1.x = eventX1;
1008c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz            p1.y = eventY1;
1009c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz            p1.pressure = 1;
1010c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz            p1.size = 1;
1011c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz            points1[i] = p1;
1012c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz
1013c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz            PointerCoords p2 = new PointerCoords();
1014c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz            p2.x = eventX2;
1015c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz            p2.y = eventY2;
1016c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz            p2.pressure = 1;
1017c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz            p2.size = 1;
1018c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz            points2[i] = p2;
1019c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz
1020c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz            eventX1 += stepX1;
1021c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz            eventY1 += stepY1;
1022c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz            eventX2 += stepX2;
1023c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz            eventY2 += stepY2;
1024c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        }
1025c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz
1026c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        // ending pointers coordinates
1027c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        PointerCoords p1 = new PointerCoords();
1028c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        p1.x = endPoint1.x;
1029c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        p1.y = endPoint1.y;
1030c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        p1.pressure = 1;
1031c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        p1.size = 1;
1032c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        points1[steps + 1] = p1;
1033c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz
1034c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        PointerCoords p2 = new PointerCoords();
1035c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        p2.x = endPoint2.x;
1036c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        p2.y = endPoint2.y;
1037c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        p2.pressure = 1;
1038c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        p2.size = 1;
1039c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        points2[steps + 1] = p2;
1040c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz
10411078ab1070411af45d5e8ec3b56abec6789e7722Guang Zhu        return performMultiPointerGesture(points1, points2);
1042c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz    }
1043c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz
1044c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz    /**
1045c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz     * Performs a multi-touch gesture
1046c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz     *
1047c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz     * Takes a series of touch coordinates for at least 2 pointers. Each pointer must have
1048c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz     * all of its touch steps defined in an array of {@link PointerCoords}. By having the ability
1049c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz     * to specify the touch points along the path of a pointer, the caller is able to specify
1050c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz     * complex gestures like circles, irregular shapes etc, where each pointer may take a
1051c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz     * different path.
1052c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz     *
1053c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz     * To create a single point on a pointer's touch path
1054c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz     * <code>
1055c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz     *       PointerCoords p = new PointerCoords();
1056c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz     *       p.x = stepX;
1057c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz     *       p.y = stepY;
1058c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz     *       p.pressure = 1;
1059c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz     *       p.size = 1;
1060c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz     * </code>
1061c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz     * @param touches each array of {@link PointerCoords} constitute a single pointer's touch path.
1062c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz     *        Multiple {@link PointerCoords} arrays constitute multiple pointers, each with its own
1063c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz     *        path. Each {@link PointerCoords} in an array constitute a point on a pointer's path.
10641078ab1070411af45d5e8ec3b56abec6789e7722Guang Zhu     * @return <code>true</code> if all touch events for this gesture are injected successfully,
10651078ab1070411af45d5e8ec3b56abec6789e7722Guang Zhu     *          <code>false</code> otherwise
1066c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz     * @since API Level 18
1067c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz     */
10681078ab1070411af45d5e8ec3b56abec6789e7722Guang Zhu    public boolean performMultiPointerGesture(PointerCoords[] ...touches) {
10691078ab1070411af45d5e8ec3b56abec6789e7722Guang Zhu        return getInteractionController().performMultiPointerGesture(touches);
1070c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz    }
1071b4671570eb1caa88c7b6042f81f1ca3a2cb6a916Guang Zhu}
1072