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/**
28445e82ee022c484166ce7175973827f591ff2ea7quddusc * A UiObject is a representation of a view. It is not in any way directly bound to a
29445e82ee022c484166ce7175973827f591ff2ea7quddusc * view as an object reference. A UiObject contains information to help it
30445e82ee022c484166ce7175973827f591ff2ea7quddusc * locate a matching view at runtime based on the {@link UiSelector} properties specified in
31445e82ee022c484166ce7175973827f591ff2ea7quddusc * its constructor. Once you create an instance of a UiObject, it can
32445e82ee022c484166ce7175973827f591ff2ea7quddusc * be reused for different views that match the selector criteria.
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    /**
72445e82ee022c484166ce7175973827f591ff2ea7quddusc     * Constructs a UiObject to represent a view that matches the specified
73445e82ee022c484166ce7175973827f591ff2ea7quddusc     * selector criteria.
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,
105445e82ee022c484166ce7175973827f591ff2ea7quddusc     * 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    /**
114445e82ee022c484166ce7175973827f591ff2ea7quddusc     * Creates a new UiObject for a child view that is under the present UiObject.
1153d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
116445e82ee022c484166ce7175973827f591ff2ea7quddusc     * @param selector for child view to match
117445e82ee022c484166ce7175973827f591ff2ea7quddusc     * @return a new UiObject representing the child view
118dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
119e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
1204ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz    public UiObject getChild(UiSelector selector) throws UiObjectNotFoundException {
121f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine        Tracer.trace(selector);
1224ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz        return new UiObject(getSelector().childSelector(selector));
123e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
124e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
125e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
126445e82ee022c484166ce7175973827f591ff2ea7quddusc     * Creates a new UiObject for a sibling view or a child of the sibling view,
127445e82ee022c484166ce7175973827f591ff2ea7quddusc     * relative to the present UiObject.
1283d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
129445e82ee022c484166ce7175973827f591ff2ea7quddusc     * @param selector for a sibling view or children of the sibling view
130445e82ee022c484166ce7175973827f591ff2ea7quddusc     * @return a new UiObject representing the matched view
131e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @throws UiObjectNotFoundException
132dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
133e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
1344ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz    public UiObject getFromParent(UiSelector selector) throws UiObjectNotFoundException {
135f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine        Tracer.trace(selector);
1364ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz        return new UiObject(getSelector().fromParent(selector));
137e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
138e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
139e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
140445e82ee022c484166ce7175973827f591ff2ea7quddusc     * Counts the child views immediately under the present UiObject.
1413d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
142445e82ee022c484166ce7175973827f591ff2ea7quddusc     * @return the count of child views.
143e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @throws UiObjectNotFoundException
144dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
145e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
146e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    public int getChildCount() throws UiObjectNotFoundException {
147f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine        Tracer.trace();
1480d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz        AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout());
149e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        if(node == null) {
150e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            throw new UiObjectNotFoundException(getSelector().toString());
151e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
152e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        return node.getChildCount();
153e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
154e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
155e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
156445e82ee022c484166ce7175973827f591ff2ea7quddusc     * Finds a matching UI element in the accessibility hierarchy, by
157445e82ee022c484166ce7175973827f591ff2ea7quddusc     * using the selector for this UiObject.
1583d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
159e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @param timeout in milliseconds
160e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @return AccessibilityNodeInfo if found else null
161dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
162e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
163e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    protected AccessibilityNodeInfo findAccessibilityNodeInfo(long timeout) {
164e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        AccessibilityNodeInfo node = null;
165bb36257f15f090966e2aeb9fd4f092e1a54722b1Adam Momtaz        long startMills = SystemClock.uptimeMillis();
166bb36257f15f090966e2aeb9fd4f092e1a54722b1Adam Momtaz        long currentMills = 0;
167bb36257f15f090966e2aeb9fd4f092e1a54722b1Adam Momtaz        while (currentMills <= timeout) {
168e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            node = getQueryController().findAccessibilityNodeInfo(getSelector());
169bb36257f15f090966e2aeb9fd4f092e1a54722b1Adam Momtaz            if (node != null) {
170bb36257f15f090966e2aeb9fd4f092e1a54722b1Adam Momtaz                break;
171bb36257f15f090966e2aeb9fd4f092e1a54722b1Adam Momtaz            } else {
172bb36257f15f090966e2aeb9fd4f092e1a54722b1Adam Momtaz                // does nothing if we're reentering another runWatchers()
173bb36257f15f090966e2aeb9fd4f092e1a54722b1Adam Momtaz                UiDevice.getInstance().runWatchers();
174bb36257f15f090966e2aeb9fd4f092e1a54722b1Adam Momtaz            }
175bb36257f15f090966e2aeb9fd4f092e1a54722b1Adam Momtaz            currentMills = SystemClock.uptimeMillis() - startMills;
176bb36257f15f090966e2aeb9fd4f092e1a54722b1Adam Momtaz            if(timeout > 0) {
177bb36257f15f090966e2aeb9fd4f092e1a54722b1Adam Momtaz                SystemClock.sleep(WAIT_FOR_SELECTOR_POLL);
178e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            }
179e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
180e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        return node;
181e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
182e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
183e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
184445e82ee022c484166ce7175973827f591ff2ea7quddusc     * Drags this object to a destination UiObject.
185445e82ee022c484166ce7175973827f591ff2ea7quddusc     * The number of steps specified in your input parameter can influence the
186445e82ee022c484166ce7175973827f591ff2ea7quddusc     * drag speed, and varying speeds may impact the results. Consider
187445e82ee022c484166ce7175973827f591ff2ea7quddusc     * evaluating different speeds when using this method in your tests.
1888d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz     *
189445e82ee022c484166ce7175973827f591ff2ea7quddusc     * @param destObj the destination UiObject.
190445e82ee022c484166ce7175973827f591ff2ea7quddusc     * @param steps usually 40 steps. You can increase or decrease the steps to change the speed.
191445e82ee022c484166ce7175973827f591ff2ea7quddusc     * @return true if successful
1928d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz     * @throws UiObjectNotFoundException
1938d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz     * @since API Level 18
1948d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz     */
1958d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz    public boolean dragTo(UiObject destObj, int steps) throws UiObjectNotFoundException {
1968d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz        Rect srcRect = getVisibleBounds();
1978d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz        Rect dstRect = destObj.getVisibleBounds();
1988d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz        return getInteractionController().swipe(srcRect.centerX(), srcRect.centerY(),
1998d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz                dstRect.centerX(), dstRect.centerY(), steps, true);
2008d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz    }
2018d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz
2028d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz    /**
203445e82ee022c484166ce7175973827f591ff2ea7quddusc     * Drags this object to arbitrary coordinates.
204445e82ee022c484166ce7175973827f591ff2ea7quddusc     * The number of steps specified in your input parameter can influence the
205445e82ee022c484166ce7175973827f591ff2ea7quddusc     * drag speed, and varying speeds may impact the results. Consider
206445e82ee022c484166ce7175973827f591ff2ea7quddusc     * evaluating different speeds when using this method in your tests.
2078d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz     *
208445e82ee022c484166ce7175973827f591ff2ea7quddusc     * @param destX the X-axis coordinate.
209445e82ee022c484166ce7175973827f591ff2ea7quddusc     * @param destY the Y-axis coordinate.
210445e82ee022c484166ce7175973827f591ff2ea7quddusc     * @param steps usually 40 steps. You can increase or decrease the steps to change the speed.
211445e82ee022c484166ce7175973827f591ff2ea7quddusc     * @return true if successful
2128d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz     * @throws UiObjectNotFoundException
2138d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz     * @since API Level 18
2148d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz     */
2158d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz    public boolean dragTo(int destX, int destY, int steps) throws UiObjectNotFoundException {
2168d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz        Rect srcRect = getVisibleBounds();
2178d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz        return getInteractionController().swipe(srcRect.centerX(), srcRect.centerY(), destX, destY,
2188d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz                steps, true);
2198d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz    }
2208d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz
2218d7e1dc0248bf9d3c7b133eaac79b7fb31321564Adam Momtaz    /**
222445e82ee022c484166ce7175973827f591ff2ea7quddusc     * Performs the swipe up action on the UiObject.
223445e82ee022c484166ce7175973827f591ff2ea7quddusc     * See also:
224445e82ee022c484166ce7175973827f591ff2ea7quddusc     * <ul>
225445e82ee022c484166ce7175973827f591ff2ea7quddusc     * <li>{@link UiScrollable#scrollToBeginning(int)}</li>
226445e82ee022c484166ce7175973827f591ff2ea7quddusc     * <li>{@link UiScrollable#scrollToEnd(int)}</li>
227445e82ee022c484166ce7175973827f591ff2ea7quddusc     * <li>{@link UiScrollable#scrollBackward()}</li>
228445e82ee022c484166ce7175973827f591ff2ea7quddusc     * <li>{@link UiScrollable#scrollForward()}</li>
229445e82ee022c484166ce7175973827f591ff2ea7quddusc     * </ul>
2303d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
231467cca7d25dbbf13c14cfd8c2ad38ab8eaf56bdaAdam Momtaz     * @param steps indicates the number of injected move steps into the system. Steps are
232467cca7d25dbbf13c14cfd8c2ad38ab8eaf56bdaAdam Momtaz     * injected about 5ms apart. So a 100 steps may take about 1/2 second to complete.
2333d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * @return true of successful
234e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @throws UiObjectNotFoundException
235dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
236e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
237e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    public boolean swipeUp(int steps) throws UiObjectNotFoundException {
238f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine        Tracer.trace(steps);
2393d50587be8ff021369c90554d814839335b445b0Adam Momtaz        Rect rect = getVisibleBounds();
240e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        if(rect.height() <= SWIPE_MARGIN_LIMIT * 2)
241e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            return false; // too small to swipe
242e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        return getInteractionController().swipe(rect.centerX(),
243e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                rect.bottom - SWIPE_MARGIN_LIMIT, rect.centerX(), rect.top + SWIPE_MARGIN_LIMIT,
244e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                steps);
245e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
246e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
247e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
248445e82ee022c484166ce7175973827f591ff2ea7quddusc     * Performs the swipe down action on the UiObject.
249445e82ee022c484166ce7175973827f591ff2ea7quddusc     * The swipe gesture can be performed over any surface. The targeted
250445e82ee022c484166ce7175973827f591ff2ea7quddusc     * UI element does not need to be scrollable.
251445e82ee022c484166ce7175973827f591ff2ea7quddusc     * See also:
252445e82ee022c484166ce7175973827f591ff2ea7quddusc     * <ul>
253445e82ee022c484166ce7175973827f591ff2ea7quddusc     * <li>{@link UiScrollable#scrollToBeginning(int)}</li>
254445e82ee022c484166ce7175973827f591ff2ea7quddusc     * <li>{@link UiScrollable#scrollToEnd(int)}</li>
255445e82ee022c484166ce7175973827f591ff2ea7quddusc     * <li>{@link UiScrollable#scrollBackward()}</li>
256445e82ee022c484166ce7175973827f591ff2ea7quddusc     * <li>{@link UiScrollable#scrollForward()}</li>
257445e82ee022c484166ce7175973827f591ff2ea7quddusc     * </ul>
2583d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
2593d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * @param steps indicates the number of injected move steps into the system. Steps are
260467cca7d25dbbf13c14cfd8c2ad38ab8eaf56bdaAdam Momtaz     * injected about 5ms apart. So a 100 steps may take about 1/2 second to complete.
2613d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * @return true if successful
262e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @throws UiObjectNotFoundException
263dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
264e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
265e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    public boolean swipeDown(int steps) throws UiObjectNotFoundException {
266f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine        Tracer.trace(steps);
2673d50587be8ff021369c90554d814839335b445b0Adam Momtaz        Rect rect = getVisibleBounds();
268e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        if(rect.height() <= SWIPE_MARGIN_LIMIT * 2)
269e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            return false; // too small to swipe
270e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        return getInteractionController().swipe(rect.centerX(),
271e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                rect.top + SWIPE_MARGIN_LIMIT, rect.centerX(),
272e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                rect.bottom - SWIPE_MARGIN_LIMIT, steps);
273e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
274e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
275e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
276445e82ee022c484166ce7175973827f591ff2ea7quddusc     * Performs the swipe left action on the UiObject.
277445e82ee022c484166ce7175973827f591ff2ea7quddusc     * The swipe gesture can be performed over any surface. The targeted
278445e82ee022c484166ce7175973827f591ff2ea7quddusc     * UI element does not need to be scrollable.
279445e82ee022c484166ce7175973827f591ff2ea7quddusc     * See also:
280445e82ee022c484166ce7175973827f591ff2ea7quddusc     * <ul>
281445e82ee022c484166ce7175973827f591ff2ea7quddusc     * <li>{@link UiScrollable#scrollToBeginning(int)}</li>
282445e82ee022c484166ce7175973827f591ff2ea7quddusc     * <li>{@link UiScrollable#scrollToEnd(int)}</li>
283445e82ee022c484166ce7175973827f591ff2ea7quddusc     * <li>{@link UiScrollable#scrollBackward()}</li>
284445e82ee022c484166ce7175973827f591ff2ea7quddusc     * <li>{@link UiScrollable#scrollForward()}</li>
285445e82ee022c484166ce7175973827f591ff2ea7quddusc     * </ul>
2863d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
2873d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * @param steps indicates the number of injected move steps into the system. Steps are
288467cca7d25dbbf13c14cfd8c2ad38ab8eaf56bdaAdam Momtaz     * injected about 5ms apart. So a 100 steps may take about 1/2 second to complete.
2893d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * @return true if successful
290e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @throws UiObjectNotFoundException
291dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
292e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
293e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    public boolean swipeLeft(int steps) throws UiObjectNotFoundException {
294f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine        Tracer.trace(steps);
2953d50587be8ff021369c90554d814839335b445b0Adam Momtaz        Rect rect = getVisibleBounds();
296e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        if(rect.width() <= SWIPE_MARGIN_LIMIT * 2)
297e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            return false; // too small to swipe
298e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        return getInteractionController().swipe(rect.right - SWIPE_MARGIN_LIMIT,
299e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                rect.centerY(), rect.left + SWIPE_MARGIN_LIMIT, rect.centerY(), steps);
300e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
301e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
302e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
303445e82ee022c484166ce7175973827f591ff2ea7quddusc     * Performs the swipe right action on the UiObject.
304445e82ee022c484166ce7175973827f591ff2ea7quddusc     * The swipe gesture can be performed over any surface. The targeted
305445e82ee022c484166ce7175973827f591ff2ea7quddusc     * UI element does not need to be scrollable.
306445e82ee022c484166ce7175973827f591ff2ea7quddusc     * See also:
307445e82ee022c484166ce7175973827f591ff2ea7quddusc     * <ul>
308445e82ee022c484166ce7175973827f591ff2ea7quddusc     * <li>{@link UiScrollable#scrollToBeginning(int)}</li>
309445e82ee022c484166ce7175973827f591ff2ea7quddusc     * <li>{@link UiScrollable#scrollToEnd(int)}</li>
310445e82ee022c484166ce7175973827f591ff2ea7quddusc     * <li>{@link UiScrollable#scrollBackward()}</li>
311445e82ee022c484166ce7175973827f591ff2ea7quddusc     * <li>{@link UiScrollable#scrollForward()}</li>
312445e82ee022c484166ce7175973827f591ff2ea7quddusc     * </ul>
3133d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
3143d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * @param steps indicates the number of injected move steps into the system. Steps are
315467cca7d25dbbf13c14cfd8c2ad38ab8eaf56bdaAdam Momtaz     * injected about 5ms apart. So a 100 steps may take about 1/2 second to complete.
3163d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * @return true if successful
317e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @throws UiObjectNotFoundException
318dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
319e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
320e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    public boolean swipeRight(int steps) throws UiObjectNotFoundException {
321f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine        Tracer.trace(steps);
3223d50587be8ff021369c90554d814839335b445b0Adam Momtaz        Rect rect = getVisibleBounds();
323e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        if(rect.width() <= SWIPE_MARGIN_LIMIT * 2)
324e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            return false; // too small to swipe
325e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        return getInteractionController().swipe(rect.left + SWIPE_MARGIN_LIMIT,
326e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                rect.centerY(), rect.right - SWIPE_MARGIN_LIMIT, rect.centerY(), steps);
327e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
328e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
329e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
3303d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * Finds the visible bounds of a partially visible UI element
3313d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
332e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @param node
3337f38ef08d07295967b905a61b2356ff6cdf31159Adam Momtaz     * @return null if node is null, else a Rect containing visible bounds
334e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
335e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    private Rect getVisibleBounds(AccessibilityNodeInfo node) {
336e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        if (node == null) {
337e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            return null;
338e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
339e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
340e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        // targeted node's bounds
34123296fc6448cd265fbb45c1fd9041976ae0da274Guang Zhu        int w = UiDevice.getInstance().getDisplayWidth();
34223296fc6448cd265fbb45c1fd9041976ae0da274Guang Zhu        int h = UiDevice.getInstance().getDisplayHeight();
34323296fc6448cd265fbb45c1fd9041976ae0da274Guang Zhu        Rect nodeRect = AccessibilityNodeInfoHelper.getVisibleBoundsInScreen(node, w, h);
344e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
345e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        // is the targeted node within a scrollable container?
346e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        AccessibilityNodeInfo scrollableParentNode = getScrollableParent(node);
347e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        if(scrollableParentNode == null) {
348e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            // nothing to adjust for so return the node's Rect as is
349e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            return nodeRect;
350e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
351e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
352e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        // Scrollable parent's visible bounds
3537f38ef08d07295967b905a61b2356ff6cdf31159Adam Momtaz        Rect parentRect = AccessibilityNodeInfoHelper
35423296fc6448cd265fbb45c1fd9041976ae0da274Guang Zhu                .getVisibleBoundsInScreen(scrollableParentNode, w, h);
355e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        // adjust for partial clipping of targeted by parent node if required
356e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        nodeRect.intersect(parentRect);
357e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        return nodeRect;
358e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
359e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
360e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
361445e82ee022c484166ce7175973827f591ff2ea7quddusc     * Walks up the layout hierarchy to find a scrollable parent. A scrollable parent
362445e82ee022c484166ce7175973827f591ff2ea7quddusc     * indicates that this node might be in a container where it is partially
363445e82ee022c484166ce7175973827f591ff2ea7quddusc     * visible due to scrolling. In this case, its clickable center might not be visible and
364445e82ee022c484166ce7175973827f591ff2ea7quddusc     * the click coordinates should be adjusted.
3653d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
366e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @param node
3671893caed0ad4e73b0676f206282d490c2d345316Thanh Le     * @return The accessibility node info.
368e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
369e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    private AccessibilityNodeInfo getScrollableParent(AccessibilityNodeInfo node) {
370e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        AccessibilityNodeInfo parent = node;
371e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        while(parent != null) {
372e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            parent = parent.getParent();
373e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            if (parent != null && parent.isScrollable()) {
374e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                return parent;
375e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            }
376e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
377e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        return null;
378e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
379e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
380e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
3813d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * Performs a click at the center of the visible bounds of the UI element represented
38246d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * by this UiObject.
3833d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
384e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @return true id successful else false
385e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @throws UiObjectNotFoundException
386dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
387e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
388e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    public boolean click() throws UiObjectNotFoundException {
389f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine        Tracer.trace();
3900d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz        AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout());
391e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        if(node == null) {
392e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            throw new UiObjectNotFoundException(getSelector().toString());
393e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
394e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        Rect rect = getVisibleBounds(node);
3950d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz        return getInteractionController().clickAndSync(rect.centerX(), rect.centerY(),
3960d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz                mConfig.getActionAcknowledgmentTimeout());
397e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
398e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
399e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
400445e82ee022c484166ce7175973827f591ff2ea7quddusc     * Waits for window transitions that would typically take longer than the
401445e82ee022c484166ce7175973827f591ff2ea7quddusc     * usual default timeouts.
4023d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * See {@link #clickAndWaitForNewWindow(long)}
4033d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
4043d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * @return true if the event was triggered, else false
4053d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * @throws UiObjectNotFoundException
406dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
4073d50587be8ff021369c90554d814839335b445b0Adam Momtaz     */
408e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    public boolean clickAndWaitForNewWindow() throws UiObjectNotFoundException {
409f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine        Tracer.trace();
410e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        return clickAndWaitForNewWindow(WAIT_FOR_WINDOW_TMEOUT);
411e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
412e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
413e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
41446d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * Performs a click at the center of the visible bounds of the UI element represented
41546d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * by this UiObject and waits for window transitions.
41646d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     *
4173d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * This method differ from {@link UiObject#click()} only in that this method waits for a
41846d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * a new window transition as a result of the click. Some examples of a window transition:
419e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * <li>launching a new activity</li>
420e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * <li>bringing up a pop-up menu</li>
421e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * <li>bringing up a dialog</li>
422e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     *
4233d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * @param timeout timeout before giving up on waiting for a new window
424e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @return true if the event was triggered, else false
425e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @throws UiObjectNotFoundException
426dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
427e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
428e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    public boolean clickAndWaitForNewWindow(long timeout) throws UiObjectNotFoundException {
429f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine        Tracer.trace(timeout);
4300d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz        AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout());
431e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        if(node == null) {
432e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            throw new UiObjectNotFoundException(getSelector().toString());
433e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
434e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        Rect rect = getVisibleBounds(node);
4350d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz        return getInteractionController().clickAndWaitForNewWindow(rect.centerX(), rect.centerY(),
4360d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz                mConfig.getActionAcknowledgmentTimeout());
437e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
438e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
439e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
4403d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * Clicks the top and left corner of the UI element
4413d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
442e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @return true on success
4431893caed0ad4e73b0676f206282d490c2d345316Thanh Le     * @throws UiObjectNotFoundException
444dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
445e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
446e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    public boolean clickTopLeft() throws UiObjectNotFoundException {
447f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine        Tracer.trace();
4480d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz        AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout());
449e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        if(node == null) {
450e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            throw new UiObjectNotFoundException(getSelector().toString());
451e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
452e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        Rect rect = getVisibleBounds(node);
4531dc7d12406947faaee8454c6efb2a0631f5da573Adam Momtaz        return getInteractionController().clickNoSync(rect.left + 5, rect.top + 5);
454e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
455e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
456e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
4573d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * Long clicks bottom and right corner of the UI element
4583d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
459e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @return true if operation was successful
460e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @throws UiObjectNotFoundException
461dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
462e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
463e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    public boolean longClickBottomRight() throws UiObjectNotFoundException  {
464f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine        Tracer.trace();
4650d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz        AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout());
466e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        if(node == null) {
467e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            throw new UiObjectNotFoundException(getSelector().toString());
468e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
469e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        Rect rect = getVisibleBounds(node);
4701dc7d12406947faaee8454c6efb2a0631f5da573Adam Momtaz        return getInteractionController().longTapNoSync(rect.right - 5, rect.bottom - 5);
471e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
472e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
473e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
4743d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * Clicks the bottom and right corner of the UI element
4753d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
476e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @return true on success
4771893caed0ad4e73b0676f206282d490c2d345316Thanh Le     * @throws UiObjectNotFoundException
478dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
479e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
480e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    public boolean clickBottomRight() throws UiObjectNotFoundException {
481f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine        Tracer.trace();
4820d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz        AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout());
483e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        if(node == null) {
484e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            throw new UiObjectNotFoundException(getSelector().toString());
485e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
486e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        Rect rect = getVisibleBounds(node);
4871dc7d12406947faaee8454c6efb2a0631f5da573Adam Momtaz        return getInteractionController().clickNoSync(rect.right - 5, rect.bottom - 5);
488e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
489e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
490e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
4913d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * Long clicks the center of the visible bounds of the UI element
4923d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
493e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @return true if operation was successful
494e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @throws UiObjectNotFoundException
495dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
496e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
497e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    public boolean longClick() throws UiObjectNotFoundException  {
498f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine        Tracer.trace();
4990d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz        AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout());
500e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        if(node == null) {
501e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            throw new UiObjectNotFoundException(getSelector().toString());
502e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
503e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        Rect rect = getVisibleBounds(node);
5041dc7d12406947faaee8454c6efb2a0631f5da573Adam Momtaz        return getInteractionController().longTapNoSync(rect.centerX(), rect.centerY());
505e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
506e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
507e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
5083d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * Long clicks on the top and left corner of the UI element
5093d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
510e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @return true if operation was successful
511e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @throws UiObjectNotFoundException
512dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
513e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
514e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    public boolean longClickTopLeft() throws UiObjectNotFoundException {
515f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine        Tracer.trace();
5160d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz        AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout());
517e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        if(node == null) {
518e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            throw new UiObjectNotFoundException(getSelector().toString());
519e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
520e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        Rect rect = getVisibleBounds(node);
5211dc7d12406947faaee8454c6efb2a0631f5da573Adam Momtaz        return getInteractionController().longTapNoSync(rect.left + 5, rect.top + 5);
522e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
523e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
524e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
5253d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * Reads the <code>text</code> property of the UI element
5263d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
527e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @return text value of the current node represented by this UiObject
528e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @throws UiObjectNotFoundException if no match could be found
529dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
530e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
531e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    public String getText() throws UiObjectNotFoundException {
532f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine        Tracer.trace();
5330d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz        AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout());
534e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        if(node == null) {
535e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            throw new UiObjectNotFoundException(getSelector().toString());
536e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
537e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        String retVal = safeStringReturn(node.getText());
538e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        Log.d(LOG_TAG, String.format("getText() = %s", retVal));
539e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        return retVal;
540e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
541e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
542e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
543445e82ee022c484166ce7175973827f591ff2ea7quddusc     * Retrieves the <code>className</code> property of the UI element.
54497835f3a7c80b147136c44c175eb9e6a4261fd92Adam Momtaz     *
54597835f3a7c80b147136c44c175eb9e6a4261fd92Adam Momtaz     * @return class name of the current node represented by this UiObject
546445e82ee022c484166ce7175973827f591ff2ea7quddusc     * @throws UiObjectNotFoundException if no match was found
54797835f3a7c80b147136c44c175eb9e6a4261fd92Adam Momtaz     * @since API Level 18
54897835f3a7c80b147136c44c175eb9e6a4261fd92Adam Momtaz     */
54997835f3a7c80b147136c44c175eb9e6a4261fd92Adam Momtaz    public String getClassName() throws UiObjectNotFoundException {
55097835f3a7c80b147136c44c175eb9e6a4261fd92Adam Momtaz        Tracer.trace();
5510d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz        AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout());
55297835f3a7c80b147136c44c175eb9e6a4261fd92Adam Momtaz        if(node == null) {
55397835f3a7c80b147136c44c175eb9e6a4261fd92Adam Momtaz            throw new UiObjectNotFoundException(getSelector().toString());
55497835f3a7c80b147136c44c175eb9e6a4261fd92Adam Momtaz        }
55597835f3a7c80b147136c44c175eb9e6a4261fd92Adam Momtaz        String retVal = safeStringReturn(node.getClassName());
55697835f3a7c80b147136c44c175eb9e6a4261fd92Adam Momtaz        Log.d(LOG_TAG, String.format("getClassName() = %s", retVal));
55797835f3a7c80b147136c44c175eb9e6a4261fd92Adam Momtaz        return retVal;
55897835f3a7c80b147136c44c175eb9e6a4261fd92Adam Momtaz    }
55997835f3a7c80b147136c44c175eb9e6a4261fd92Adam Momtaz
56097835f3a7c80b147136c44c175eb9e6a4261fd92Adam Momtaz    /**
5613d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * Reads the <code>content_desc</code> property of the UI element
5623d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
563e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @return value of node attribute "content_desc"
564e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @throws UiObjectNotFoundException
565dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
566e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
567e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    public String getContentDescription() throws UiObjectNotFoundException {
568f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine        Tracer.trace();
5690d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz        AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout());
570e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        if(node == null) {
571e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            throw new UiObjectNotFoundException(getSelector().toString());
572e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
573e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        return safeStringReturn(node.getContentDescription());
574e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
575e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
576e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
57746d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * Sets the text in an editable field, after clearing the field's content.
57846d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     *
57946d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * The {@link UiSelector} selector of this object must reference a UI element that is editable.
58046d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     *
58146d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * When you call this method, the method first simulates a {@link #click()} on
58246d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * editable field to set focus. The method then clears the field's contents
58346d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * and injects your specified text into the field.
5843d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
58546d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * If you want to capture the original contents of the field, call {@link #getText()} first.
58646d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * You can then modify the text and use this method to update the field.
58746d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     *
58846d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * @param text string to set
589e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @return true if operation is successful
590e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @throws UiObjectNotFoundException
591dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
592e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
593e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    public boolean setText(String text) throws UiObjectNotFoundException {
594f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine        Tracer.trace(text);
595e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        clearTextField();
596e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        return getInteractionController().sendText(text);
597e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
598e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
599e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
60046d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * Clears the existing text contents in an editable field.
60146d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     *
60246d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * The {@link UiSelector} of this object must reference a UI element that is editable.
60346d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     *
60446d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * When you call this method, the method first sets focus at the start edge of the field.
60546d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * The method then simulates a long-press to select the existing text, and deletes the
60646d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * selected text.
60746d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     *
60846d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * If a "Select-All" option is displayed, the method will automatically attempt to use it
60946d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * to ensure full text selection.
61046d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     *
61146d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * Note that it is possible that not all the text in the field is selected; for example,
61246d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * if the text contains separators such as spaces, slashes, at symbol etc.
61346d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * Also, not all editable fields support the long-press functionality.
61446d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     *
615e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @throws UiObjectNotFoundException
616dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
617e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
618e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    public void clearTextField() throws UiObjectNotFoundException {
619f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine        Tracer.trace();
620e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        // long click left + center
6210d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz        AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout());
622e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        if(node == null) {
623e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            throw new UiObjectNotFoundException(getSelector().toString());
624e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
625e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        Rect rect = getVisibleBounds(node);
6261dc7d12406947faaee8454c6efb2a0631f5da573Adam Momtaz        getInteractionController().longTapNoSync(rect.left + 20, rect.centerY());
627e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        // check if the edit menu is open
6284ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz        UiObject selectAll = new UiObject(new UiSelector().descriptionContains("Select all"));
629e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        if(selectAll.waitForExists(50))
630e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            selectAll.click();
631e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        // wait for the selection
632e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        SystemClock.sleep(250);
633e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        // delete it
634e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        getInteractionController().sendKey(KeyEvent.KEYCODE_DEL, 0);
635e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
636e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
637e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
6383d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * Check if the UI element's <code>checked</code> property is currently true
6393d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
640e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @return true if it is else false
641dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
642e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
643e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    public boolean isChecked() throws UiObjectNotFoundException {
644f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine        Tracer.trace();
6450d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz        AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout());
646e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        if(node == null) {
647e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            throw new UiObjectNotFoundException(getSelector().toString());
648e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
649e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        return node.isChecked();
650e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
651e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
652e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
653445e82ee022c484166ce7175973827f591ff2ea7quddusc     * Checks if the UI element's <code>selected</code> property is currently true.
6543d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
655e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @return true if it is else false
656e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @throws UiObjectNotFoundException
657dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
658e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
659e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    public boolean isSelected() throws UiObjectNotFoundException {
660f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine        Tracer.trace();
6610d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz        AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout());
662e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        if(node == null) {
663e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            throw new UiObjectNotFoundException(getSelector().toString());
664e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
665e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        return node.isSelected();
666e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
667e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
668e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
669445e82ee022c484166ce7175973827f591ff2ea7quddusc     * Checks if the UI element's <code>checkable</code> property is currently true.
6703d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
671e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @return true if it is else false
672e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @throws UiObjectNotFoundException
673dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
674e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
675e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    public boolean isCheckable() throws UiObjectNotFoundException {
676f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine        Tracer.trace();
6770d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz        AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout());
678e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        if(node == null) {
679e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            throw new UiObjectNotFoundException(getSelector().toString());
680e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
681e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        return node.isCheckable();
682e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
683e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
684e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
685445e82ee022c484166ce7175973827f591ff2ea7quddusc     * Checks if the UI element's <code>enabled</code> property is currently true.
6863d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
687e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @return true if it is else false
688e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @throws UiObjectNotFoundException
689dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
690e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
691e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    public boolean isEnabled() throws UiObjectNotFoundException {
692f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine        Tracer.trace();
6930d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz        AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout());
694e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        if(node == null) {
695e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            throw new UiObjectNotFoundException(getSelector().toString());
696e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
697e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        return node.isEnabled();
698e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
699e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
700e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
701445e82ee022c484166ce7175973827f591ff2ea7quddusc     * Checks if the UI element's <code>clickable</code> property is currently true.
7023d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
703e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @return true if it is else false
704e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @throws UiObjectNotFoundException
705dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
706e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
707e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    public boolean isClickable() throws UiObjectNotFoundException {
708f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine        Tracer.trace();
7090d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz        AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout());
710e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        if(node == null) {
711e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            throw new UiObjectNotFoundException(getSelector().toString());
712e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
713e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        return node.isClickable();
714e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
715e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
716e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
7173d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * Check if the UI element's <code>focused</code> property is currently true
7183d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
719e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @return true if it is else false
720e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @throws UiObjectNotFoundException
721dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
722e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
723e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    public boolean isFocused() throws UiObjectNotFoundException {
724f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine        Tracer.trace();
7250d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz        AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout());
726e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        if(node == null) {
727e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            throw new UiObjectNotFoundException(getSelector().toString());
728e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
729e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        return node.isFocused();
730e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
731e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
732e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
733445e82ee022c484166ce7175973827f591ff2ea7quddusc     * Check if the UI element's <code>focusable</code> property is currently true.
7343d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
735e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @return true if it is else false
736e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @throws UiObjectNotFoundException
737dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
738e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
739e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    public boolean isFocusable() throws UiObjectNotFoundException {
740f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine        Tracer.trace();
7410d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz        AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout());
742e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        if(node == null) {
743e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            throw new UiObjectNotFoundException(getSelector().toString());
744e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
745e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        return node.isFocusable();
746e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
747e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
748e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
749445e82ee022c484166ce7175973827f591ff2ea7quddusc     * Check if the view's <code>scrollable</code> property is currently true
7503d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
751e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @return true if it is else false
752e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @throws UiObjectNotFoundException
753dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
754e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
755e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    public boolean isScrollable() throws UiObjectNotFoundException {
756f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine        Tracer.trace();
7570d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz        AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout());
758e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        if(node == null) {
759e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            throw new UiObjectNotFoundException(getSelector().toString());
760e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
761e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        return node.isScrollable();
762e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
763e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
764e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
765445e82ee022c484166ce7175973827f591ff2ea7quddusc     * Check if the view's <code>long-clickable</code> property is currently true
7663d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
767e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @return true if it is else false
768e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @throws UiObjectNotFoundException
769dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
770e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
771e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    public boolean isLongClickable() throws UiObjectNotFoundException {
772f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine        Tracer.trace();
7730d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz        AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout());
774e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        if(node == null) {
775e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            throw new UiObjectNotFoundException(getSelector().toString());
776e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
777e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        return node.isLongClickable();
778e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
779e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
780e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
781445e82ee022c484166ce7175973827f591ff2ea7quddusc     * Reads the view's <code>package</code> property
7823d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
7833d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * @return true if it is else false
784e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @throws UiObjectNotFoundException
785dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
786e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
787e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    public String getPackageName() throws UiObjectNotFoundException {
788f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine        Tracer.trace();
7890d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz        AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout());
790e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        if(node == null) {
791e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            throw new UiObjectNotFoundException(getSelector().toString());
792e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
793e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        return safeStringReturn(node.getPackageName());
794e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
795e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
796e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
797445e82ee022c484166ce7175973827f591ff2ea7quddusc     * Returns the visible bounds of the view.
79846d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     *
799445e82ee022c484166ce7175973827f591ff2ea7quddusc     * If a portion of the view is visible, only the bounds of the visible portion are
80046d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * reported.
8013d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
802e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @return Rect
803e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @throws UiObjectNotFoundException
8041893caed0ad4e73b0676f206282d490c2d345316Thanh Le     * @see {@link #getBounds()}
80579693ede92636fe6f3a6ec4dc049a438fd9504ffGuang Zhu     * @since API Level 17
806e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
8073d50587be8ff021369c90554d814839335b445b0Adam Momtaz    public Rect getVisibleBounds() throws UiObjectNotFoundException {
808f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine        Tracer.trace();
8090d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz        AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout());
810e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        if(node == null) {
811e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            throw new UiObjectNotFoundException(getSelector().toString());
812e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
813e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        return getVisibleBounds(node);
814e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
815e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
816e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
817445e82ee022c484166ce7175973827f591ff2ea7quddusc     * Returns the view's <code>bounds</code> property. See {@link #getVisibleBounds()}
8183d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
8193d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * @return Rect
8203d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * @throws UiObjectNotFoundException
821dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
8223d50587be8ff021369c90554d814839335b445b0Adam Momtaz     */
8233d50587be8ff021369c90554d814839335b445b0Adam Momtaz    public Rect getBounds() throws UiObjectNotFoundException {
824f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine        Tracer.trace();
8250d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz        AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout());
8263d50587be8ff021369c90554d814839335b445b0Adam Momtaz        if(node == null) {
8273d50587be8ff021369c90554d814839335b445b0Adam Momtaz            throw new UiObjectNotFoundException(getSelector().toString());
8283d50587be8ff021369c90554d814839335b445b0Adam Momtaz        }
8293d50587be8ff021369c90554d814839335b445b0Adam Momtaz        Rect nodeRect = new Rect();
8303d50587be8ff021369c90554d814839335b445b0Adam Momtaz        node.getBoundsInScreen(nodeRect);
8313d50587be8ff021369c90554d814839335b445b0Adam Momtaz
8323d50587be8ff021369c90554d814839335b445b0Adam Momtaz        return nodeRect;
8333d50587be8ff021369c90554d814839335b445b0Adam Momtaz    }
8343d50587be8ff021369c90554d814839335b445b0Adam Momtaz
8353d50587be8ff021369c90554d814839335b445b0Adam Momtaz    /**
836445e82ee022c484166ce7175973827f591ff2ea7quddusc     * Waits a specified length of time for a view to become visible.
83746d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     *
838445e82ee022c484166ce7175973827f591ff2ea7quddusc     * This method waits until the view becomes visible on the display, or
83946d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * until the timeout has elapsed. You can use this method in situations where
84046d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * the content that you want to select is not immediately displayed.
8413d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
84246d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * @param timeout the amount of time to wait (in milliseconds)
843445e82ee022c484166ce7175973827f591ff2ea7quddusc     * @return true if the view is displayed, else false if timeout elapsed while waiting
844dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
845e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
846e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    public boolean waitForExists(long timeout) {
847f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine        Tracer.trace(timeout);
848e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        if(findAccessibilityNodeInfo(timeout) != null) {
849e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            return true;
850e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
851e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        return false;
852e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
853e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
854e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
855445e82ee022c484166ce7175973827f591ff2ea7quddusc     * Waits a specified length of time for a view to become undetectable.
8563d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
857445e82ee022c484166ce7175973827f591ff2ea7quddusc     * This method waits until a view is no longer matchable, or until the
85846d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * timeout has elapsed.
85946d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     *
860445e82ee022c484166ce7175973827f591ff2ea7quddusc     * A view becomes undetectable when the {@link UiSelector} of the object is
86146d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * unable to find a match because the element has either changed its state or is no
86246d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * longer displayed.
86346d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     *
86446d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * You can use this method when attempting to wait for some long operation
86546d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * to compete, such as downloading a large file or connecting to a remote server.
86646d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     *
86746d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * @param timeout time to wait (in milliseconds)
86846d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * @return true if the element is gone before timeout elapsed, else false if timeout elapsed
86946d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * but a matching element is still found.
870dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
871e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
872e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    public boolean waitUntilGone(long timeout) {
873f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine        Tracer.trace(timeout);
874e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        long startMills = SystemClock.uptimeMillis();
875e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        long currentMills = 0;
876e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        while (currentMills <= timeout) {
877e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            if(findAccessibilityNodeInfo(0) == null)
878e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                return true;
879e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            currentMills = SystemClock.uptimeMillis() - startMills;
880e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            if(timeout > 0)
881e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                SystemClock.sleep(WAIT_FOR_SELECTOR_POLL);
882e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
883e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        return false;
884e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
885e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
886e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
887445e82ee022c484166ce7175973827f591ff2ea7quddusc     * Check if view exists.
88846d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     *
889e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * This methods performs a {@link #waitForExists(long)} with zero timeout. This
890445e82ee022c484166ce7175973827f591ff2ea7quddusc     * basically returns immediately whether the view represented by this UiObject
891445e82ee022c484166ce7175973827f591ff2ea7quddusc     * exists or not. If you need to wait longer for this view, then see
892e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * {@link #waitForExists(long)}.
8933d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
894445e82ee022c484166ce7175973827f591ff2ea7quddusc     * @return true if the view represented by this UiObject does exist
895dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
896e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
897e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    public boolean exists() {
898f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine        Tracer.trace();
899e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        return waitForExists(0);
900e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
901e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
902e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    private String safeStringReturn(CharSequence cs) {
903e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        if(cs == null)
904e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            return "";
905e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        return cs.toString();
906e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
907c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz
908c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz    /**
909445e82ee022c484166ce7175973827f591ff2ea7quddusc     * Performs a two-pointer gesture, where each pointer moves diagonally
910445e82ee022c484166ce7175973827f591ff2ea7quddusc     * opposite across the other, from the center out towards the edges of the
911c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz     * this UiObject.
912445e82ee022c484166ce7175973827f591ff2ea7quddusc     * @param percent percentage of the object's diagonal length for the pinch gesture
913445e82ee022c484166ce7175973827f591ff2ea7quddusc     * @param steps the number of steps for the gesture. Steps are injected
914445e82ee022c484166ce7175973827f591ff2ea7quddusc     * about 5 milliseconds apart, so 100 steps may take around 0.5 seconds to complete.
9151078ab1070411af45d5e8ec3b56abec6789e7722Guang Zhu     * @return <code>true</code> if all touch events for this gesture are injected successfully,
916445e82ee022c484166ce7175973827f591ff2ea7quddusc     *         <code>false</code> otherwise
917c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz     * @throws UiObjectNotFoundException
918c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz     * @since API Level 18
919c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz     */
9201078ab1070411af45d5e8ec3b56abec6789e7722Guang Zhu    public boolean pinchOut(int percent, int steps) throws UiObjectNotFoundException {
921c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        // make value between 1 and 100
922c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        percent = (percent < 0) ? 1 : (percent > 100) ? 100 : percent;
923c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        float percentage = percent / 100f;
924c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz
9250d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz        AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout());
926c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        if (node == null) {
927c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz            throw new UiObjectNotFoundException(getSelector().toString());
928c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        }
929c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz
930c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        Rect rect = getVisibleBounds(node);
931c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        if (rect.width() <= FINGER_TOUCH_HALF_WIDTH * 2)
932c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz            throw new IllegalStateException("Object width is too small for operation");
933c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz
934c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        // start from the same point at the center of the control
935c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        Point startPoint1 = new Point(rect.centerX() - FINGER_TOUCH_HALF_WIDTH, rect.centerY());
936c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        Point startPoint2 = new Point(rect.centerX() + FINGER_TOUCH_HALF_WIDTH, rect.centerY());
937c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz
938c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        // End at the top-left and bottom-right corners of the control
939c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        Point endPoint1 = new Point(rect.centerX() - (int)((rect.width()/2) * percentage),
940c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz                rect.centerY());
941c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        Point endPoint2 = new Point(rect.centerX() + (int)((rect.width()/2) * percentage),
942c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz                rect.centerY());
943c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz
9441078ab1070411af45d5e8ec3b56abec6789e7722Guang Zhu        return performTwoPointerGesture(startPoint1, startPoint2, endPoint1, endPoint2, steps);
945c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz    }
946c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz
947c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz    /**
948445e82ee022c484166ce7175973827f591ff2ea7quddusc     * Performs a two-pointer gesture, where each pointer moves diagonally
949445e82ee022c484166ce7175973827f591ff2ea7quddusc     * toward the other, from the edges to the center of this UiObject .
950445e82ee022c484166ce7175973827f591ff2ea7quddusc     * @param percent percentage of the object's diagonal length for the pinch gesture
951445e82ee022c484166ce7175973827f591ff2ea7quddusc     * @param steps the number of steps for the gesture. Steps are injected
952445e82ee022c484166ce7175973827f591ff2ea7quddusc     * about 5 milliseconds apart, so 100 steps may take around 0.5 seconds to complete.
9531078ab1070411af45d5e8ec3b56abec6789e7722Guang Zhu     * @return <code>true</code> if all touch events for this gesture are injected successfully,
954445e82ee022c484166ce7175973827f591ff2ea7quddusc     *         <code>false</code> otherwise
955c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz     * @throws UiObjectNotFoundException
956c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz     * @since API Level 18
957c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz     */
9581078ab1070411af45d5e8ec3b56abec6789e7722Guang Zhu    public boolean pinchIn(int percent, int steps) throws UiObjectNotFoundException {
959c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        // make value between 1 and 100
960c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        percent = (percent < 0) ? 0 : (percent > 100) ? 100 : percent;
961c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        float percentage = percent / 100f;
962c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz
9630d3e425526a214d355e87b0c90f1b85c8aefe35aAdam Momtaz        AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout());
964c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        if (node == null) {
965c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz            throw new UiObjectNotFoundException(getSelector().toString());
966c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        }
967c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz
968c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        Rect rect = getVisibleBounds(node);
969c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        if (rect.width() <= FINGER_TOUCH_HALF_WIDTH * 2)
970c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz            throw new IllegalStateException("Object width is too small for operation");
971c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz
972c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        Point startPoint1 = new Point(rect.centerX() - (int)((rect.width()/2) * percentage),
973c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz                rect.centerY());
974c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        Point startPoint2 = new Point(rect.centerX() + (int)((rect.width()/2) * percentage),
975c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz                rect.centerY());
976c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz
977c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        Point endPoint1 = new Point(rect.centerX() - FINGER_TOUCH_HALF_WIDTH, rect.centerY());
978c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        Point endPoint2 = new Point(rect.centerX() + FINGER_TOUCH_HALF_WIDTH, rect.centerY());
979c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz
9801078ab1070411af45d5e8ec3b56abec6789e7722Guang Zhu        return performTwoPointerGesture(startPoint1, startPoint2, endPoint1, endPoint2, steps);
981c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz    }
982c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz
983c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz    /**
984445e82ee022c484166ce7175973827f591ff2ea7quddusc     * Generates a two-pointer gesture with arbitrary starting and ending points.
985c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz     *
986c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz     * @param startPoint1 start point of pointer 1
987c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz     * @param startPoint2 start point of pointer 2
988c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz     * @param endPoint1 end point of pointer 1
989c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz     * @param endPoint2 end point of pointer 2
990445e82ee022c484166ce7175973827f591ff2ea7quddusc     * @param steps the number of steps for the gesture. Steps are injected
991445e82ee022c484166ce7175973827f591ff2ea7quddusc     * about 5 milliseconds apart, so 100 steps may take around 0.5 seconds to complete.
9921078ab1070411af45d5e8ec3b56abec6789e7722Guang Zhu     * @return <code>true</code> if all touch events for this gesture are injected successfully,
993445e82ee022c484166ce7175973827f591ff2ea7quddusc     *         <code>false</code> otherwise
994c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz     * @since API Level 18
995c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz     */
9961078ab1070411af45d5e8ec3b56abec6789e7722Guang Zhu    public boolean performTwoPointerGesture(Point startPoint1, Point startPoint2, Point endPoint1,
997c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz            Point endPoint2, int steps) {
998c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz
999c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        // avoid a divide by zero
1000c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        if(steps == 0)
1001c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz            steps = 1;
1002c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz
1003c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        final float stepX1 = (endPoint1.x - startPoint1.x) / steps;
1004c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        final float stepY1 = (endPoint1.y - startPoint1.y) / steps;
1005c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        final float stepX2 = (endPoint2.x - startPoint2.x) / steps;
1006c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        final float stepY2 = (endPoint2.y - startPoint2.y) / steps;
1007c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz
1008c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        int eventX1, eventY1, eventX2, eventY2;
1009c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        eventX1 = startPoint1.x;
1010c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        eventY1 = startPoint1.y;
1011c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        eventX2 = startPoint2.x;
1012c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        eventY2 = startPoint2.y;
1013c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz
1014c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        // allocate for steps plus first down and last up
1015c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        PointerCoords[] points1 = new PointerCoords[steps + 2];
1016c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        PointerCoords[] points2 = new PointerCoords[steps + 2];
1017c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz
1018c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        // Include the first and last touch downs in the arrays of steps
1019c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        for (int i = 0; i < steps + 1; i++) {
1020c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz            PointerCoords p1 = new PointerCoords();
1021c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz            p1.x = eventX1;
1022c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz            p1.y = eventY1;
1023c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz            p1.pressure = 1;
1024c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz            p1.size = 1;
1025c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz            points1[i] = p1;
1026c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz
1027c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz            PointerCoords p2 = new PointerCoords();
1028c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz            p2.x = eventX2;
1029c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz            p2.y = eventY2;
1030c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz            p2.pressure = 1;
1031c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz            p2.size = 1;
1032c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz            points2[i] = p2;
1033c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz
1034c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz            eventX1 += stepX1;
1035c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz            eventY1 += stepY1;
1036c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz            eventX2 += stepX2;
1037c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz            eventY2 += stepY2;
1038c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        }
1039c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz
1040c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        // ending pointers coordinates
1041c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        PointerCoords p1 = new PointerCoords();
1042c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        p1.x = endPoint1.x;
1043c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        p1.y = endPoint1.y;
1044c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        p1.pressure = 1;
1045c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        p1.size = 1;
1046c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        points1[steps + 1] = p1;
1047c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz
1048c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        PointerCoords p2 = new PointerCoords();
1049c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        p2.x = endPoint2.x;
1050c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        p2.y = endPoint2.y;
1051c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        p2.pressure = 1;
1052c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        p2.size = 1;
1053c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz        points2[steps + 1] = p2;
1054c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz
10551078ab1070411af45d5e8ec3b56abec6789e7722Guang Zhu        return performMultiPointerGesture(points1, points2);
1056c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz    }
1057c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz
1058c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz    /**
1059445e82ee022c484166ce7175973827f591ff2ea7quddusc     * Performs a multi-touch gesture. You must specify touch coordinates for
1060445e82ee022c484166ce7175973827f591ff2ea7quddusc     * at least 2 pointers. Each pointer must have all of its touch steps
1061445e82ee022c484166ce7175973827f591ff2ea7quddusc     * defined in an array of {@link PointerCoords}. You can use this method to
1062445e82ee022c484166ce7175973827f591ff2ea7quddusc     * specify complex gestures, like circles and irregular shapes, where each
1063445e82ee022c484166ce7175973827f591ff2ea7quddusc     * pointer may take a different path.
1064c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz     *
1065445e82ee022c484166ce7175973827f591ff2ea7quddusc     * To create a single point on a pointer's touch path:
1066c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz     * <code>
1067c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz     *       PointerCoords p = new PointerCoords();
1068c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz     *       p.x = stepX;
1069c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz     *       p.y = stepY;
1070c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz     *       p.pressure = 1;
1071c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz     *       p.size = 1;
1072c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz     * </code>
10739ebf91aa923d2424298cb908a79dd03aefbf0a8fGuang Zhu     * @param touches represents the pointers' paths. Each {@link PointerCoords}
10749ebf91aa923d2424298cb908a79dd03aefbf0a8fGuang Zhu     * array represents a different pointer. Each {@link PointerCoords} in an
1075445e82ee022c484166ce7175973827f591ff2ea7quddusc     * array element represents a touch point on a pointer's path.
10761078ab1070411af45d5e8ec3b56abec6789e7722Guang Zhu     * @return <code>true</code> if all touch events for this gesture are injected successfully,
1077445e82ee022c484166ce7175973827f591ff2ea7quddusc     *         <code>false</code> otherwise
1078c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz     * @since API Level 18
1079c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz     */
10801078ab1070411af45d5e8ec3b56abec6789e7722Guang Zhu    public boolean performMultiPointerGesture(PointerCoords[] ...touches) {
10811078ab1070411af45d5e8ec3b56abec6789e7722Guang Zhu        return getInteractionController().performMultiPointerGesture(touches);
1082c344be11dbfd56e95d076f46b870108fdaa662f0Adam Momtaz    }
10839ebf91aa923d2424298cb908a79dd03aefbf0a8fGuang Zhu}
1084