1ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu/*
2ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu * Copyright (C) 2012 The Android Open Source Project
3ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu *
4ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu * Licensed under the Apache License, Version 2.0 (the "License");
5ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu * you may not use this file except in compliance with the License.
6ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu * You may obtain a copy of the License at
7ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu *
8ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu *      http://www.apache.org/licenses/LICENSE-2.0
9ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu *
10ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu * Unless required by applicable law or agreed to in writing, software
11ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu * distributed under the License is distributed on an "AS IS" BASIS,
12ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu * See the License for the specific language governing permissions and
14ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu * limitations under the License.
15ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu */
16ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu
17ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhupackage com.android.uiautomator.core;
18ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu
1997e4adbf51055559e5a5fa18fbb5147ea276c6c0Adam Momtazimport android.graphics.Point;
20ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhuimport android.graphics.Rect;
21ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhuimport android.os.SystemClock;
22ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhuimport android.util.Log;
23ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhuimport android.view.KeyEvent;
2497e4adbf51055559e5a5fa18fbb5147ea276c6c0Adam Momtazimport android.view.MotionEvent.PointerCoords;
25ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhuimport android.view.accessibility.AccessibilityNodeInfo;
26ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu
27ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu/**
28753092685410ea01dbb122162cd40cac48332ae1quddusc * A UiObject is a representation of a view. It is not in any way directly bound to a
29753092685410ea01dbb122162cd40cac48332ae1quddusc * view as an object reference. A UiObject contains information to help it
30753092685410ea01dbb122162cd40cac48332ae1quddusc * locate a matching view at runtime based on the {@link UiSelector} properties specified in
31753092685410ea01dbb122162cd40cac48332ae1quddusc * its constructor. Once you create an instance of a UiObject, it can
32753092685410ea01dbb122162cd40cac48332ae1quddusc * be reused for different views that match the selector criteria.
33d6b7eab5d1cf65a31aeebacc4a842e836ba5817cGuang Zhu * @since API Level 16
34ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu */
35ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhupublic class UiObject {
36ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu    private static final String LOG_TAG = UiObject.class.getSimpleName();
37d6b7eab5d1cf65a31aeebacc4a842e836ba5817cGuang Zhu    /**
38d6b7eab5d1cf65a31aeebacc4a842e836ba5817cGuang Zhu     * @since API Level 16
39bf43bba97b8009df1dc6c25d135fcfcbb9729540Adam Momtaz     * @deprecated use {@link Configurator#setWaitForSelectorTimeout(long)}
40d6b7eab5d1cf65a31aeebacc4a842e836ba5817cGuang Zhu     **/
41bf43bba97b8009df1dc6c25d135fcfcbb9729540Adam Momtaz    @Deprecated
42ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu    protected static final long WAIT_FOR_SELECTOR_TIMEOUT = 10 * 1000;
43d6b7eab5d1cf65a31aeebacc4a842e836ba5817cGuang Zhu    /**
44d6b7eab5d1cf65a31aeebacc4a842e836ba5817cGuang Zhu     * @since API Level 16
45d6b7eab5d1cf65a31aeebacc4a842e836ba5817cGuang Zhu     **/
46ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu    protected static final long WAIT_FOR_SELECTOR_POLL = 1000;
47ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu    // set a default timeout to 5.5s, since ANR threshold is 5s
48d6b7eab5d1cf65a31aeebacc4a842e836ba5817cGuang Zhu    /**
49d6b7eab5d1cf65a31aeebacc4a842e836ba5817cGuang Zhu     * @since API Level 16
50d6b7eab5d1cf65a31aeebacc4a842e836ba5817cGuang Zhu     **/
51ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu    protected static final long WAIT_FOR_WINDOW_TMEOUT = 5500;
52d6b7eab5d1cf65a31aeebacc4a842e836ba5817cGuang Zhu    /**
5397e4adbf51055559e5a5fa18fbb5147ea276c6c0Adam Momtaz     * @since API Level 16
5497e4adbf51055559e5a5fa18fbb5147ea276c6c0Adam Momtaz     **/
5597e4adbf51055559e5a5fa18fbb5147ea276c6c0Adam Momtaz    protected static final int SWIPE_MARGIN_LIMIT = 5;
5697e4adbf51055559e5a5fa18fbb5147ea276c6c0Adam Momtaz    /**
57d6b7eab5d1cf65a31aeebacc4a842e836ba5817cGuang Zhu     * @since API Level 17
58bf43bba97b8009df1dc6c25d135fcfcbb9729540Adam Momtaz     * @deprecated use {@link Configurator#setScrollAcknowledgmentTimeout(long)}
59d6b7eab5d1cf65a31aeebacc4a842e836ba5817cGuang Zhu     **/
60bf43bba97b8009df1dc6c25d135fcfcbb9729540Adam Momtaz    @Deprecated
61fa9a4a7575f0bf4a948ab169ff249f57258f35b6Adam Momtaz    protected static final long WAIT_FOR_EVENT_TMEOUT = 3 * 1000;
62d6b7eab5d1cf65a31aeebacc4a842e836ba5817cGuang Zhu    /**
6397e4adbf51055559e5a5fa18fbb5147ea276c6c0Adam Momtaz     * @since API Level 18
64d6b7eab5d1cf65a31aeebacc4a842e836ba5817cGuang Zhu     **/
6597e4adbf51055559e5a5fa18fbb5147ea276c6c0Adam Momtaz    protected static final int FINGER_TOUCH_HALF_WIDTH = 20;
66ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu
6773da7f69437c911dc60cc3b9ad7ad876677c8f14Adam Momtaz    private final UiSelector mSelector;
68ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu
69bf43bba97b8009df1dc6c25d135fcfcbb9729540Adam Momtaz    private final Configurator mConfig = Configurator.getInstance();
70bf43bba97b8009df1dc6c25d135fcfcbb9729540Adam Momtaz
71ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu    /**
72753092685410ea01dbb122162cd40cac48332ae1quddusc     * Constructs a UiObject to represent a view that matches the specified
73753092685410ea01dbb122162cd40cac48332ae1quddusc     * selector criteria.
74ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu     * @param selector
75d6b7eab5d1cf65a31aeebacc4a842e836ba5817cGuang Zhu     * @since API Level 16
76ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu     */
77dc45c6d0e77da06314f5454211d2e683a32b3b24Adam Momtaz    public UiObject(UiSelector selector) {
78ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu        mSelector = selector;
79ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu    }
80ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu
81ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu    /**
82f38e3f7321e4999bf92ddd6db5d5009f2e9801a2Adam Momtaz     * Debugging helper. A test can dump the properties of a selector as a string
83f38e3f7321e4999bf92ddd6db5d5009f2e9801a2Adam Momtaz     * to its logs if needed. <code>getSelector().toString();</code>
84f38e3f7321e4999bf92ddd6db5d5009f2e9801a2Adam Momtaz     *
85dc45c6d0e77da06314f5454211d2e683a32b3b24Adam Momtaz     * @return {@link UiSelector}
86d6b7eab5d1cf65a31aeebacc4a842e836ba5817cGuang Zhu     * @since API Level 16
87ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu     */
88dc45c6d0e77da06314f5454211d2e683a32b3b24Adam Momtaz    public final UiSelector getSelector() {
89b04f3c526835516b098227342e741b7ce944c2f3Maxim Siniavine        Tracer.trace();
90dc45c6d0e77da06314f5454211d2e683a32b3b24Adam Momtaz        return new UiSelector(mSelector);
91ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu    }
92ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu
93ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu    /**
94f38e3f7321e4999bf92ddd6db5d5009f2e9801a2Adam Momtaz     * Retrieves the {@link QueryController} to translate a {@link UiSelector} selector
95f38e3f7321e4999bf92ddd6db5d5009f2e9801a2Adam Momtaz     * into an {@link AccessibilityNodeInfo}.
96f38e3f7321e4999bf92ddd6db5d5009f2e9801a2Adam Momtaz     *
97ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu     * @return {@link QueryController}
98ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu     */
995a5e8ca8a086bd87b7753cbd3c46ff1ca72292a2Guang Zhu    QueryController getQueryController() {
10017fac436d78f6ac642386a245fb4fdb7243a91a4Guang Zhu        return UiDevice.getInstance().getAutomatorBridge().getQueryController();
101ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu    }
102ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu
103ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu    /**
104f38e3f7321e4999bf92ddd6db5d5009f2e9801a2Adam Momtaz     * Retrieves the {@link InteractionController} to perform finger actions such as tapping,
105753092685410ea01dbb122162cd40cac48332ae1quddusc     * swiping, or entering text.
106f38e3f7321e4999bf92ddd6db5d5009f2e9801a2Adam Momtaz     *
107ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu     * @return {@link InteractionController}
108ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu     */
1095a5e8ca8a086bd87b7753cbd3c46ff1ca72292a2Guang Zhu    InteractionController getInteractionController() {
11017fac436d78f6ac642386a245fb4fdb7243a91a4Guang Zhu        return UiDevice.getInstance().getAutomatorBridge().getInteractionController();
111ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu    }
112ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu
113ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu    /**
114753092685410ea01dbb122162cd40cac48332ae1quddusc     * Creates a new UiObject for a child view that is under the present UiObject.
115f38e3f7321e4999bf92ddd6db5d5009f2e9801a2Adam Momtaz     *
116753092685410ea01dbb122162cd40cac48332ae1quddusc     * @param selector for child view to match
117753092685410ea01dbb122162cd40cac48332ae1quddusc     * @return a new UiObject representing the child view
118d6b7eab5d1cf65a31aeebacc4a842e836ba5817cGuang Zhu     * @since API Level 16
119ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu     */
120dc45c6d0e77da06314f5454211d2e683a32b3b24Adam Momtaz    public UiObject getChild(UiSelector selector) throws UiObjectNotFoundException {
121b04f3c526835516b098227342e741b7ce944c2f3Maxim Siniavine        Tracer.trace(selector);
122dc45c6d0e77da06314f5454211d2e683a32b3b24Adam Momtaz        return new UiObject(getSelector().childSelector(selector));
123ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu    }
124ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu
125ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu    /**
126753092685410ea01dbb122162cd40cac48332ae1quddusc     * Creates a new UiObject for a sibling view or a child of the sibling view,
127753092685410ea01dbb122162cd40cac48332ae1quddusc     * relative to the present UiObject.
128f38e3f7321e4999bf92ddd6db5d5009f2e9801a2Adam Momtaz     *
129753092685410ea01dbb122162cd40cac48332ae1quddusc     * @param selector for a sibling view or children of the sibling view
130753092685410ea01dbb122162cd40cac48332ae1quddusc     * @return a new UiObject representing the matched view
131ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu     * @throws UiObjectNotFoundException
132d6b7eab5d1cf65a31aeebacc4a842e836ba5817cGuang Zhu     * @since API Level 16
133ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu     */
134dc45c6d0e77da06314f5454211d2e683a32b3b24Adam Momtaz    public UiObject getFromParent(UiSelector selector) throws UiObjectNotFoundException {
135b04f3c526835516b098227342e741b7ce944c2f3Maxim Siniavine        Tracer.trace(selector);
136dc45c6d0e77da06314f5454211d2e683a32b3b24Adam Momtaz        return new UiObject(getSelector().fromParent(selector));
137ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu    }
138ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu
139ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu    /**
140753092685410ea01dbb122162cd40cac48332ae1quddusc     * Counts the child views immediately under the present UiObject.
141f38e3f7321e4999bf92ddd6db5d5009f2e9801a2Adam Momtaz     *
142753092685410ea01dbb122162cd40cac48332ae1quddusc     * @return the count of child views.
143ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu     * @throws UiObjectNotFoundException
144d6b7eab5d1cf65a31aeebacc4a842e836ba5817cGuang Zhu     * @since API Level 16
145ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu     */
146ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu    public int getChildCount() throws UiObjectNotFoundException {
147b04f3c526835516b098227342e741b7ce944c2f3Maxim Siniavine        Tracer.trace();
148bf43bba97b8009df1dc6c25d135fcfcbb9729540Adam Momtaz        AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout());
149ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu        if(node == null) {
150ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu            throw new UiObjectNotFoundException(getSelector().toString());
151ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu        }
152ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu        return node.getChildCount();
153ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu    }
154ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu
155ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu    /**
156753092685410ea01dbb122162cd40cac48332ae1quddusc     * Finds a matching UI element in the accessibility hierarchy, by
157753092685410ea01dbb122162cd40cac48332ae1quddusc     * using the selector for this UiObject.
158f38e3f7321e4999bf92ddd6db5d5009f2e9801a2Adam Momtaz     *
159ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu     * @param timeout in milliseconds
160ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu     * @return AccessibilityNodeInfo if found else null
161d6b7eab5d1cf65a31aeebacc4a842e836ba5817cGuang Zhu     * @since API Level 16
162ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu     */
163ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu    protected AccessibilityNodeInfo findAccessibilityNodeInfo(long timeout) {
164ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu        AccessibilityNodeInfo node = null;
165f510bdfd84fd93b9ecf3967d37df4f402b9f1806Adam Momtaz        long startMills = SystemClock.uptimeMillis();
166f510bdfd84fd93b9ecf3967d37df4f402b9f1806Adam Momtaz        long currentMills = 0;
167f510bdfd84fd93b9ecf3967d37df4f402b9f1806Adam Momtaz        while (currentMills <= timeout) {
168ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu            node = getQueryController().findAccessibilityNodeInfo(getSelector());
169f510bdfd84fd93b9ecf3967d37df4f402b9f1806Adam Momtaz            if (node != null) {
170f510bdfd84fd93b9ecf3967d37df4f402b9f1806Adam Momtaz                break;
171f510bdfd84fd93b9ecf3967d37df4f402b9f1806Adam Momtaz            } else {
172f510bdfd84fd93b9ecf3967d37df4f402b9f1806Adam Momtaz                // does nothing if we're reentering another runWatchers()
173f510bdfd84fd93b9ecf3967d37df4f402b9f1806Adam Momtaz                UiDevice.getInstance().runWatchers();
174f510bdfd84fd93b9ecf3967d37df4f402b9f1806Adam Momtaz            }
175f510bdfd84fd93b9ecf3967d37df4f402b9f1806Adam Momtaz            currentMills = SystemClock.uptimeMillis() - startMills;
176f510bdfd84fd93b9ecf3967d37df4f402b9f1806Adam Momtaz            if(timeout > 0) {
177f510bdfd84fd93b9ecf3967d37df4f402b9f1806Adam Momtaz                SystemClock.sleep(WAIT_FOR_SELECTOR_POLL);
178ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu            }
179ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu        }
180ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu        return node;
181ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu    }
182ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu
183ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu    /**
184753092685410ea01dbb122162cd40cac48332ae1quddusc     * Drags this object to a destination UiObject.
185753092685410ea01dbb122162cd40cac48332ae1quddusc     * The number of steps specified in your input parameter can influence the
186753092685410ea01dbb122162cd40cac48332ae1quddusc     * drag speed, and varying speeds may impact the results. Consider
187753092685410ea01dbb122162cd40cac48332ae1quddusc     * evaluating different speeds when using this method in your tests.
188516cd58fd9422502e2a1e6f4c4615a32bb05606cAdam Momtaz     *
189753092685410ea01dbb122162cd40cac48332ae1quddusc     * @param destObj the destination UiObject.
190753092685410ea01dbb122162cd40cac48332ae1quddusc     * @param steps usually 40 steps. You can increase or decrease the steps to change the speed.
191753092685410ea01dbb122162cd40cac48332ae1quddusc     * @return true if successful
192516cd58fd9422502e2a1e6f4c4615a32bb05606cAdam Momtaz     * @throws UiObjectNotFoundException
193516cd58fd9422502e2a1e6f4c4615a32bb05606cAdam Momtaz     * @since API Level 18
194516cd58fd9422502e2a1e6f4c4615a32bb05606cAdam Momtaz     */
195516cd58fd9422502e2a1e6f4c4615a32bb05606cAdam Momtaz    public boolean dragTo(UiObject destObj, int steps) throws UiObjectNotFoundException {
196516cd58fd9422502e2a1e6f4c4615a32bb05606cAdam Momtaz        Rect srcRect = getVisibleBounds();
197516cd58fd9422502e2a1e6f4c4615a32bb05606cAdam Momtaz        Rect dstRect = destObj.getVisibleBounds();
198516cd58fd9422502e2a1e6f4c4615a32bb05606cAdam Momtaz        return getInteractionController().swipe(srcRect.centerX(), srcRect.centerY(),
199516cd58fd9422502e2a1e6f4c4615a32bb05606cAdam Momtaz                dstRect.centerX(), dstRect.centerY(), steps, true);
200516cd58fd9422502e2a1e6f4c4615a32bb05606cAdam Momtaz    }
201516cd58fd9422502e2a1e6f4c4615a32bb05606cAdam Momtaz
202516cd58fd9422502e2a1e6f4c4615a32bb05606cAdam Momtaz    /**
203753092685410ea01dbb122162cd40cac48332ae1quddusc     * Drags this object to arbitrary coordinates.
204753092685410ea01dbb122162cd40cac48332ae1quddusc     * The number of steps specified in your input parameter can influence the
205753092685410ea01dbb122162cd40cac48332ae1quddusc     * drag speed, and varying speeds may impact the results. Consider
206753092685410ea01dbb122162cd40cac48332ae1quddusc     * evaluating different speeds when using this method in your tests.
207516cd58fd9422502e2a1e6f4c4615a32bb05606cAdam Momtaz     *
208753092685410ea01dbb122162cd40cac48332ae1quddusc     * @param destX the X-axis coordinate.
209753092685410ea01dbb122162cd40cac48332ae1quddusc     * @param destY the Y-axis coordinate.
210753092685410ea01dbb122162cd40cac48332ae1quddusc     * @param steps usually 40 steps. You can increase or decrease the steps to change the speed.
211753092685410ea01dbb122162cd40cac48332ae1quddusc     * @return true if successful
212516cd58fd9422502e2a1e6f4c4615a32bb05606cAdam Momtaz     * @throws UiObjectNotFoundException
213516cd58fd9422502e2a1e6f4c4615a32bb05606cAdam Momtaz     * @since API Level 18
214516cd58fd9422502e2a1e6f4c4615a32bb05606cAdam Momtaz     */
215516cd58fd9422502e2a1e6f4c4615a32bb05606cAdam Momtaz    public boolean dragTo(int destX, int destY, int steps) throws UiObjectNotFoundException {
216516cd58fd9422502e2a1e6f4c4615a32bb05606cAdam Momtaz        Rect srcRect = getVisibleBounds();
217516cd58fd9422502e2a1e6f4c4615a32bb05606cAdam Momtaz        return getInteractionController().swipe(srcRect.centerX(), srcRect.centerY(), destX, destY,
218516cd58fd9422502e2a1e6f4c4615a32bb05606cAdam Momtaz                steps, true);
219516cd58fd9422502e2a1e6f4c4615a32bb05606cAdam Momtaz    }
220516cd58fd9422502e2a1e6f4c4615a32bb05606cAdam Momtaz
221516cd58fd9422502e2a1e6f4c4615a32bb05606cAdam Momtaz    /**
222753092685410ea01dbb122162cd40cac48332ae1quddusc     * Performs the swipe up action on the UiObject.
223753092685410ea01dbb122162cd40cac48332ae1quddusc     * See also:
224753092685410ea01dbb122162cd40cac48332ae1quddusc     * <ul>
225753092685410ea01dbb122162cd40cac48332ae1quddusc     * <li>{@link UiScrollable#scrollToBeginning(int)}</li>
226753092685410ea01dbb122162cd40cac48332ae1quddusc     * <li>{@link UiScrollable#scrollToEnd(int)}</li>
227753092685410ea01dbb122162cd40cac48332ae1quddusc     * <li>{@link UiScrollable#scrollBackward()}</li>
228753092685410ea01dbb122162cd40cac48332ae1quddusc     * <li>{@link UiScrollable#scrollForward()}</li>
229753092685410ea01dbb122162cd40cac48332ae1quddusc     * </ul>
230f38e3f7321e4999bf92ddd6db5d5009f2e9801a2Adam Momtaz     *
231f2030d3dd3f4968b85a3177b9cd21db831a0edafAdam Momtaz     * @param steps indicates the number of injected move steps into the system. Steps are
232f2030d3dd3f4968b85a3177b9cd21db831a0edafAdam Momtaz     * injected about 5ms apart. So a 100 steps may take about 1/2 second to complete.
233f38e3f7321e4999bf92ddd6db5d5009f2e9801a2Adam Momtaz     * @return true of successful
234ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu     * @throws UiObjectNotFoundException
235d6b7eab5d1cf65a31aeebacc4a842e836ba5817cGuang Zhu     * @since API Level 16
236ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu     */
237ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu    public boolean swipeUp(int steps) throws UiObjectNotFoundException {
238b04f3c526835516b098227342e741b7ce944c2f3Maxim Siniavine        Tracer.trace(steps);
239f38e3f7321e4999bf92ddd6db5d5009f2e9801a2Adam Momtaz        Rect rect = getVisibleBounds();
240ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu        if(rect.height() <= SWIPE_MARGIN_LIMIT * 2)
241ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu            return false; // too small to swipe
242ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu        return getInteractionController().swipe(rect.centerX(),
243ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu                rect.bottom - SWIPE_MARGIN_LIMIT, rect.centerX(), rect.top + SWIPE_MARGIN_LIMIT,
244ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu                steps);
245ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu    }
246ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu
247ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu    /**
248753092685410ea01dbb122162cd40cac48332ae1quddusc     * Performs the swipe down action on the UiObject.
249753092685410ea01dbb122162cd40cac48332ae1quddusc     * The swipe gesture can be performed over any surface. The targeted
250753092685410ea01dbb122162cd40cac48332ae1quddusc     * UI element does not need to be scrollable.
251753092685410ea01dbb122162cd40cac48332ae1quddusc     * See also:
252753092685410ea01dbb122162cd40cac48332ae1quddusc     * <ul>
253753092685410ea01dbb122162cd40cac48332ae1quddusc     * <li>{@link UiScrollable#scrollToBeginning(int)}</li>
254753092685410ea01dbb122162cd40cac48332ae1quddusc     * <li>{@link UiScrollable#scrollToEnd(int)}</li>
255753092685410ea01dbb122162cd40cac48332ae1quddusc     * <li>{@link UiScrollable#scrollBackward()}</li>
256753092685410ea01dbb122162cd40cac48332ae1quddusc     * <li>{@link UiScrollable#scrollForward()}</li>
257753092685410ea01dbb122162cd40cac48332ae1quddusc     * </ul>
258f38e3f7321e4999bf92ddd6db5d5009f2e9801a2Adam Momtaz     *
259f38e3f7321e4999bf92ddd6db5d5009f2e9801a2Adam Momtaz     * @param steps indicates the number of injected move steps into the system. Steps are
260f2030d3dd3f4968b85a3177b9cd21db831a0edafAdam Momtaz     * injected about 5ms apart. So a 100 steps may take about 1/2 second to complete.
261f38e3f7321e4999bf92ddd6db5d5009f2e9801a2Adam Momtaz     * @return true if successful
262ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu     * @throws UiObjectNotFoundException
263d6b7eab5d1cf65a31aeebacc4a842e836ba5817cGuang Zhu     * @since API Level 16
264ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu     */
265ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu    public boolean swipeDown(int steps) throws UiObjectNotFoundException {
266b04f3c526835516b098227342e741b7ce944c2f3Maxim Siniavine        Tracer.trace(steps);
267f38e3f7321e4999bf92ddd6db5d5009f2e9801a2Adam Momtaz        Rect rect = getVisibleBounds();
268ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu        if(rect.height() <= SWIPE_MARGIN_LIMIT * 2)
269ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu            return false; // too small to swipe
270ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu        return getInteractionController().swipe(rect.centerX(),
271ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu                rect.top + SWIPE_MARGIN_LIMIT, rect.centerX(),
272ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu                rect.bottom - SWIPE_MARGIN_LIMIT, steps);
273ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu    }
274ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu
275ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu    /**
276753092685410ea01dbb122162cd40cac48332ae1quddusc     * Performs the swipe left action on the UiObject.
277753092685410ea01dbb122162cd40cac48332ae1quddusc     * The swipe gesture can be performed over any surface. The targeted
278753092685410ea01dbb122162cd40cac48332ae1quddusc     * UI element does not need to be scrollable.
279753092685410ea01dbb122162cd40cac48332ae1quddusc     * See also:
280753092685410ea01dbb122162cd40cac48332ae1quddusc     * <ul>
281753092685410ea01dbb122162cd40cac48332ae1quddusc     * <li>{@link UiScrollable#scrollToBeginning(int)}</li>
282753092685410ea01dbb122162cd40cac48332ae1quddusc     * <li>{@link UiScrollable#scrollToEnd(int)}</li>
283753092685410ea01dbb122162cd40cac48332ae1quddusc     * <li>{@link UiScrollable#scrollBackward()}</li>
284753092685410ea01dbb122162cd40cac48332ae1quddusc     * <li>{@link UiScrollable#scrollForward()}</li>
285753092685410ea01dbb122162cd40cac48332ae1quddusc     * </ul>
286f38e3f7321e4999bf92ddd6db5d5009f2e9801a2Adam Momtaz     *
287f38e3f7321e4999bf92ddd6db5d5009f2e9801a2Adam Momtaz     * @param steps indicates the number of injected move steps into the system. Steps are
288f2030d3dd3f4968b85a3177b9cd21db831a0edafAdam Momtaz     * injected about 5ms apart. So a 100 steps may take about 1/2 second to complete.
289f38e3f7321e4999bf92ddd6db5d5009f2e9801a2Adam Momtaz     * @return true if successful
290ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu     * @throws UiObjectNotFoundException
291d6b7eab5d1cf65a31aeebacc4a842e836ba5817cGuang Zhu     * @since API Level 16
292ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu     */
293ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu    public boolean swipeLeft(int steps) throws UiObjectNotFoundException {
294b04f3c526835516b098227342e741b7ce944c2f3Maxim Siniavine        Tracer.trace(steps);
295f38e3f7321e4999bf92ddd6db5d5009f2e9801a2Adam Momtaz        Rect rect = getVisibleBounds();
296ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu        if(rect.width() <= SWIPE_MARGIN_LIMIT * 2)
297ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu            return false; // too small to swipe
298ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu        return getInteractionController().swipe(rect.right - SWIPE_MARGIN_LIMIT,
299ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu                rect.centerY(), rect.left + SWIPE_MARGIN_LIMIT, rect.centerY(), steps);
300ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu    }
301ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu
302ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu    /**
303753092685410ea01dbb122162cd40cac48332ae1quddusc     * Performs the swipe right action on the UiObject.
304753092685410ea01dbb122162cd40cac48332ae1quddusc     * The swipe gesture can be performed over any surface. The targeted
305753092685410ea01dbb122162cd40cac48332ae1quddusc     * UI element does not need to be scrollable.
306753092685410ea01dbb122162cd40cac48332ae1quddusc     * See also:
307753092685410ea01dbb122162cd40cac48332ae1quddusc     * <ul>
308753092685410ea01dbb122162cd40cac48332ae1quddusc     * <li>{@link UiScrollable#scrollToBeginning(int)}</li>
309753092685410ea01dbb122162cd40cac48332ae1quddusc     * <li>{@link UiScrollable#scrollToEnd(int)}</li>
310753092685410ea01dbb122162cd40cac48332ae1quddusc     * <li>{@link UiScrollable#scrollBackward()}</li>
311753092685410ea01dbb122162cd40cac48332ae1quddusc     * <li>{@link UiScrollable#scrollForward()}</li>
312753092685410ea01dbb122162cd40cac48332ae1quddusc     * </ul>
313f38e3f7321e4999bf92ddd6db5d5009f2e9801a2Adam Momtaz     *
314f38e3f7321e4999bf92ddd6db5d5009f2e9801a2Adam Momtaz     * @param steps indicates the number of injected move steps into the system. Steps are
315f2030d3dd3f4968b85a3177b9cd21db831a0edafAdam Momtaz     * injected about 5ms apart. So a 100 steps may take about 1/2 second to complete.
316f38e3f7321e4999bf92ddd6db5d5009f2e9801a2Adam Momtaz     * @return true if successful
317ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu     * @throws UiObjectNotFoundException
318d6b7eab5d1cf65a31aeebacc4a842e836ba5817cGuang Zhu     * @since API Level 16
319ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu     */
320ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu    public boolean swipeRight(int steps) throws UiObjectNotFoundException {
321b04f3c526835516b098227342e741b7ce944c2f3Maxim Siniavine        Tracer.trace(steps);
322f38e3f7321e4999bf92ddd6db5d5009f2e9801a2Adam Momtaz        Rect rect = getVisibleBounds();
323ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu        if(rect.width() <= SWIPE_MARGIN_LIMIT * 2)
324ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu            return false; // too small to swipe
325ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu        return getInteractionController().swipe(rect.left + SWIPE_MARGIN_LIMIT,
326ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu                rect.centerY(), rect.right - SWIPE_MARGIN_LIMIT, rect.centerY(), steps);
327ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu    }
328ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu
329ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu    /**
330f38e3f7321e4999bf92ddd6db5d5009f2e9801a2Adam Momtaz     * Finds the visible bounds of a partially visible UI element
331f38e3f7321e4999bf92ddd6db5d5009f2e9801a2Adam Momtaz     *
332ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu     * @param node
33373da7f69437c911dc60cc3b9ad7ad876677c8f14Adam Momtaz     * @return null if node is null, else a Rect containing visible bounds
334ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu     */
335ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu    private Rect getVisibleBounds(AccessibilityNodeInfo node) {
336ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu        if (node == null) {
337ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu            return null;
338ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu        }
339ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu
340ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu        // targeted node's bounds
34147d54d40309083809bf04ba07a5b7191fbca9351Guang Zhu        int w = UiDevice.getInstance().getDisplayWidth();
34247d54d40309083809bf04ba07a5b7191fbca9351Guang Zhu        int h = UiDevice.getInstance().getDisplayHeight();
34347d54d40309083809bf04ba07a5b7191fbca9351Guang Zhu        Rect nodeRect = AccessibilityNodeInfoHelper.getVisibleBoundsInScreen(node, w, h);
344ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu
345ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu        // is the targeted node within a scrollable container?
346ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu        AccessibilityNodeInfo scrollableParentNode = getScrollableParent(node);
347ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu        if(scrollableParentNode == null) {
348ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu            // nothing to adjust for so return the node's Rect as is
349ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu            return nodeRect;
350ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu        }
351ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu
352ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu        // Scrollable parent's visible bounds
35373da7f69437c911dc60cc3b9ad7ad876677c8f14Adam Momtaz        Rect parentRect = AccessibilityNodeInfoHelper
35447d54d40309083809bf04ba07a5b7191fbca9351Guang Zhu                .getVisibleBoundsInScreen(scrollableParentNode, w, h);
355ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu        // adjust for partial clipping of targeted by parent node if required
356ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu        nodeRect.intersect(parentRect);
357ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu        return nodeRect;
358ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu    }
359ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu
360ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu    /**
361753092685410ea01dbb122162cd40cac48332ae1quddusc     * Walks up the layout hierarchy to find a scrollable parent. A scrollable parent
362753092685410ea01dbb122162cd40cac48332ae1quddusc     * indicates that this node might be in a container where it is partially
363753092685410ea01dbb122162cd40cac48332ae1quddusc     * visible due to scrolling. In this case, its clickable center might not be visible and
364753092685410ea01dbb122162cd40cac48332ae1quddusc     * the click coordinates should be adjusted.
365f38e3f7321e4999bf92ddd6db5d5009f2e9801a2Adam Momtaz     *
366ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu     * @param node
3675478840ad89ace2474b9b4d3ab14b92d9e06bf47Thanh Le     * @return The accessibility node info.
368ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu     */
369ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu    private AccessibilityNodeInfo getScrollableParent(AccessibilityNodeInfo node) {
370ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu        AccessibilityNodeInfo parent = node;
371ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu        while(parent != null) {
372ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu            parent = parent.getParent();
373ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu            if (parent != null && parent.isScrollable()) {
374ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu                return parent;
375ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu            }
376ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu        }
377ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu        return null;
378ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu    }
379ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu
380ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu    /**
381f38e3f7321e4999bf92ddd6db5d5009f2e9801a2Adam Momtaz     * Performs a click at the center of the visible bounds of the UI element represented
382fbcc9c7c6df14a11e92f5c2553069e3333710896Adam Momtaz     * by this UiObject.
383f38e3f7321e4999bf92ddd6db5d5009f2e9801a2Adam Momtaz     *
384ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu     * @return true id successful else false
385ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu     * @throws UiObjectNotFoundException
386d6b7eab5d1cf65a31aeebacc4a842e836ba5817cGuang Zhu     * @since API Level 16
387ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu     */
388ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu    public boolean click() throws UiObjectNotFoundException {
389b04f3c526835516b098227342e741b7ce944c2f3Maxim Siniavine        Tracer.trace();
390bf43bba97b8009df1dc6c25d135fcfcbb9729540Adam Momtaz        AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout());
391ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu        if(node == null) {
392ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu            throw new UiObjectNotFoundException(getSelector().toString());
393ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu        }
394ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu        Rect rect = getVisibleBounds(node);
395bf43bba97b8009df1dc6c25d135fcfcbb9729540Adam Momtaz        return getInteractionController().clickAndSync(rect.centerX(), rect.centerY(),
396bf43bba97b8009df1dc6c25d135fcfcbb9729540Adam Momtaz                mConfig.getActionAcknowledgmentTimeout());
397ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu    }
398ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu
399ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu    /**
400753092685410ea01dbb122162cd40cac48332ae1quddusc     * Waits for window transitions that would typically take longer than the
401753092685410ea01dbb122162cd40cac48332ae1quddusc     * usual default timeouts.
402f38e3f7321e4999bf92ddd6db5d5009f2e9801a2Adam Momtaz     * See {@link #clickAndWaitForNewWindow(long)}
403f38e3f7321e4999bf92ddd6db5d5009f2e9801a2Adam Momtaz     *
404f38e3f7321e4999bf92ddd6db5d5009f2e9801a2Adam Momtaz     * @return true if the event was triggered, else false
405f38e3f7321e4999bf92ddd6db5d5009f2e9801a2Adam Momtaz     * @throws UiObjectNotFoundException
406d6b7eab5d1cf65a31aeebacc4a842e836ba5817cGuang Zhu     * @since API Level 16
407f38e3f7321e4999bf92ddd6db5d5009f2e9801a2Adam Momtaz     */
408ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu    public boolean clickAndWaitForNewWindow() throws UiObjectNotFoundException {
409b04f3c526835516b098227342e741b7ce944c2f3Maxim Siniavine        Tracer.trace();
410ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu        return clickAndWaitForNewWindow(WAIT_FOR_WINDOW_TMEOUT);
411ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu    }
412ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu
413ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu    /**
414fbcc9c7c6df14a11e92f5c2553069e3333710896Adam Momtaz     * Performs a click at the center of the visible bounds of the UI element represented
415fbcc9c7c6df14a11e92f5c2553069e3333710896Adam Momtaz     * by this UiObject and waits for window transitions.
416fbcc9c7c6df14a11e92f5c2553069e3333710896Adam Momtaz     *
417f38e3f7321e4999bf92ddd6db5d5009f2e9801a2Adam Momtaz     * This method differ from {@link UiObject#click()} only in that this method waits for a
418fbcc9c7c6df14a11e92f5c2553069e3333710896Adam Momtaz     * a new window transition as a result of the click. Some examples of a window transition:
419ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu     * <li>launching a new activity</li>
420ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu     * <li>bringing up a pop-up menu</li>
421ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu     * <li>bringing up a dialog</li>
422ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu     *
423f38e3f7321e4999bf92ddd6db5d5009f2e9801a2Adam Momtaz     * @param timeout timeout before giving up on waiting for a new window
424ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu     * @return true if the event was triggered, else false
425ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu     * @throws UiObjectNotFoundException
426d6b7eab5d1cf65a31aeebacc4a842e836ba5817cGuang Zhu     * @since API Level 16
427ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu     */
428ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu    public boolean clickAndWaitForNewWindow(long timeout) throws UiObjectNotFoundException {
429b04f3c526835516b098227342e741b7ce944c2f3Maxim Siniavine        Tracer.trace(timeout);
430bf43bba97b8009df1dc6c25d135fcfcbb9729540Adam Momtaz        AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout());
431ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu        if(node == null) {
432ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu            throw new UiObjectNotFoundException(getSelector().toString());
433ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu        }
434ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu        Rect rect = getVisibleBounds(node);
435bf43bba97b8009df1dc6c25d135fcfcbb9729540Adam Momtaz        return getInteractionController().clickAndWaitForNewWindow(rect.centerX(), rect.centerY(),
436bf43bba97b8009df1dc6c25d135fcfcbb9729540Adam Momtaz                mConfig.getActionAcknowledgmentTimeout());
437ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu    }
438ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu
439ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu    /**
440f38e3f7321e4999bf92ddd6db5d5009f2e9801a2Adam Momtaz     * Clicks the top and left corner of the UI element
441f38e3f7321e4999bf92ddd6db5d5009f2e9801a2Adam Momtaz     *
442ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu     * @return true on success
4435478840ad89ace2474b9b4d3ab14b92d9e06bf47Thanh Le     * @throws UiObjectNotFoundException
444d6b7eab5d1cf65a31aeebacc4a842e836ba5817cGuang Zhu     * @since API Level 16
445ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu     */
446ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu    public boolean clickTopLeft() throws UiObjectNotFoundException {
447b04f3c526835516b098227342e741b7ce944c2f3Maxim Siniavine        Tracer.trace();
448bf43bba97b8009df1dc6c25d135fcfcbb9729540Adam Momtaz        AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout());
449ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu        if(node == null) {
450ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu            throw new UiObjectNotFoundException(getSelector().toString());
451ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu        }
452ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu        Rect rect = getVisibleBounds(node);
4533949d2773cc87adf0554940f69d1529434949ca2Adam Momtaz        return getInteractionController().clickNoSync(rect.left + 5, rect.top + 5);
454ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu    }
455ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu
456ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu    /**
457f38e3f7321e4999bf92ddd6db5d5009f2e9801a2Adam Momtaz     * Long clicks bottom and right corner of the UI element
458f38e3f7321e4999bf92ddd6db5d5009f2e9801a2Adam Momtaz     *
459ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu     * @return true if operation was successful
460ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu     * @throws UiObjectNotFoundException
461d6b7eab5d1cf65a31aeebacc4a842e836ba5817cGuang Zhu     * @since API Level 16
462ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu     */
463ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu    public boolean longClickBottomRight() throws UiObjectNotFoundException  {
464b04f3c526835516b098227342e741b7ce944c2f3Maxim Siniavine        Tracer.trace();
465bf43bba97b8009df1dc6c25d135fcfcbb9729540Adam Momtaz        AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout());
466ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu        if(node == null) {
467ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu            throw new UiObjectNotFoundException(getSelector().toString());
468ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu        }
469ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu        Rect rect = getVisibleBounds(node);
4703949d2773cc87adf0554940f69d1529434949ca2Adam Momtaz        return getInteractionController().longTapNoSync(rect.right - 5, rect.bottom - 5);
471ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu    }
472ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu
473ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu    /**
474f38e3f7321e4999bf92ddd6db5d5009f2e9801a2Adam Momtaz     * Clicks the bottom and right corner of the UI element
475f38e3f7321e4999bf92ddd6db5d5009f2e9801a2Adam Momtaz     *
476ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu     * @return true on success
4775478840ad89ace2474b9b4d3ab14b92d9e06bf47Thanh Le     * @throws UiObjectNotFoundException
478d6b7eab5d1cf65a31aeebacc4a842e836ba5817cGuang Zhu     * @since API Level 16
479ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu     */
480ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu    public boolean clickBottomRight() throws UiObjectNotFoundException {
481b04f3c526835516b098227342e741b7ce944c2f3Maxim Siniavine        Tracer.trace();
482bf43bba97b8009df1dc6c25d135fcfcbb9729540Adam Momtaz        AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout());
483ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu        if(node == null) {
484ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu            throw new UiObjectNotFoundException(getSelector().toString());
485ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu        }
486ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu        Rect rect = getVisibleBounds(node);
4873949d2773cc87adf0554940f69d1529434949ca2Adam Momtaz        return getInteractionController().clickNoSync(rect.right - 5, rect.bottom - 5);
488ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu    }
489ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu
490ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu    /**
491f38e3f7321e4999bf92ddd6db5d5009f2e9801a2Adam Momtaz     * Long clicks the center of the visible bounds of the UI element
492f38e3f7321e4999bf92ddd6db5d5009f2e9801a2Adam Momtaz     *
493ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu     * @return true if operation was successful
494ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu     * @throws UiObjectNotFoundException
495d6b7eab5d1cf65a31aeebacc4a842e836ba5817cGuang Zhu     * @since API Level 16
496ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu     */
497ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu    public boolean longClick() throws UiObjectNotFoundException  {
498b04f3c526835516b098227342e741b7ce944c2f3Maxim Siniavine        Tracer.trace();
499bf43bba97b8009df1dc6c25d135fcfcbb9729540Adam Momtaz        AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout());
500ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu        if(node == null) {
501ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu            throw new UiObjectNotFoundException(getSelector().toString());
502ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu        }
503ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu        Rect rect = getVisibleBounds(node);
5043949d2773cc87adf0554940f69d1529434949ca2Adam Momtaz        return getInteractionController().longTapNoSync(rect.centerX(), rect.centerY());
505ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu    }
506ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu
507ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu    /**
508f38e3f7321e4999bf92ddd6db5d5009f2e9801a2Adam Momtaz     * Long clicks on the top and left corner of the UI element
509f38e3f7321e4999bf92ddd6db5d5009f2e9801a2Adam Momtaz     *
510ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu     * @return true if operation was successful
511ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu     * @throws UiObjectNotFoundException
512d6b7eab5d1cf65a31aeebacc4a842e836ba5817cGuang Zhu     * @since API Level 16
513ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu     */
514ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu    public boolean longClickTopLeft() throws UiObjectNotFoundException {
515b04f3c526835516b098227342e741b7ce944c2f3Maxim Siniavine        Tracer.trace();
516bf43bba97b8009df1dc6c25d135fcfcbb9729540Adam Momtaz        AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout());
517ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu        if(node == null) {
518ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu            throw new UiObjectNotFoundException(getSelector().toString());
519ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu        }
520ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu        Rect rect = getVisibleBounds(node);
5213949d2773cc87adf0554940f69d1529434949ca2Adam Momtaz        return getInteractionController().longTapNoSync(rect.left + 5, rect.top + 5);
522ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu    }
523ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu
524ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu    /**
525f38e3f7321e4999bf92ddd6db5d5009f2e9801a2Adam Momtaz     * Reads the <code>text</code> property of the UI element
526f38e3f7321e4999bf92ddd6db5d5009f2e9801a2Adam Momtaz     *
527ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu     * @return text value of the current node represented by this UiObject
528ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu     * @throws UiObjectNotFoundException if no match could be found
529d6b7eab5d1cf65a31aeebacc4a842e836ba5817cGuang Zhu     * @since API Level 16
530ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu     */
531ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu    public String getText() throws UiObjectNotFoundException {
532b04f3c526835516b098227342e741b7ce944c2f3Maxim Siniavine        Tracer.trace();
533bf43bba97b8009df1dc6c25d135fcfcbb9729540Adam Momtaz        AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout());
534ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu        if(node == null) {
535ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu            throw new UiObjectNotFoundException(getSelector().toString());
536ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu        }
537ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu        String retVal = safeStringReturn(node.getText());
538ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu        Log.d(LOG_TAG, String.format("getText() = %s", retVal));
539ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu        return retVal;
540ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu    }
541ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu
542ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu    /**
543753092685410ea01dbb122162cd40cac48332ae1quddusc     * Retrieves the <code>className</code> property of the UI element.
54492aa0ff3a891d5ca4b37d1ad091b0e207d6e3041Adam Momtaz     *
54592aa0ff3a891d5ca4b37d1ad091b0e207d6e3041Adam Momtaz     * @return class name of the current node represented by this UiObject
546753092685410ea01dbb122162cd40cac48332ae1quddusc     * @throws UiObjectNotFoundException if no match was found
54792aa0ff3a891d5ca4b37d1ad091b0e207d6e3041Adam Momtaz     * @since API Level 18
54892aa0ff3a891d5ca4b37d1ad091b0e207d6e3041Adam Momtaz     */
54992aa0ff3a891d5ca4b37d1ad091b0e207d6e3041Adam Momtaz    public String getClassName() throws UiObjectNotFoundException {
55092aa0ff3a891d5ca4b37d1ad091b0e207d6e3041Adam Momtaz        Tracer.trace();
551bf43bba97b8009df1dc6c25d135fcfcbb9729540Adam Momtaz        AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout());
55292aa0ff3a891d5ca4b37d1ad091b0e207d6e3041Adam Momtaz        if(node == null) {
55392aa0ff3a891d5ca4b37d1ad091b0e207d6e3041Adam Momtaz            throw new UiObjectNotFoundException(getSelector().toString());
55492aa0ff3a891d5ca4b37d1ad091b0e207d6e3041Adam Momtaz        }
55592aa0ff3a891d5ca4b37d1ad091b0e207d6e3041Adam Momtaz        String retVal = safeStringReturn(node.getClassName());
55692aa0ff3a891d5ca4b37d1ad091b0e207d6e3041Adam Momtaz        Log.d(LOG_TAG, String.format("getClassName() = %s", retVal));
55792aa0ff3a891d5ca4b37d1ad091b0e207d6e3041Adam Momtaz        return retVal;
55892aa0ff3a891d5ca4b37d1ad091b0e207d6e3041Adam Momtaz    }
55992aa0ff3a891d5ca4b37d1ad091b0e207d6e3041Adam Momtaz
56092aa0ff3a891d5ca4b37d1ad091b0e207d6e3041Adam Momtaz    /**
561f38e3f7321e4999bf92ddd6db5d5009f2e9801a2Adam Momtaz     * Reads the <code>content_desc</code> property of the UI element
562f38e3f7321e4999bf92ddd6db5d5009f2e9801a2Adam Momtaz     *
563ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu     * @return value of node attribute "content_desc"
564ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu     * @throws UiObjectNotFoundException
565d6b7eab5d1cf65a31aeebacc4a842e836ba5817cGuang Zhu     * @since API Level 16
566ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu     */
567ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu    public String getContentDescription() throws UiObjectNotFoundException {
568b04f3c526835516b098227342e741b7ce944c2f3Maxim Siniavine        Tracer.trace();
569bf43bba97b8009df1dc6c25d135fcfcbb9729540Adam Momtaz        AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout());
570ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu        if(node == null) {
571ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu            throw new UiObjectNotFoundException(getSelector().toString());
572ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu        }
573ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu        return safeStringReturn(node.getContentDescription());
574ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu    }
575ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu
576ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu    /**
577fbcc9c7c6df14a11e92f5c2553069e3333710896Adam Momtaz     * Sets the text in an editable field, after clearing the field's content.
578fbcc9c7c6df14a11e92f5c2553069e3333710896Adam Momtaz     *
579fbcc9c7c6df14a11e92f5c2553069e3333710896Adam Momtaz     * The {@link UiSelector} selector of this object must reference a UI element that is editable.
580fbcc9c7c6df14a11e92f5c2553069e3333710896Adam Momtaz     *
581fbcc9c7c6df14a11e92f5c2553069e3333710896Adam Momtaz     * When you call this method, the method first simulates a {@link #click()} on
582fbcc9c7c6df14a11e92f5c2553069e3333710896Adam Momtaz     * editable field to set focus. The method then clears the field's contents
583fbcc9c7c6df14a11e92f5c2553069e3333710896Adam Momtaz     * and injects your specified text into the field.
584f38e3f7321e4999bf92ddd6db5d5009f2e9801a2Adam Momtaz     *
585fbcc9c7c6df14a11e92f5c2553069e3333710896Adam Momtaz     * If you want to capture the original contents of the field, call {@link #getText()} first.
586fbcc9c7c6df14a11e92f5c2553069e3333710896Adam Momtaz     * You can then modify the text and use this method to update the field.
587fbcc9c7c6df14a11e92f5c2553069e3333710896Adam Momtaz     *
588fbcc9c7c6df14a11e92f5c2553069e3333710896Adam Momtaz     * @param text string to set
589ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu     * @return true if operation is successful
590ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu     * @throws UiObjectNotFoundException
591d6b7eab5d1cf65a31aeebacc4a842e836ba5817cGuang Zhu     * @since API Level 16
592ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu     */
593ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu    public boolean setText(String text) throws UiObjectNotFoundException {
594b04f3c526835516b098227342e741b7ce944c2f3Maxim Siniavine        Tracer.trace(text);
595ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu        clearTextField();
596ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu        return getInteractionController().sendText(text);
597ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu    }
598ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu
599ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu    /**
600fbcc9c7c6df14a11e92f5c2553069e3333710896Adam Momtaz     * Clears the existing text contents in an editable field.
601fbcc9c7c6df14a11e92f5c2553069e3333710896Adam Momtaz     *
602fbcc9c7c6df14a11e92f5c2553069e3333710896Adam Momtaz     * The {@link UiSelector} of this object must reference a UI element that is editable.
603fbcc9c7c6df14a11e92f5c2553069e3333710896Adam Momtaz     *
604fbcc9c7c6df14a11e92f5c2553069e3333710896Adam Momtaz     * When you call this method, the method first sets focus at the start edge of the field.
605fbcc9c7c6df14a11e92f5c2553069e3333710896Adam Momtaz     * The method then simulates a long-press to select the existing text, and deletes the
606fbcc9c7c6df14a11e92f5c2553069e3333710896Adam Momtaz     * selected text.
607fbcc9c7c6df14a11e92f5c2553069e3333710896Adam Momtaz     *
608fbcc9c7c6df14a11e92f5c2553069e3333710896Adam Momtaz     * If a "Select-All" option is displayed, the method will automatically attempt to use it
609fbcc9c7c6df14a11e92f5c2553069e3333710896Adam Momtaz     * to ensure full text selection.
610fbcc9c7c6df14a11e92f5c2553069e3333710896Adam Momtaz     *
611fbcc9c7c6df14a11e92f5c2553069e3333710896Adam Momtaz     * Note that it is possible that not all the text in the field is selected; for example,
612fbcc9c7c6df14a11e92f5c2553069e3333710896Adam Momtaz     * if the text contains separators such as spaces, slashes, at symbol etc.
613fbcc9c7c6df14a11e92f5c2553069e3333710896Adam Momtaz     * Also, not all editable fields support the long-press functionality.
614fbcc9c7c6df14a11e92f5c2553069e3333710896Adam Momtaz     *
615ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu     * @throws UiObjectNotFoundException
616d6b7eab5d1cf65a31aeebacc4a842e836ba5817cGuang Zhu     * @since API Level 16
617ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu     */
618ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu    public void clearTextField() throws UiObjectNotFoundException {
619b04f3c526835516b098227342e741b7ce944c2f3Maxim Siniavine        Tracer.trace();
620ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu        // long click left + center
621bf43bba97b8009df1dc6c25d135fcfcbb9729540Adam Momtaz        AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout());
622ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu        if(node == null) {
623ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu            throw new UiObjectNotFoundException(getSelector().toString());
624ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu        }
625ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu        Rect rect = getVisibleBounds(node);
6263949d2773cc87adf0554940f69d1529434949ca2Adam Momtaz        getInteractionController().longTapNoSync(rect.left + 20, rect.centerY());
627ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu        // check if the edit menu is open
628dc45c6d0e77da06314f5454211d2e683a32b3b24Adam Momtaz        UiObject selectAll = new UiObject(new UiSelector().descriptionContains("Select all"));
629ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu        if(selectAll.waitForExists(50))
630ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu            selectAll.click();
631ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu        // wait for the selection
632ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu        SystemClock.sleep(250);
633ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu        // delete it
634ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu        getInteractionController().sendKey(KeyEvent.KEYCODE_DEL, 0);
635ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu    }
636ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu
637ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu    /**
638f38e3f7321e4999bf92ddd6db5d5009f2e9801a2Adam Momtaz     * Check if the UI element's <code>checked</code> property is currently true
639f38e3f7321e4999bf92ddd6db5d5009f2e9801a2Adam Momtaz     *
640ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu     * @return true if it is else false
641d6b7eab5d1cf65a31aeebacc4a842e836ba5817cGuang Zhu     * @since API Level 16
642ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu     */
643ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu    public boolean isChecked() throws UiObjectNotFoundException {
644b04f3c526835516b098227342e741b7ce944c2f3Maxim Siniavine        Tracer.trace();
645bf43bba97b8009df1dc6c25d135fcfcbb9729540Adam Momtaz        AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout());
646ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu        if(node == null) {
647ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu            throw new UiObjectNotFoundException(getSelector().toString());
648ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu        }
649ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu        return node.isChecked();
650ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu    }
651ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu
652ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu    /**
653753092685410ea01dbb122162cd40cac48332ae1quddusc     * Checks if the UI element's <code>selected</code> property is currently true.
654f38e3f7321e4999bf92ddd6db5d5009f2e9801a2Adam Momtaz     *
655ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu     * @return true if it is else false
656ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu     * @throws UiObjectNotFoundException
657d6b7eab5d1cf65a31aeebacc4a842e836ba5817cGuang Zhu     * @since API Level 16
658ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu     */
659ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu    public boolean isSelected() throws UiObjectNotFoundException {
660b04f3c526835516b098227342e741b7ce944c2f3Maxim Siniavine        Tracer.trace();
661bf43bba97b8009df1dc6c25d135fcfcbb9729540Adam Momtaz        AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout());
662ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu        if(node == null) {
663ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu            throw new UiObjectNotFoundException(getSelector().toString());
664ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu        }
665ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu        return node.isSelected();
666ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu    }
667ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu
668ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu    /**
669753092685410ea01dbb122162cd40cac48332ae1quddusc     * Checks if the UI element's <code>checkable</code> property is currently true.
670f38e3f7321e4999bf92ddd6db5d5009f2e9801a2Adam Momtaz     *
671ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu     * @return true if it is else false
672ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu     * @throws UiObjectNotFoundException
673d6b7eab5d1cf65a31aeebacc4a842e836ba5817cGuang Zhu     * @since API Level 16
674ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu     */
675ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu    public boolean isCheckable() throws UiObjectNotFoundException {
676b04f3c526835516b098227342e741b7ce944c2f3Maxim Siniavine        Tracer.trace();
677bf43bba97b8009df1dc6c25d135fcfcbb9729540Adam Momtaz        AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout());
678ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu        if(node == null) {
679ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu            throw new UiObjectNotFoundException(getSelector().toString());
680ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu        }
681ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu        return node.isCheckable();
682ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu    }
683ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu
684ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu    /**
685753092685410ea01dbb122162cd40cac48332ae1quddusc     * Checks if the UI element's <code>enabled</code> property is currently true.
686f38e3f7321e4999bf92ddd6db5d5009f2e9801a2Adam Momtaz     *
687ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu     * @return true if it is else false
688ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu     * @throws UiObjectNotFoundException
689d6b7eab5d1cf65a31aeebacc4a842e836ba5817cGuang Zhu     * @since API Level 16
690ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu     */
691ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu    public boolean isEnabled() throws UiObjectNotFoundException {
692b04f3c526835516b098227342e741b7ce944c2f3Maxim Siniavine        Tracer.trace();
693bf43bba97b8009df1dc6c25d135fcfcbb9729540Adam Momtaz        AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout());
694ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu        if(node == null) {
695ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu            throw new UiObjectNotFoundException(getSelector().toString());
696ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu        }
697ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu        return node.isEnabled();
698ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu    }
699ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu
700ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu    /**
701753092685410ea01dbb122162cd40cac48332ae1quddusc     * Checks if the UI element's <code>clickable</code> property is currently true.
702f38e3f7321e4999bf92ddd6db5d5009f2e9801a2Adam Momtaz     *
703ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu     * @return true if it is else false
704ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu     * @throws UiObjectNotFoundException
705d6b7eab5d1cf65a31aeebacc4a842e836ba5817cGuang Zhu     * @since API Level 16
706ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu     */
707ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu    public boolean isClickable() throws UiObjectNotFoundException {
708b04f3c526835516b098227342e741b7ce944c2f3Maxim Siniavine        Tracer.trace();
709bf43bba97b8009df1dc6c25d135fcfcbb9729540Adam Momtaz        AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout());
710ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu        if(node == null) {
711ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu            throw new UiObjectNotFoundException(getSelector().toString());
712ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu        }
713ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu        return node.isClickable();
714ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu    }
715ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu
716ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu    /**
717f38e3f7321e4999bf92ddd6db5d5009f2e9801a2Adam Momtaz     * Check if the UI element's <code>focused</code> property is currently true
718f38e3f7321e4999bf92ddd6db5d5009f2e9801a2Adam Momtaz     *
719ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu     * @return true if it is else false
720ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu     * @throws UiObjectNotFoundException
721d6b7eab5d1cf65a31aeebacc4a842e836ba5817cGuang Zhu     * @since API Level 16
722ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu     */
723ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu    public boolean isFocused() throws UiObjectNotFoundException {
724b04f3c526835516b098227342e741b7ce944c2f3Maxim Siniavine        Tracer.trace();
725bf43bba97b8009df1dc6c25d135fcfcbb9729540Adam Momtaz        AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout());
726ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu        if(node == null) {
727ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu            throw new UiObjectNotFoundException(getSelector().toString());
728ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu        }
729ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu        return node.isFocused();
730ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu    }
731ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu
732ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu    /**
733753092685410ea01dbb122162cd40cac48332ae1quddusc     * Check if the UI element's <code>focusable</code> property is currently true.
734f38e3f7321e4999bf92ddd6db5d5009f2e9801a2Adam Momtaz     *
735ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu     * @return true if it is else false
736ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu     * @throws UiObjectNotFoundException
737d6b7eab5d1cf65a31aeebacc4a842e836ba5817cGuang Zhu     * @since API Level 16
738ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu     */
739ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu    public boolean isFocusable() throws UiObjectNotFoundException {
740b04f3c526835516b098227342e741b7ce944c2f3Maxim Siniavine        Tracer.trace();
741bf43bba97b8009df1dc6c25d135fcfcbb9729540Adam Momtaz        AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout());
742ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu        if(node == null) {
743ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu            throw new UiObjectNotFoundException(getSelector().toString());
744ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu        }
745ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu        return node.isFocusable();
746ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu    }
747ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu
748ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu    /**
749753092685410ea01dbb122162cd40cac48332ae1quddusc     * Check if the view's <code>scrollable</code> property is currently true
750f38e3f7321e4999bf92ddd6db5d5009f2e9801a2Adam Momtaz     *
751ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu     * @return true if it is else false
752ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu     * @throws UiObjectNotFoundException
753d6b7eab5d1cf65a31aeebacc4a842e836ba5817cGuang Zhu     * @since API Level 16
754ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu     */
755ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu    public boolean isScrollable() throws UiObjectNotFoundException {
756b04f3c526835516b098227342e741b7ce944c2f3Maxim Siniavine        Tracer.trace();
757bf43bba97b8009df1dc6c25d135fcfcbb9729540Adam Momtaz        AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout());
758ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu        if(node == null) {
759ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu            throw new UiObjectNotFoundException(getSelector().toString());
760ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu        }
761ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu        return node.isScrollable();
762ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu    }
763ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu
764ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu    /**
765753092685410ea01dbb122162cd40cac48332ae1quddusc     * Check if the view's <code>long-clickable</code> property is currently true
766f38e3f7321e4999bf92ddd6db5d5009f2e9801a2Adam Momtaz     *
767ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu     * @return true if it is else false
768ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu     * @throws UiObjectNotFoundException
769d6b7eab5d1cf65a31aeebacc4a842e836ba5817cGuang Zhu     * @since API Level 16
770ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu     */
771ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu    public boolean isLongClickable() throws UiObjectNotFoundException {
772b04f3c526835516b098227342e741b7ce944c2f3Maxim Siniavine        Tracer.trace();
773bf43bba97b8009df1dc6c25d135fcfcbb9729540Adam Momtaz        AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout());
774ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu        if(node == null) {
775ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu            throw new UiObjectNotFoundException(getSelector().toString());
776ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu        }
777ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu        return node.isLongClickable();
778ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu    }
779ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu
780ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu    /**
781753092685410ea01dbb122162cd40cac48332ae1quddusc     * Reads the view's <code>package</code> property
782f38e3f7321e4999bf92ddd6db5d5009f2e9801a2Adam Momtaz     *
783f38e3f7321e4999bf92ddd6db5d5009f2e9801a2Adam Momtaz     * @return true if it is else false
784ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu     * @throws UiObjectNotFoundException
785d6b7eab5d1cf65a31aeebacc4a842e836ba5817cGuang Zhu     * @since API Level 16
786ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu     */
787ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu    public String getPackageName() throws UiObjectNotFoundException {
788b04f3c526835516b098227342e741b7ce944c2f3Maxim Siniavine        Tracer.trace();
789bf43bba97b8009df1dc6c25d135fcfcbb9729540Adam Momtaz        AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout());
790ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu        if(node == null) {
791ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu            throw new UiObjectNotFoundException(getSelector().toString());
792ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu        }
793ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu        return safeStringReturn(node.getPackageName());
794ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu    }
795ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu
796ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu    /**
797753092685410ea01dbb122162cd40cac48332ae1quddusc     * Returns the visible bounds of the view.
798fbcc9c7c6df14a11e92f5c2553069e3333710896Adam Momtaz     *
799753092685410ea01dbb122162cd40cac48332ae1quddusc     * If a portion of the view is visible, only the bounds of the visible portion are
800fbcc9c7c6df14a11e92f5c2553069e3333710896Adam Momtaz     * reported.
801f38e3f7321e4999bf92ddd6db5d5009f2e9801a2Adam Momtaz     *
802ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu     * @return Rect
803ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu     * @throws UiObjectNotFoundException
8045478840ad89ace2474b9b4d3ab14b92d9e06bf47Thanh Le     * @see {@link #getBounds()}
8058dab12c1039f9dc99f330ddc638626b4fbb11b19Guang Zhu     * @since API Level 17
806ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu     */
807f38e3f7321e4999bf92ddd6db5d5009f2e9801a2Adam Momtaz    public Rect getVisibleBounds() throws UiObjectNotFoundException {
808b04f3c526835516b098227342e741b7ce944c2f3Maxim Siniavine        Tracer.trace();
809bf43bba97b8009df1dc6c25d135fcfcbb9729540Adam Momtaz        AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout());
810ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu        if(node == null) {
811ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu            throw new UiObjectNotFoundException(getSelector().toString());
812ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu        }
813ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu        return getVisibleBounds(node);
814ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu    }
815ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu
816ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu    /**
817753092685410ea01dbb122162cd40cac48332ae1quddusc     * Returns the view's <code>bounds</code> property. See {@link #getVisibleBounds()}
818f38e3f7321e4999bf92ddd6db5d5009f2e9801a2Adam Momtaz     *
819f38e3f7321e4999bf92ddd6db5d5009f2e9801a2Adam Momtaz     * @return Rect
820f38e3f7321e4999bf92ddd6db5d5009f2e9801a2Adam Momtaz     * @throws UiObjectNotFoundException
821d6b7eab5d1cf65a31aeebacc4a842e836ba5817cGuang Zhu     * @since API Level 16
822f38e3f7321e4999bf92ddd6db5d5009f2e9801a2Adam Momtaz     */
823f38e3f7321e4999bf92ddd6db5d5009f2e9801a2Adam Momtaz    public Rect getBounds() throws UiObjectNotFoundException {
824b04f3c526835516b098227342e741b7ce944c2f3Maxim Siniavine        Tracer.trace();
825bf43bba97b8009df1dc6c25d135fcfcbb9729540Adam Momtaz        AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout());
826f38e3f7321e4999bf92ddd6db5d5009f2e9801a2Adam Momtaz        if(node == null) {
827f38e3f7321e4999bf92ddd6db5d5009f2e9801a2Adam Momtaz            throw new UiObjectNotFoundException(getSelector().toString());
828f38e3f7321e4999bf92ddd6db5d5009f2e9801a2Adam Momtaz        }
829f38e3f7321e4999bf92ddd6db5d5009f2e9801a2Adam Momtaz        Rect nodeRect = new Rect();
830f38e3f7321e4999bf92ddd6db5d5009f2e9801a2Adam Momtaz        node.getBoundsInScreen(nodeRect);
831f38e3f7321e4999bf92ddd6db5d5009f2e9801a2Adam Momtaz
832f38e3f7321e4999bf92ddd6db5d5009f2e9801a2Adam Momtaz        return nodeRect;
833f38e3f7321e4999bf92ddd6db5d5009f2e9801a2Adam Momtaz    }
834f38e3f7321e4999bf92ddd6db5d5009f2e9801a2Adam Momtaz
835f38e3f7321e4999bf92ddd6db5d5009f2e9801a2Adam Momtaz    /**
836753092685410ea01dbb122162cd40cac48332ae1quddusc     * Waits a specified length of time for a view to become visible.
837fbcc9c7c6df14a11e92f5c2553069e3333710896Adam Momtaz     *
838753092685410ea01dbb122162cd40cac48332ae1quddusc     * This method waits until the view becomes visible on the display, or
839fbcc9c7c6df14a11e92f5c2553069e3333710896Adam Momtaz     * until the timeout has elapsed. You can use this method in situations where
840fbcc9c7c6df14a11e92f5c2553069e3333710896Adam Momtaz     * the content that you want to select is not immediately displayed.
841f38e3f7321e4999bf92ddd6db5d5009f2e9801a2Adam Momtaz     *
842fbcc9c7c6df14a11e92f5c2553069e3333710896Adam Momtaz     * @param timeout the amount of time to wait (in milliseconds)
843753092685410ea01dbb122162cd40cac48332ae1quddusc     * @return true if the view is displayed, else false if timeout elapsed while waiting
844d6b7eab5d1cf65a31aeebacc4a842e836ba5817cGuang Zhu     * @since API Level 16
845ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu     */
846ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu    public boolean waitForExists(long timeout) {
847b04f3c526835516b098227342e741b7ce944c2f3Maxim Siniavine        Tracer.trace(timeout);
848ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu        if(findAccessibilityNodeInfo(timeout) != null) {
849ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu            return true;
850ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu        }
851ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu        return false;
852ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu    }
853ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu
854ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu    /**
855753092685410ea01dbb122162cd40cac48332ae1quddusc     * Waits a specified length of time for a view to become undetectable.
856f38e3f7321e4999bf92ddd6db5d5009f2e9801a2Adam Momtaz     *
857753092685410ea01dbb122162cd40cac48332ae1quddusc     * This method waits until a view is no longer matchable, or until the
858fbcc9c7c6df14a11e92f5c2553069e3333710896Adam Momtaz     * timeout has elapsed.
859fbcc9c7c6df14a11e92f5c2553069e3333710896Adam Momtaz     *
860753092685410ea01dbb122162cd40cac48332ae1quddusc     * A view becomes undetectable when the {@link UiSelector} of the object is
861fbcc9c7c6df14a11e92f5c2553069e3333710896Adam Momtaz     * unable to find a match because the element has either changed its state or is no
862fbcc9c7c6df14a11e92f5c2553069e3333710896Adam Momtaz     * longer displayed.
863fbcc9c7c6df14a11e92f5c2553069e3333710896Adam Momtaz     *
864fbcc9c7c6df14a11e92f5c2553069e3333710896Adam Momtaz     * You can use this method when attempting to wait for some long operation
865fbcc9c7c6df14a11e92f5c2553069e3333710896Adam Momtaz     * to compete, such as downloading a large file or connecting to a remote server.
866fbcc9c7c6df14a11e92f5c2553069e3333710896Adam Momtaz     *
867fbcc9c7c6df14a11e92f5c2553069e3333710896Adam Momtaz     * @param timeout time to wait (in milliseconds)
868fbcc9c7c6df14a11e92f5c2553069e3333710896Adam Momtaz     * @return true if the element is gone before timeout elapsed, else false if timeout elapsed
869fbcc9c7c6df14a11e92f5c2553069e3333710896Adam Momtaz     * but a matching element is still found.
870d6b7eab5d1cf65a31aeebacc4a842e836ba5817cGuang Zhu     * @since API Level 16
871ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu     */
872ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu    public boolean waitUntilGone(long timeout) {
873b04f3c526835516b098227342e741b7ce944c2f3Maxim Siniavine        Tracer.trace(timeout);
874ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu        long startMills = SystemClock.uptimeMillis();
875ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu        long currentMills = 0;
876ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu        while (currentMills <= timeout) {
877ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu            if(findAccessibilityNodeInfo(0) == null)
878ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu                return true;
879ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu            currentMills = SystemClock.uptimeMillis() - startMills;
880ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu            if(timeout > 0)
881ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu                SystemClock.sleep(WAIT_FOR_SELECTOR_POLL);
882ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu        }
883ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu        return false;
884ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu    }
885ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu
886ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu    /**
887753092685410ea01dbb122162cd40cac48332ae1quddusc     * Check if view exists.
888fbcc9c7c6df14a11e92f5c2553069e3333710896Adam Momtaz     *
889ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu     * This methods performs a {@link #waitForExists(long)} with zero timeout. This
890753092685410ea01dbb122162cd40cac48332ae1quddusc     * basically returns immediately whether the view represented by this UiObject
891753092685410ea01dbb122162cd40cac48332ae1quddusc     * exists or not. If you need to wait longer for this view, then see
892ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu     * {@link #waitForExists(long)}.
893f38e3f7321e4999bf92ddd6db5d5009f2e9801a2Adam Momtaz     *
894753092685410ea01dbb122162cd40cac48332ae1quddusc     * @return true if the view represented by this UiObject does exist
895d6b7eab5d1cf65a31aeebacc4a842e836ba5817cGuang Zhu     * @since API Level 16
896ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu     */
897ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu    public boolean exists() {
898b04f3c526835516b098227342e741b7ce944c2f3Maxim Siniavine        Tracer.trace();
899ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu        return waitForExists(0);
900ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu    }
901ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu
902ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu    private String safeStringReturn(CharSequence cs) {
903ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu        if(cs == null)
904ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu            return "";
905ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu        return cs.toString();
906ff763316cdb1986d8668ca3011cbb892b43aab93Guang Zhu    }
90797e4adbf51055559e5a5fa18fbb5147ea276c6c0Adam Momtaz
90897e4adbf51055559e5a5fa18fbb5147ea276c6c0Adam Momtaz    /**
909753092685410ea01dbb122162cd40cac48332ae1quddusc     * Performs a two-pointer gesture, where each pointer moves diagonally
910753092685410ea01dbb122162cd40cac48332ae1quddusc     * opposite across the other, from the center out towards the edges of the
91197e4adbf51055559e5a5fa18fbb5147ea276c6c0Adam Momtaz     * this UiObject.
912753092685410ea01dbb122162cd40cac48332ae1quddusc     * @param percent percentage of the object's diagonal length for the pinch gesture
913753092685410ea01dbb122162cd40cac48332ae1quddusc     * @param steps the number of steps for the gesture. Steps are injected
914753092685410ea01dbb122162cd40cac48332ae1quddusc     * about 5 milliseconds apart, so 100 steps may take around 0.5 seconds to complete.
9151ac23e97d43bc4acc3101c3ad3f3529fd118906cGuang Zhu     * @return <code>true</code> if all touch events for this gesture are injected successfully,
916753092685410ea01dbb122162cd40cac48332ae1quddusc     *         <code>false</code> otherwise
91797e4adbf51055559e5a5fa18fbb5147ea276c6c0Adam Momtaz     * @throws UiObjectNotFoundException
91897e4adbf51055559e5a5fa18fbb5147ea276c6c0Adam Momtaz     * @since API Level 18
91997e4adbf51055559e5a5fa18fbb5147ea276c6c0Adam Momtaz     */
9201ac23e97d43bc4acc3101c3ad3f3529fd118906cGuang Zhu    public boolean pinchOut(int percent, int steps) throws UiObjectNotFoundException {
92197e4adbf51055559e5a5fa18fbb5147ea276c6c0Adam Momtaz        // make value between 1 and 100
92297e4adbf51055559e5a5fa18fbb5147ea276c6c0Adam Momtaz        percent = (percent < 0) ? 1 : (percent > 100) ? 100 : percent;
92397e4adbf51055559e5a5fa18fbb5147ea276c6c0Adam Momtaz        float percentage = percent / 100f;
92497e4adbf51055559e5a5fa18fbb5147ea276c6c0Adam Momtaz
925bf43bba97b8009df1dc6c25d135fcfcbb9729540Adam Momtaz        AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout());
92697e4adbf51055559e5a5fa18fbb5147ea276c6c0Adam Momtaz        if (node == null) {
92797e4adbf51055559e5a5fa18fbb5147ea276c6c0Adam Momtaz            throw new UiObjectNotFoundException(getSelector().toString());
92897e4adbf51055559e5a5fa18fbb5147ea276c6c0Adam Momtaz        }
92997e4adbf51055559e5a5fa18fbb5147ea276c6c0Adam Momtaz
93097e4adbf51055559e5a5fa18fbb5147ea276c6c0Adam Momtaz        Rect rect = getVisibleBounds(node);
93197e4adbf51055559e5a5fa18fbb5147ea276c6c0Adam Momtaz        if (rect.width() <= FINGER_TOUCH_HALF_WIDTH * 2)
93297e4adbf51055559e5a5fa18fbb5147ea276c6c0Adam Momtaz            throw new IllegalStateException("Object width is too small for operation");
93397e4adbf51055559e5a5fa18fbb5147ea276c6c0Adam Momtaz
93497e4adbf51055559e5a5fa18fbb5147ea276c6c0Adam Momtaz        // start from the same point at the center of the control
93597e4adbf51055559e5a5fa18fbb5147ea276c6c0Adam Momtaz        Point startPoint1 = new Point(rect.centerX() - FINGER_TOUCH_HALF_WIDTH, rect.centerY());
93697e4adbf51055559e5a5fa18fbb5147ea276c6c0Adam Momtaz        Point startPoint2 = new Point(rect.centerX() + FINGER_TOUCH_HALF_WIDTH, rect.centerY());
93797e4adbf51055559e5a5fa18fbb5147ea276c6c0Adam Momtaz
93897e4adbf51055559e5a5fa18fbb5147ea276c6c0Adam Momtaz        // End at the top-left and bottom-right corners of the control
93997e4adbf51055559e5a5fa18fbb5147ea276c6c0Adam Momtaz        Point endPoint1 = new Point(rect.centerX() - (int)((rect.width()/2) * percentage),
94097e4adbf51055559e5a5fa18fbb5147ea276c6c0Adam Momtaz                rect.centerY());
94197e4adbf51055559e5a5fa18fbb5147ea276c6c0Adam Momtaz        Point endPoint2 = new Point(rect.centerX() + (int)((rect.width()/2) * percentage),
94297e4adbf51055559e5a5fa18fbb5147ea276c6c0Adam Momtaz                rect.centerY());
94397e4adbf51055559e5a5fa18fbb5147ea276c6c0Adam Momtaz
9441ac23e97d43bc4acc3101c3ad3f3529fd118906cGuang Zhu        return performTwoPointerGesture(startPoint1, startPoint2, endPoint1, endPoint2, steps);
94597e4adbf51055559e5a5fa18fbb5147ea276c6c0Adam Momtaz    }
94697e4adbf51055559e5a5fa18fbb5147ea276c6c0Adam Momtaz
94797e4adbf51055559e5a5fa18fbb5147ea276c6c0Adam Momtaz    /**
948753092685410ea01dbb122162cd40cac48332ae1quddusc     * Performs a two-pointer gesture, where each pointer moves diagonally
949753092685410ea01dbb122162cd40cac48332ae1quddusc     * toward the other, from the edges to the center of this UiObject .
950753092685410ea01dbb122162cd40cac48332ae1quddusc     * @param percent percentage of the object's diagonal length for the pinch gesture
951753092685410ea01dbb122162cd40cac48332ae1quddusc     * @param steps the number of steps for the gesture. Steps are injected
952753092685410ea01dbb122162cd40cac48332ae1quddusc     * about 5 milliseconds apart, so 100 steps may take around 0.5 seconds to complete.
9531ac23e97d43bc4acc3101c3ad3f3529fd118906cGuang Zhu     * @return <code>true</code> if all touch events for this gesture are injected successfully,
954753092685410ea01dbb122162cd40cac48332ae1quddusc     *         <code>false</code> otherwise
95597e4adbf51055559e5a5fa18fbb5147ea276c6c0Adam Momtaz     * @throws UiObjectNotFoundException
95697e4adbf51055559e5a5fa18fbb5147ea276c6c0Adam Momtaz     * @since API Level 18
95797e4adbf51055559e5a5fa18fbb5147ea276c6c0Adam Momtaz     */
9581ac23e97d43bc4acc3101c3ad3f3529fd118906cGuang Zhu    public boolean pinchIn(int percent, int steps) throws UiObjectNotFoundException {
95997e4adbf51055559e5a5fa18fbb5147ea276c6c0Adam Momtaz        // make value between 1 and 100
96097e4adbf51055559e5a5fa18fbb5147ea276c6c0Adam Momtaz        percent = (percent < 0) ? 0 : (percent > 100) ? 100 : percent;
96197e4adbf51055559e5a5fa18fbb5147ea276c6c0Adam Momtaz        float percentage = percent / 100f;
96297e4adbf51055559e5a5fa18fbb5147ea276c6c0Adam Momtaz
963bf43bba97b8009df1dc6c25d135fcfcbb9729540Adam Momtaz        AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout());
96497e4adbf51055559e5a5fa18fbb5147ea276c6c0Adam Momtaz        if (node == null) {
96597e4adbf51055559e5a5fa18fbb5147ea276c6c0Adam Momtaz            throw new UiObjectNotFoundException(getSelector().toString());
96697e4adbf51055559e5a5fa18fbb5147ea276c6c0Adam Momtaz        }
96797e4adbf51055559e5a5fa18fbb5147ea276c6c0Adam Momtaz
96897e4adbf51055559e5a5fa18fbb5147ea276c6c0Adam Momtaz        Rect rect = getVisibleBounds(node);
96997e4adbf51055559e5a5fa18fbb5147ea276c6c0Adam Momtaz        if (rect.width() <= FINGER_TOUCH_HALF_WIDTH * 2)
97097e4adbf51055559e5a5fa18fbb5147ea276c6c0Adam Momtaz            throw new IllegalStateException("Object width is too small for operation");
97197e4adbf51055559e5a5fa18fbb5147ea276c6c0Adam Momtaz
97297e4adbf51055559e5a5fa18fbb5147ea276c6c0Adam Momtaz        Point startPoint1 = new Point(rect.centerX() - (int)((rect.width()/2) * percentage),
97397e4adbf51055559e5a5fa18fbb5147ea276c6c0Adam Momtaz                rect.centerY());
97497e4adbf51055559e5a5fa18fbb5147ea276c6c0Adam Momtaz        Point startPoint2 = new Point(rect.centerX() + (int)((rect.width()/2) * percentage),
97597e4adbf51055559e5a5fa18fbb5147ea276c6c0Adam Momtaz                rect.centerY());
97697e4adbf51055559e5a5fa18fbb5147ea276c6c0Adam Momtaz
97797e4adbf51055559e5a5fa18fbb5147ea276c6c0Adam Momtaz        Point endPoint1 = new Point(rect.centerX() - FINGER_TOUCH_HALF_WIDTH, rect.centerY());
97897e4adbf51055559e5a5fa18fbb5147ea276c6c0Adam Momtaz        Point endPoint2 = new Point(rect.centerX() + FINGER_TOUCH_HALF_WIDTH, rect.centerY());
97997e4adbf51055559e5a5fa18fbb5147ea276c6c0Adam Momtaz
9801ac23e97d43bc4acc3101c3ad3f3529fd118906cGuang Zhu        return performTwoPointerGesture(startPoint1, startPoint2, endPoint1, endPoint2, steps);
98197e4adbf51055559e5a5fa18fbb5147ea276c6c0Adam Momtaz    }
98297e4adbf51055559e5a5fa18fbb5147ea276c6c0Adam Momtaz
98397e4adbf51055559e5a5fa18fbb5147ea276c6c0Adam Momtaz    /**
984753092685410ea01dbb122162cd40cac48332ae1quddusc     * Generates a two-pointer gesture with arbitrary starting and ending points.
98597e4adbf51055559e5a5fa18fbb5147ea276c6c0Adam Momtaz     *
98697e4adbf51055559e5a5fa18fbb5147ea276c6c0Adam Momtaz     * @param startPoint1 start point of pointer 1
98797e4adbf51055559e5a5fa18fbb5147ea276c6c0Adam Momtaz     * @param startPoint2 start point of pointer 2
98897e4adbf51055559e5a5fa18fbb5147ea276c6c0Adam Momtaz     * @param endPoint1 end point of pointer 1
98997e4adbf51055559e5a5fa18fbb5147ea276c6c0Adam Momtaz     * @param endPoint2 end point of pointer 2
990753092685410ea01dbb122162cd40cac48332ae1quddusc     * @param steps the number of steps for the gesture. Steps are injected
991753092685410ea01dbb122162cd40cac48332ae1quddusc     * about 5 milliseconds apart, so 100 steps may take around 0.5 seconds to complete.
9921ac23e97d43bc4acc3101c3ad3f3529fd118906cGuang Zhu     * @return <code>true</code> if all touch events for this gesture are injected successfully,
993753092685410ea01dbb122162cd40cac48332ae1quddusc     *         <code>false</code> otherwise
99497e4adbf51055559e5a5fa18fbb5147ea276c6c0Adam Momtaz     * @since API Level 18
99597e4adbf51055559e5a5fa18fbb5147ea276c6c0Adam Momtaz     */
9961ac23e97d43bc4acc3101c3ad3f3529fd118906cGuang Zhu    public boolean performTwoPointerGesture(Point startPoint1, Point startPoint2, Point endPoint1,
99797e4adbf51055559e5a5fa18fbb5147ea276c6c0Adam Momtaz            Point endPoint2, int steps) {
99897e4adbf51055559e5a5fa18fbb5147ea276c6c0Adam Momtaz
99997e4adbf51055559e5a5fa18fbb5147ea276c6c0Adam Momtaz        // avoid a divide by zero
100097e4adbf51055559e5a5fa18fbb5147ea276c6c0Adam Momtaz        if(steps == 0)
100197e4adbf51055559e5a5fa18fbb5147ea276c6c0Adam Momtaz            steps = 1;
100297e4adbf51055559e5a5fa18fbb5147ea276c6c0Adam Momtaz
100397e4adbf51055559e5a5fa18fbb5147ea276c6c0Adam Momtaz        final float stepX1 = (endPoint1.x - startPoint1.x) / steps;
100497e4adbf51055559e5a5fa18fbb5147ea276c6c0Adam Momtaz        final float stepY1 = (endPoint1.y - startPoint1.y) / steps;
100597e4adbf51055559e5a5fa18fbb5147ea276c6c0Adam Momtaz        final float stepX2 = (endPoint2.x - startPoint2.x) / steps;
100697e4adbf51055559e5a5fa18fbb5147ea276c6c0Adam Momtaz        final float stepY2 = (endPoint2.y - startPoint2.y) / steps;
100797e4adbf51055559e5a5fa18fbb5147ea276c6c0Adam Momtaz
100897e4adbf51055559e5a5fa18fbb5147ea276c6c0Adam Momtaz        int eventX1, eventY1, eventX2, eventY2;
100997e4adbf51055559e5a5fa18fbb5147ea276c6c0Adam Momtaz        eventX1 = startPoint1.x;
101097e4adbf51055559e5a5fa18fbb5147ea276c6c0Adam Momtaz        eventY1 = startPoint1.y;
101197e4adbf51055559e5a5fa18fbb5147ea276c6c0Adam Momtaz        eventX2 = startPoint2.x;
101297e4adbf51055559e5a5fa18fbb5147ea276c6c0Adam Momtaz        eventY2 = startPoint2.y;
101397e4adbf51055559e5a5fa18fbb5147ea276c6c0Adam Momtaz
101497e4adbf51055559e5a5fa18fbb5147ea276c6c0Adam Momtaz        // allocate for steps plus first down and last up
101597e4adbf51055559e5a5fa18fbb5147ea276c6c0Adam Momtaz        PointerCoords[] points1 = new PointerCoords[steps + 2];
101697e4adbf51055559e5a5fa18fbb5147ea276c6c0Adam Momtaz        PointerCoords[] points2 = new PointerCoords[steps + 2];
101797e4adbf51055559e5a5fa18fbb5147ea276c6c0Adam Momtaz
101897e4adbf51055559e5a5fa18fbb5147ea276c6c0Adam Momtaz        // Include the first and last touch downs in the arrays of steps
101997e4adbf51055559e5a5fa18fbb5147ea276c6c0Adam Momtaz        for (int i = 0; i < steps + 1; i++) {
102097e4adbf51055559e5a5fa18fbb5147ea276c6c0Adam Momtaz            PointerCoords p1 = new PointerCoords();
102197e4adbf51055559e5a5fa18fbb5147ea276c6c0Adam Momtaz            p1.x = eventX1;
102297e4adbf51055559e5a5fa18fbb5147ea276c6c0Adam Momtaz            p1.y = eventY1;
102397e4adbf51055559e5a5fa18fbb5147ea276c6c0Adam Momtaz            p1.pressure = 1;
102497e4adbf51055559e5a5fa18fbb5147ea276c6c0Adam Momtaz            p1.size = 1;
102597e4adbf51055559e5a5fa18fbb5147ea276c6c0Adam Momtaz            points1[i] = p1;
102697e4adbf51055559e5a5fa18fbb5147ea276c6c0Adam Momtaz
102797e4adbf51055559e5a5fa18fbb5147ea276c6c0Adam Momtaz            PointerCoords p2 = new PointerCoords();
102897e4adbf51055559e5a5fa18fbb5147ea276c6c0Adam Momtaz            p2.x = eventX2;
102997e4adbf51055559e5a5fa18fbb5147ea276c6c0Adam Momtaz            p2.y = eventY2;
103097e4adbf51055559e5a5fa18fbb5147ea276c6c0Adam Momtaz            p2.pressure = 1;
103197e4adbf51055559e5a5fa18fbb5147ea276c6c0Adam Momtaz            p2.size = 1;
103297e4adbf51055559e5a5fa18fbb5147ea276c6c0Adam Momtaz            points2[i] = p2;
103397e4adbf51055559e5a5fa18fbb5147ea276c6c0Adam Momtaz
103497e4adbf51055559e5a5fa18fbb5147ea276c6c0Adam Momtaz            eventX1 += stepX1;
103597e4adbf51055559e5a5fa18fbb5147ea276c6c0Adam Momtaz            eventY1 += stepY1;
103697e4adbf51055559e5a5fa18fbb5147ea276c6c0Adam Momtaz            eventX2 += stepX2;
103797e4adbf51055559e5a5fa18fbb5147ea276c6c0Adam Momtaz            eventY2 += stepY2;
103897e4adbf51055559e5a5fa18fbb5147ea276c6c0Adam Momtaz        }
103997e4adbf51055559e5a5fa18fbb5147ea276c6c0Adam Momtaz
104097e4adbf51055559e5a5fa18fbb5147ea276c6c0Adam Momtaz        // ending pointers coordinates
104197e4adbf51055559e5a5fa18fbb5147ea276c6c0Adam Momtaz        PointerCoords p1 = new PointerCoords();
104297e4adbf51055559e5a5fa18fbb5147ea276c6c0Adam Momtaz        p1.x = endPoint1.x;
104397e4adbf51055559e5a5fa18fbb5147ea276c6c0Adam Momtaz        p1.y = endPoint1.y;
104497e4adbf51055559e5a5fa18fbb5147ea276c6c0Adam Momtaz        p1.pressure = 1;
104597e4adbf51055559e5a5fa18fbb5147ea276c6c0Adam Momtaz        p1.size = 1;
104697e4adbf51055559e5a5fa18fbb5147ea276c6c0Adam Momtaz        points1[steps + 1] = p1;
104797e4adbf51055559e5a5fa18fbb5147ea276c6c0Adam Momtaz
104897e4adbf51055559e5a5fa18fbb5147ea276c6c0Adam Momtaz        PointerCoords p2 = new PointerCoords();
104997e4adbf51055559e5a5fa18fbb5147ea276c6c0Adam Momtaz        p2.x = endPoint2.x;
105097e4adbf51055559e5a5fa18fbb5147ea276c6c0Adam Momtaz        p2.y = endPoint2.y;
105197e4adbf51055559e5a5fa18fbb5147ea276c6c0Adam Momtaz        p2.pressure = 1;
105297e4adbf51055559e5a5fa18fbb5147ea276c6c0Adam Momtaz        p2.size = 1;
105397e4adbf51055559e5a5fa18fbb5147ea276c6c0Adam Momtaz        points2[steps + 1] = p2;
105497e4adbf51055559e5a5fa18fbb5147ea276c6c0Adam Momtaz
10551ac23e97d43bc4acc3101c3ad3f3529fd118906cGuang Zhu        return performMultiPointerGesture(points1, points2);
105697e4adbf51055559e5a5fa18fbb5147ea276c6c0Adam Momtaz    }
105797e4adbf51055559e5a5fa18fbb5147ea276c6c0Adam Momtaz
105897e4adbf51055559e5a5fa18fbb5147ea276c6c0Adam Momtaz    /**
1059753092685410ea01dbb122162cd40cac48332ae1quddusc     * Performs a multi-touch gesture. You must specify touch coordinates for
1060753092685410ea01dbb122162cd40cac48332ae1quddusc     * at least 2 pointers. Each pointer must have all of its touch steps
1061753092685410ea01dbb122162cd40cac48332ae1quddusc     * defined in an array of {@link PointerCoords}. You can use this method to
1062753092685410ea01dbb122162cd40cac48332ae1quddusc     * specify complex gestures, like circles and irregular shapes, where each
1063753092685410ea01dbb122162cd40cac48332ae1quddusc     * pointer may take a different path.
106497e4adbf51055559e5a5fa18fbb5147ea276c6c0Adam Momtaz     *
1065753092685410ea01dbb122162cd40cac48332ae1quddusc     * To create a single point on a pointer's touch path:
106697e4adbf51055559e5a5fa18fbb5147ea276c6c0Adam Momtaz     * <code>
106797e4adbf51055559e5a5fa18fbb5147ea276c6c0Adam Momtaz     *       PointerCoords p = new PointerCoords();
106897e4adbf51055559e5a5fa18fbb5147ea276c6c0Adam Momtaz     *       p.x = stepX;
106997e4adbf51055559e5a5fa18fbb5147ea276c6c0Adam Momtaz     *       p.y = stepY;
107097e4adbf51055559e5a5fa18fbb5147ea276c6c0Adam Momtaz     *       p.pressure = 1;
107197e4adbf51055559e5a5fa18fbb5147ea276c6c0Adam Momtaz     *       p.size = 1;
107297e4adbf51055559e5a5fa18fbb5147ea276c6c0Adam Momtaz     * </code>
10737093e225477d309c278c45cfe545f2c070aadad0Guang Zhu     * @param touches represents the pointers' paths. Each {@link PointerCoords}
10747093e225477d309c278c45cfe545f2c070aadad0Guang Zhu     * array represents a different pointer. Each {@link PointerCoords} in an
1075753092685410ea01dbb122162cd40cac48332ae1quddusc     * array element represents a touch point on a pointer's path.
10761ac23e97d43bc4acc3101c3ad3f3529fd118906cGuang Zhu     * @return <code>true</code> if all touch events for this gesture are injected successfully,
1077753092685410ea01dbb122162cd40cac48332ae1quddusc     *         <code>false</code> otherwise
107897e4adbf51055559e5a5fa18fbb5147ea276c6c0Adam Momtaz     * @since API Level 18
107997e4adbf51055559e5a5fa18fbb5147ea276c6c0Adam Momtaz     */
10801ac23e97d43bc4acc3101c3ad3f3529fd118906cGuang Zhu    public boolean performMultiPointerGesture(PointerCoords[] ...touches) {
10811ac23e97d43bc4acc3101c3ad3f3529fd118906cGuang Zhu        return getInteractionController().performMultiPointerGesture(touches);
108297e4adbf51055559e5a5fa18fbb5147ea276c6c0Adam Momtaz    }
10837093e225477d309c278c45cfe545f2c070aadad0Guang Zhu}
1084