1e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu/*
2e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * Copyright (C) 2012 The Android Open Source Project
3e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu *
4e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * Licensed under the Apache License, Version 2.0 (the "License");
5e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * you may not use this file except in compliance with the License.
6e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * You may obtain a copy of the License at
7e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu *
8e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu *      http://www.apache.org/licenses/LICENSE-2.0
9e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu *
10e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * Unless required by applicable law or agreed to in writing, software
11e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * distributed under the License is distributed on an "AS IS" BASIS,
12e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * See the License for the specific language governing permissions and
14e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * limitations under the License.
15e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */
16e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
17e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhupackage com.android.uiautomator.core;
18e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
19e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhuimport android.graphics.Rect;
20e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhuimport android.os.SystemClock;
21e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhuimport android.util.Log;
22e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhuimport android.view.KeyEvent;
236088c8f9e34e34a4958b1601ed7c1bb34c95da21Adam Momtazimport android.view.accessibility.AccessibilityEvent;
24e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhuimport android.view.accessibility.AccessibilityNodeInfo;
25e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
26e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu/**
2746d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * A UiObject is a representation of a UI element. It is not in any way directly bound to a
2846d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * UI element as an object reference. A UiObject holds information to help it
2946d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * locate a matching UI element at runtime based on the {@link UiSelector} properties specified in
3046d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * its constructor. Since a UiObject is a representative for a UI element, it can
3146d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz * be reused for different views with matching UI elements.
32dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16
33e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */
34e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhupublic class UiObject {
35e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    private static final String LOG_TAG = UiObject.class.getSimpleName();
36dbba713661688a285e701a006ce2d199296ac328Guang Zhu    /**
37dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
38dbba713661688a285e701a006ce2d199296ac328Guang Zhu     **/
39e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    protected static final long WAIT_FOR_SELECTOR_TIMEOUT = 10 * 1000;
40dbba713661688a285e701a006ce2d199296ac328Guang Zhu    /**
41dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
42dbba713661688a285e701a006ce2d199296ac328Guang Zhu     **/
43e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    protected static final long WAIT_FOR_SELECTOR_POLL = 1000;
44e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    // set a default timeout to 5.5s, since ANR threshold is 5s
45dbba713661688a285e701a006ce2d199296ac328Guang Zhu    /**
46dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
47dbba713661688a285e701a006ce2d199296ac328Guang Zhu     **/
48e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    protected static final long WAIT_FOR_WINDOW_TMEOUT = 5500;
49dbba713661688a285e701a006ce2d199296ac328Guang Zhu    /**
50dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 17
51dbba713661688a285e701a006ce2d199296ac328Guang Zhu     **/
526088c8f9e34e34a4958b1601ed7c1bb34c95da21Adam Momtaz    protected static final long WAIT_FOR_EVENT_TMEOUT = 3 * 1000;
53dbba713661688a285e701a006ce2d199296ac328Guang Zhu    /**
54dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
55dbba713661688a285e701a006ce2d199296ac328Guang Zhu     **/
56e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    protected static final int SWIPE_MARGIN_LIMIT = 5;
57e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
587f38ef08d07295967b905a61b2356ff6cdf31159Adam Momtaz    private final UiSelector mSelector;
59ddc1008f06fd2a875037026490ce1f848a442572Guang Zhu    private final UiAutomatorBridge mUiAutomationBridge;
60e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
61e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
623d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * Constructs a UiObject to represent a specific UI element matched by the specified
633d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * {@link UiSelector} selector properties.
64e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @param selector
65dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
66e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
674ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz    public UiObject(UiSelector selector) {
68e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        mUiAutomationBridge = UiDevice.getInstance().getAutomatorBridge();
69e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        mSelector = selector;
70e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
71e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
72e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
733d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * Debugging helper. A test can dump the properties of a selector as a string
743d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * to its logs if needed. <code>getSelector().toString();</code>
753d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
764ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz     * @return {@link UiSelector}
77dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
78e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
794ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz    public final UiSelector getSelector() {
80f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine        Tracer.trace();
814ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz        return new UiSelector(mSelector);
82e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
83e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
84e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
853d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * Retrieves the {@link QueryController} to translate a {@link UiSelector} selector
863d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * into an {@link AccessibilityNodeInfo}.
873d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
88e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @return {@link QueryController}
89e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
90ddc1008f06fd2a875037026490ce1f848a442572Guang Zhu    QueryController getQueryController() {
91e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        return mUiAutomationBridge.getQueryController();
92e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
93e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
94e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
953d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * Retrieves the {@link InteractionController} to perform finger actions such as tapping,
963d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * swiping or entering text.
973d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
98e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @return {@link InteractionController}
99e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
100ddc1008f06fd2a875037026490ce1f848a442572Guang Zhu    InteractionController getInteractionController() {
101e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        return mUiAutomationBridge.getInteractionController();
102e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
103e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
104e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
1053d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * Creates a new UiObject representing a child UI element of the element currently represented
1063d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * by this UiObject.
1073d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
1083d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * @param selector for UI element to match
1093d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * @return a new UiObject representing the matched UI element
110dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
111e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
1124ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz    public UiObject getChild(UiSelector selector) throws UiObjectNotFoundException {
113f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine        Tracer.trace(selector);
1144ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz        return new UiObject(getSelector().childSelector(selector));
115e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
116e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
117e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
1183d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * Creates a new UiObject representing a child UI element from the parent element currently
1193d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * represented by this object. Essentially this is starting the search from the parent
1203d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * element and can also be used to find sibling UI elements to the one currently represented
1213d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * by this UiObject.
1223d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
1233d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * @param selector for the UI element to match
1243d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * @return a new UiObject representing the matched UI element
125e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @throws UiObjectNotFoundException
126dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
127e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
1284ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz    public UiObject getFromParent(UiSelector selector) throws UiObjectNotFoundException {
129f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine        Tracer.trace(selector);
1304ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz        return new UiObject(getSelector().fromParent(selector));
131e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
132e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
133e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
1343d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * Counts the child UI elements immediately under the UI element currently represented by
135e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * this UiObject.
1363d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
137e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @return the count of child UI elements.
138e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @throws UiObjectNotFoundException
139dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
140e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
141e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    public int getChildCount() throws UiObjectNotFoundException {
142f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine        Tracer.trace();
143e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT);
144e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        if(node == null) {
145e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            throw new UiObjectNotFoundException(getSelector().toString());
146e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
147e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        return node.getChildCount();
148e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
149e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
150e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
1513d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * Uses the member UiSelector properties to find a matching UI element reported in
1523d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * the accessibility hierarchy.
1533d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
154e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @param timeout in milliseconds
155e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @return AccessibilityNodeInfo if found else null
156dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
157e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
158e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    protected AccessibilityNodeInfo findAccessibilityNodeInfo(long timeout) {
159e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        AccessibilityNodeInfo node = null;
160e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        if(UiDevice.getInstance().isInWatcherContext()) {
161e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            // we will NOT run watchers or do any sort of polling if the
162e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            // reason we're here is because of a watcher is executing. Watchers
163e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            // will not have other watchers run for them so they should not block
164e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            // while they poll for items to become present. We disable polling for them.
165e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            node = getQueryController().findAccessibilityNodeInfo(getSelector());
166e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        } else {
167e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            long startMills = SystemClock.uptimeMillis();
168e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            long currentMills = 0;
169e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            while (currentMills <= timeout) {
170e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                node = getQueryController().findAccessibilityNodeInfo(getSelector());
171e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                if (node != null) {
172e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                    break;
173e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                } else {
174e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                    UiDevice.getInstance().runWatchers();
175e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                }
176e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                currentMills = SystemClock.uptimeMillis() - startMills;
177e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                if(timeout > 0) {
178e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                    SystemClock.sleep(WAIT_FOR_SELECTOR_POLL);
179e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                }
180e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            }
181e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
182e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        return node;
183e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
184e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
185e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
1863d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * Perform the action on the UI element that is represented by this UiObject. Also see
1871893caed0ad4e73b0676f206282d490c2d345316Thanh Le     * {@link UiScrollable#scrollToBeginning(int)}, {@link UiScrollable#scrollToEnd(int)},
1881893caed0ad4e73b0676f206282d490c2d345316Thanh Le     * {@link UiScrollable#scrollBackward()}, {@link UiScrollable#scrollForward()}.
1893d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
190467cca7d25dbbf13c14cfd8c2ad38ab8eaf56bdaAdam Momtaz     * @param steps indicates the number of injected move steps into the system. Steps are
191467cca7d25dbbf13c14cfd8c2ad38ab8eaf56bdaAdam Momtaz     * injected about 5ms apart. So a 100 steps may take about 1/2 second to complete.
1923d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * @return true of successful
193e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @throws UiObjectNotFoundException
194dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
195e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
196e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    public boolean swipeUp(int steps) throws UiObjectNotFoundException {
197f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine        Tracer.trace(steps);
1983d50587be8ff021369c90554d814839335b445b0Adam Momtaz        Rect rect = getVisibleBounds();
199e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        if(rect.height() <= SWIPE_MARGIN_LIMIT * 2)
200e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            return false; // too small to swipe
201e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        return getInteractionController().swipe(rect.centerX(),
202e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                rect.bottom - SWIPE_MARGIN_LIMIT, rect.centerX(), rect.top + SWIPE_MARGIN_LIMIT,
203e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                steps);
204e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
205e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
206e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
207e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * Perform the action on the UI element that is represented by this object, Also see
2081893caed0ad4e73b0676f206282d490c2d345316Thanh Le     * {@link UiScrollable#scrollToBeginning(int)}, {@link UiScrollable#scrollToEnd(int)},
2091893caed0ad4e73b0676f206282d490c2d345316Thanh Le     * {@link UiScrollable#scrollBackward()}, {@link UiScrollable#scrollForward()}. This method will
2101893caed0ad4e73b0676f206282d490c2d345316Thanh Le     * perform the swipe gesture over any surface.  The targeted UI element does not need to have
2111893caed0ad4e73b0676f206282d490c2d345316Thanh Le     * the attribute <code>scrollable</code> set to <code>true</code> for this operation to be
2121893caed0ad4e73b0676f206282d490c2d345316Thanh Le     * performed.
2133d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
2143d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * @param steps indicates the number of injected move steps into the system. Steps are
215467cca7d25dbbf13c14cfd8c2ad38ab8eaf56bdaAdam Momtaz     * injected about 5ms apart. So a 100 steps may take about 1/2 second to complete.
2163d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * @return true if successful
217e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @throws UiObjectNotFoundException
218dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
219e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
220e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    public boolean swipeDown(int steps) throws UiObjectNotFoundException {
221f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine        Tracer.trace(steps);
2223d50587be8ff021369c90554d814839335b445b0Adam Momtaz        Rect rect = getVisibleBounds();
223e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        if(rect.height() <= SWIPE_MARGIN_LIMIT * 2)
224e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            return false; // too small to swipe
225e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        return getInteractionController().swipe(rect.centerX(),
226e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                rect.top + SWIPE_MARGIN_LIMIT, rect.centerX(),
227e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                rect.bottom - SWIPE_MARGIN_LIMIT, steps);
228e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
229e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
230e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
231e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * Perform the action on the UI element that is represented by this object. Also see
2321893caed0ad4e73b0676f206282d490c2d345316Thanh Le     * {@link UiScrollable#scrollToBeginning(int)}, {@link UiScrollable#scrollToEnd(int)},
2331893caed0ad4e73b0676f206282d490c2d345316Thanh Le     * {@link UiScrollable#scrollBackward()}, {@link UiScrollable#scrollForward()}. This method will
2341893caed0ad4e73b0676f206282d490c2d345316Thanh Le     * perform the swipe gesture over any surface. The targeted UI element does not need to have the
2351893caed0ad4e73b0676f206282d490c2d345316Thanh Le     * attribute <code>scrollable</code> set to <code>true</code> for this operation to be
2361893caed0ad4e73b0676f206282d490c2d345316Thanh Le     * performed.
2373d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
2383d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * @param steps indicates the number of injected move steps into the system. Steps are
239467cca7d25dbbf13c14cfd8c2ad38ab8eaf56bdaAdam Momtaz     * injected about 5ms apart. So a 100 steps may take about 1/2 second to complete.
2403d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * @return true if successful
241e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @throws UiObjectNotFoundException
242dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
243e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
244e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    public boolean swipeLeft(int steps) throws UiObjectNotFoundException {
245f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine        Tracer.trace(steps);
2463d50587be8ff021369c90554d814839335b445b0Adam Momtaz        Rect rect = getVisibleBounds();
247e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        if(rect.width() <= SWIPE_MARGIN_LIMIT * 2)
248e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            return false; // too small to swipe
249e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        return getInteractionController().swipe(rect.right - SWIPE_MARGIN_LIMIT,
250e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                rect.centerY(), rect.left + SWIPE_MARGIN_LIMIT, rect.centerY(), steps);
251e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
252e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
253e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
254e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * Perform the action on the UI element that is represented by this object. Also see
2551893caed0ad4e73b0676f206282d490c2d345316Thanh Le     * {@link UiScrollable#scrollToBeginning(int)}, {@link UiScrollable#scrollToEnd(int)},
2561893caed0ad4e73b0676f206282d490c2d345316Thanh Le     * {@link UiScrollable#scrollBackward()}, {@link UiScrollable#scrollForward()}. This method will
2571893caed0ad4e73b0676f206282d490c2d345316Thanh Le     * perform the swipe gesture over any surface. The targeted UI element does not need to have the
2581893caed0ad4e73b0676f206282d490c2d345316Thanh Le     * attribute <code>scrollable</code> set to <code>true</code> for this operation to be
2591893caed0ad4e73b0676f206282d490c2d345316Thanh Le     * performed.
2603d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
2613d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * @param steps indicates the number of injected move steps into the system. Steps are
262467cca7d25dbbf13c14cfd8c2ad38ab8eaf56bdaAdam Momtaz     * injected about 5ms apart. So a 100 steps may take about 1/2 second to complete.
2633d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * @return true if successful
264e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @throws UiObjectNotFoundException
265dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
266e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
267e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    public boolean swipeRight(int steps) throws UiObjectNotFoundException {
268f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine        Tracer.trace(steps);
2693d50587be8ff021369c90554d814839335b445b0Adam Momtaz        Rect rect = getVisibleBounds();
270e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        if(rect.width() <= SWIPE_MARGIN_LIMIT * 2)
271e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            return false; // too small to swipe
272e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        return getInteractionController().swipe(rect.left + SWIPE_MARGIN_LIMIT,
273e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                rect.centerY(), rect.right - SWIPE_MARGIN_LIMIT, rect.centerY(), steps);
274e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
275e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
276e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
2773d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * Finds the visible bounds of a partially visible UI element
2783d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
279e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @param node
2807f38ef08d07295967b905a61b2356ff6cdf31159Adam Momtaz     * @return null if node is null, else a Rect containing visible bounds
281e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
282e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    private Rect getVisibleBounds(AccessibilityNodeInfo node) {
283e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        if (node == null) {
284e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            return null;
285e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
286e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
287e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        // targeted node's bounds
2887f38ef08d07295967b905a61b2356ff6cdf31159Adam Momtaz        Rect nodeRect = AccessibilityNodeInfoHelper.getVisibleBoundsInScreen(node);
289e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
290e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        // is the targeted node within a scrollable container?
291e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        AccessibilityNodeInfo scrollableParentNode = getScrollableParent(node);
292e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        if(scrollableParentNode == null) {
293e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            // nothing to adjust for so return the node's Rect as is
294e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            return nodeRect;
295e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
296e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
297e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        // Scrollable parent's visible bounds
2987f38ef08d07295967b905a61b2356ff6cdf31159Adam Momtaz        Rect parentRect = AccessibilityNodeInfoHelper
2997f38ef08d07295967b905a61b2356ff6cdf31159Adam Momtaz                .getVisibleBoundsInScreen(scrollableParentNode);
300e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        // adjust for partial clipping of targeted by parent node if required
301e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        nodeRect.intersect(parentRect);
302e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        return nodeRect;
303e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
304e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
305e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
3067f38ef08d07295967b905a61b2356ff6cdf31159Adam Momtaz     * Walk the hierarchy up to find a scrollable parent. A scrollable parent
3077f38ef08d07295967b905a61b2356ff6cdf31159Adam Momtaz     * indicates that this node may be in a content where it is partially
3087f38ef08d07295967b905a61b2356ff6cdf31159Adam Momtaz     * visible due to scrolling. its clickable center maybe invisible and
3097f38ef08d07295967b905a61b2356ff6cdf31159Adam Momtaz     * adjustments should be made to the click coordinates.
3103d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
311e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @param node
3121893caed0ad4e73b0676f206282d490c2d345316Thanh Le     * @return The accessibility node info.
313e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
314e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    private AccessibilityNodeInfo getScrollableParent(AccessibilityNodeInfo node) {
315e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        AccessibilityNodeInfo parent = node;
316e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        while(parent != null) {
317e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            parent = parent.getParent();
318e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            if (parent != null && parent.isScrollable()) {
319e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                return parent;
320e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            }
321e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
322e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        return null;
323e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
324e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
325e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
3263d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * Performs a click at the center of the visible bounds of the UI element represented
32746d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * by this UiObject.
3283d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
329e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @return true id successful else false
330e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @throws UiObjectNotFoundException
331dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
332e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
333e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    public boolean click() throws UiObjectNotFoundException {
334f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine        Tracer.trace();
335e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT);
336e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        if(node == null) {
337e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            throw new UiObjectNotFoundException(getSelector().toString());
338e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
339e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        Rect rect = getVisibleBounds(node);
34008f500a92397522c48bcdad58d37ec1be95956d1Adam Momtaz        return getInteractionController().clickAndWaitForEvents(rect.centerX(), rect.centerY(),
34108f500a92397522c48bcdad58d37ec1be95956d1Adam Momtaz                WAIT_FOR_EVENT_TMEOUT, false, AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED +
34208f500a92397522c48bcdad58d37ec1be95956d1Adam Momtaz                AccessibilityEvent.TYPE_VIEW_SELECTED);
343e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
344e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
345e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
3463d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * See {@link #clickAndWaitForNewWindow(long)}
347a46ac3504426564954292b13380120e8cc6b1527Adam Momtaz     * This method is intended to reliably wait for window transitions that would typically take
348a46ac3504426564954292b13380120e8cc6b1527Adam Momtaz     * longer than the usual default timeouts.
3493d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
3503d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * @return true if the event was triggered, else false
3513d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * @throws UiObjectNotFoundException
352dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
3533d50587be8ff021369c90554d814839335b445b0Adam Momtaz     */
354e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    public boolean clickAndWaitForNewWindow() throws UiObjectNotFoundException {
355f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine        Tracer.trace();
356e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        return clickAndWaitForNewWindow(WAIT_FOR_WINDOW_TMEOUT);
357e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
358e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
359e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
36046d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * Performs a click at the center of the visible bounds of the UI element represented
36146d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * by this UiObject and waits for window transitions.
36246d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     *
3633d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * This method differ from {@link UiObject#click()} only in that this method waits for a
36446d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * a new window transition as a result of the click. Some examples of a window transition:
365e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * <li>launching a new activity</li>
366e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * <li>bringing up a pop-up menu</li>
367e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * <li>bringing up a dialog</li>
368e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     *
3693d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * @param timeout timeout before giving up on waiting for a new window
370e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @return true if the event was triggered, else false
371e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @throws UiObjectNotFoundException
372dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
373e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
374e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    public boolean clickAndWaitForNewWindow(long timeout) throws UiObjectNotFoundException {
375f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine        Tracer.trace(timeout);
376e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT);
377e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        if(node == null) {
378e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            throw new UiObjectNotFoundException(getSelector().toString());
379e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
380e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        Rect rect = getVisibleBounds(node);
3814ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz        return getInteractionController().clickAndWaitForNewWindow(
382e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                rect.centerX(), rect.centerY(), timeout);
383e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
384e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
385e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
3863d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * Clicks the top and left corner of the UI element
3873d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
388e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @return true on success
3891893caed0ad4e73b0676f206282d490c2d345316Thanh Le     * @throws UiObjectNotFoundException
390dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
391e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
392e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    public boolean clickTopLeft() throws UiObjectNotFoundException {
393f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine        Tracer.trace();
394e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT);
395e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        if(node == null) {
396e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            throw new UiObjectNotFoundException(getSelector().toString());
397e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
398e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        Rect rect = getVisibleBounds(node);
3994ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz        return getInteractionController().click(rect.left + 5, rect.top + 5);
400e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
401e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
402e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
4033d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * Long clicks bottom and right corner of the UI element
4043d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
405e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @return true if operation was successful
406e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @throws UiObjectNotFoundException
407dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
408e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
409e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    public boolean longClickBottomRight() throws UiObjectNotFoundException  {
410f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine        Tracer.trace();
411e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT);
412e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        if(node == null) {
413e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            throw new UiObjectNotFoundException(getSelector().toString());
414e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
415e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        Rect rect = getVisibleBounds(node);
416e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        return getInteractionController().longTap(rect.right - 5, rect.bottom - 5);
417e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
418e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
419e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
4203d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * Clicks the bottom and right corner of the UI element
4213d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
422e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @return true on success
4231893caed0ad4e73b0676f206282d490c2d345316Thanh Le     * @throws UiObjectNotFoundException
424dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
425e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
426e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    public boolean clickBottomRight() throws UiObjectNotFoundException {
427f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine        Tracer.trace();
428e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT);
429e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        if(node == null) {
430e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            throw new UiObjectNotFoundException(getSelector().toString());
431e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
432e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        Rect rect = getVisibleBounds(node);
4334ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz        return getInteractionController().click(rect.right - 5, rect.bottom - 5);
434e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
435e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
436e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
4373d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * Long clicks the center of the visible bounds of the UI element
4383d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
439e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @return true if operation was successful
440e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @throws UiObjectNotFoundException
441dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
442e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
443e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    public boolean longClick() throws UiObjectNotFoundException  {
444f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine        Tracer.trace();
445e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT);
446e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        if(node == null) {
447e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            throw new UiObjectNotFoundException(getSelector().toString());
448e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
449e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        Rect rect = getVisibleBounds(node);
450e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        return getInteractionController().longTap(rect.centerX(), rect.centerY());
451e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
452e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
453e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
4543d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * Long clicks on the top and left corner of the UI element
4553d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
456e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @return true if operation was successful
457e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @throws UiObjectNotFoundException
458dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
459e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
460e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    public boolean longClickTopLeft() throws UiObjectNotFoundException {
461f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine        Tracer.trace();
462e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT);
463e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        if(node == null) {
464e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            throw new UiObjectNotFoundException(getSelector().toString());
465e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
466e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        Rect rect = getVisibleBounds(node);
467e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        return getInteractionController().longTap(rect.left + 5, rect.top + 5);
468e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
469e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
470e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
4713d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * Reads the <code>text</code> property of the UI element
4723d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
473e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @return text value of the current node represented by this UiObject
474e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @throws UiObjectNotFoundException if no match could be found
475dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
476e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
477e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    public String getText() throws UiObjectNotFoundException {
478f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine        Tracer.trace();
479e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT);
480e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        if(node == null) {
481e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            throw new UiObjectNotFoundException(getSelector().toString());
482e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
483e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        String retVal = safeStringReturn(node.getText());
484e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        Log.d(LOG_TAG, String.format("getText() = %s", retVal));
485e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        return retVal;
486e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
487e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
488e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
4893d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * Reads the <code>content_desc</code> property of the UI element
4903d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
491e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @return value of node attribute "content_desc"
492e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @throws UiObjectNotFoundException
493dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
494e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
495e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    public String getContentDescription() throws UiObjectNotFoundException {
496f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine        Tracer.trace();
497e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT);
498e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        if(node == null) {
499e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            throw new UiObjectNotFoundException(getSelector().toString());
500e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
501e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        return safeStringReturn(node.getContentDescription());
502e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
503e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
504e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
50546d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * Sets the text in an editable field, after clearing the field's content.
50646d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     *
50746d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * The {@link UiSelector} selector of this object must reference a UI element that is editable.
50846d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     *
50946d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * When you call this method, the method first simulates a {@link #click()} on
51046d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * editable field to set focus. The method then clears the field's contents
51146d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * and injects your specified text into the field.
5123d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
51346d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * If you want to capture the original contents of the field, call {@link #getText()} first.
51446d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * You can then modify the text and use this method to update the field.
51546d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     *
51646d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * @param text string to set
517e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @return true if operation is successful
518e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @throws UiObjectNotFoundException
519dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
520e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
521e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    public boolean setText(String text) throws UiObjectNotFoundException {
522f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine        Tracer.trace(text);
523e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        clearTextField();
524e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        return getInteractionController().sendText(text);
525e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
526e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
527e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
52846d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * Clears the existing text contents in an editable field.
52946d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     *
53046d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * The {@link UiSelector} of this object must reference a UI element that is editable.
53146d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     *
53246d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * When you call this method, the method first sets focus at the start edge of the field.
53346d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * The method then simulates a long-press to select the existing text, and deletes the
53446d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * selected text.
53546d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     *
53646d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * If a "Select-All" option is displayed, the method will automatically attempt to use it
53746d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * to ensure full text selection.
53846d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     *
53946d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * Note that it is possible that not all the text in the field is selected; for example,
54046d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * if the text contains separators such as spaces, slashes, at symbol etc.
54146d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * Also, not all editable fields support the long-press functionality.
54246d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     *
543e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @throws UiObjectNotFoundException
544dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
545e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
546e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    public void clearTextField() throws UiObjectNotFoundException {
547f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine        Tracer.trace();
548e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        // long click left + center
549e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT);
550e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        if(node == null) {
551e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            throw new UiObjectNotFoundException(getSelector().toString());
552e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
553e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        Rect rect = getVisibleBounds(node);
554e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        getInteractionController().longTap(rect.left + 20, rect.centerY());
555e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        // check if the edit menu is open
5564ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz        UiObject selectAll = new UiObject(new UiSelector().descriptionContains("Select all"));
557e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        if(selectAll.waitForExists(50))
558e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            selectAll.click();
559e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        // wait for the selection
560e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        SystemClock.sleep(250);
561e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        // delete it
562e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        getInteractionController().sendKey(KeyEvent.KEYCODE_DEL, 0);
563e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
564e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
565e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
5663d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * Check if the UI element's <code>checked</code> property is currently true
5673d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
568e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @return true if it is else false
569dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
570e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
571e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    public boolean isChecked() throws UiObjectNotFoundException {
572f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine        Tracer.trace();
573e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT);
574e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        if(node == null) {
575e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            throw new UiObjectNotFoundException(getSelector().toString());
576e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
577e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        return node.isChecked();
578e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
579e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
580e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
5813d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * Check if the UI element's <code>selected</code> property is currently true
5823d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
583e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @return true if it is else false
584e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @throws UiObjectNotFoundException
585dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
586e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
587e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    public boolean isSelected() throws UiObjectNotFoundException {
588f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine        Tracer.trace();
589e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT);
590e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        if(node == null) {
591e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            throw new UiObjectNotFoundException(getSelector().toString());
592e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
593e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        return node.isSelected();
594e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
595e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
596e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
5973d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * Check if the UI element's <code>checkable</code> property is currently true
5983d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
599e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @return true if it is else false
600e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @throws UiObjectNotFoundException
601dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
602e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
603e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    public boolean isCheckable() throws UiObjectNotFoundException {
604f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine        Tracer.trace();
605e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT);
606e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        if(node == null) {
607e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            throw new UiObjectNotFoundException(getSelector().toString());
608e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
609e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        return node.isCheckable();
610e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
611e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
612e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
6133d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * Check if the UI element's <code>enabled</code> property is currently true
6143d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
615e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @return true if it is else false
616e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @throws UiObjectNotFoundException
617dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
618e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
619e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    public boolean isEnabled() throws UiObjectNotFoundException {
620f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine        Tracer.trace();
621e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT);
622e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        if(node == null) {
623e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            throw new UiObjectNotFoundException(getSelector().toString());
624e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
625e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        return node.isEnabled();
626e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
627e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
628e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
6293d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * Check if the UI element's <code>clickable</code> property is currently true
6303d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
631e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @return true if it is else false
632e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @throws UiObjectNotFoundException
633dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
634e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
635e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    public boolean isClickable() throws UiObjectNotFoundException {
636f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine        Tracer.trace();
637e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT);
638e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        if(node == null) {
639e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            throw new UiObjectNotFoundException(getSelector().toString());
640e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
641e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        return node.isClickable();
642e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
643e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
644e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
6453d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * Check if the UI element's <code>focused</code> property is currently true
6463d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
647e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @return true if it is else false
648e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @throws UiObjectNotFoundException
649dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
650e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
651e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    public boolean isFocused() throws UiObjectNotFoundException {
652f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine        Tracer.trace();
653e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT);
654e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        if(node == null) {
655e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            throw new UiObjectNotFoundException(getSelector().toString());
656e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
657e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        return node.isFocused();
658e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
659e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
660e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
6613d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * Check if the UI element's <code>focusable</code> property is currently true
6623d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
663e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @return true if it is else false
664e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @throws UiObjectNotFoundException
665dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
666e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
667e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    public boolean isFocusable() throws UiObjectNotFoundException {
668f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine        Tracer.trace();
669e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT);
670e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        if(node == null) {
671e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            throw new UiObjectNotFoundException(getSelector().toString());
672e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
673e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        return node.isFocusable();
674e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
675e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
676e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
6773d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * Check if the UI element's <code>scrollable</code> property is currently true
6783d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
679e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @return true if it is else false
680e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @throws UiObjectNotFoundException
681dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
682e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
683e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    public boolean isScrollable() throws UiObjectNotFoundException {
684f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine        Tracer.trace();
685e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT);
686e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        if(node == null) {
687e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            throw new UiObjectNotFoundException(getSelector().toString());
688e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
689e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        return node.isScrollable();
690e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
691e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
692e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
6933d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * Check if the UI element's <code>long-clickable</code> property is currently true
6943d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
695e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @return true if it is else false
696e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @throws UiObjectNotFoundException
697dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
698e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
699e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    public boolean isLongClickable() throws UiObjectNotFoundException {
700f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine        Tracer.trace();
701e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT);
702e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        if(node == null) {
703e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            throw new UiObjectNotFoundException(getSelector().toString());
704e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
705e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        return node.isLongClickable();
706e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
707e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
708e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
7093d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * Reads the UI element's <code>package</code> property
7103d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
7113d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * @return true if it is else false
712e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @throws UiObjectNotFoundException
713dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
714e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
715e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    public String getPackageName() throws UiObjectNotFoundException {
716f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine        Tracer.trace();
717e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT);
718e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        if(node == null) {
719e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            throw new UiObjectNotFoundException(getSelector().toString());
720e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
721e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        return safeStringReturn(node.getPackageName());
722e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
723e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
724e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
72546d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * Returns the visible bounds of the UI element.
72646d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     *
72746d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * If a portion of the UI element is visible, only the bounds of the visible portion are
72846d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * reported.
7293d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
730e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @return Rect
731e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @throws UiObjectNotFoundException
7321893caed0ad4e73b0676f206282d490c2d345316Thanh Le     * @see {@link #getBounds()}
73379693ede92636fe6f3a6ec4dc049a438fd9504ffGuang Zhu     * @since API Level 17
734e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
7353d50587be8ff021369c90554d814839335b445b0Adam Momtaz    public Rect getVisibleBounds() throws UiObjectNotFoundException {
736f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine        Tracer.trace();
737e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT);
738e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        if(node == null) {
739e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            throw new UiObjectNotFoundException(getSelector().toString());
740e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
741e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        return getVisibleBounds(node);
742e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
743e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
744e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
74546d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * Returns the UI element's <code>bounds</code> property. See {@link #getVisibleBounds()}
7463d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
7473d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * @return Rect
7483d50587be8ff021369c90554d814839335b445b0Adam Momtaz     * @throws UiObjectNotFoundException
749dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
7503d50587be8ff021369c90554d814839335b445b0Adam Momtaz     */
7513d50587be8ff021369c90554d814839335b445b0Adam Momtaz    public Rect getBounds() throws UiObjectNotFoundException {
752f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine        Tracer.trace();
7533d50587be8ff021369c90554d814839335b445b0Adam Momtaz        AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT);
7543d50587be8ff021369c90554d814839335b445b0Adam Momtaz        if(node == null) {
7553d50587be8ff021369c90554d814839335b445b0Adam Momtaz            throw new UiObjectNotFoundException(getSelector().toString());
7563d50587be8ff021369c90554d814839335b445b0Adam Momtaz        }
7573d50587be8ff021369c90554d814839335b445b0Adam Momtaz        Rect nodeRect = new Rect();
7583d50587be8ff021369c90554d814839335b445b0Adam Momtaz        node.getBoundsInScreen(nodeRect);
7593d50587be8ff021369c90554d814839335b445b0Adam Momtaz
7603d50587be8ff021369c90554d814839335b445b0Adam Momtaz        return nodeRect;
7613d50587be8ff021369c90554d814839335b445b0Adam Momtaz    }
7623d50587be8ff021369c90554d814839335b445b0Adam Momtaz
7633d50587be8ff021369c90554d814839335b445b0Adam Momtaz    /**
76446d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * Waits a specified length of time for a UI element to become visible.
76546d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     *
76646d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * This method waits until the UI element becomes visible on the display, or
76746d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * until the timeout has elapsed. You can use this method in situations where
76846d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * the content that you want to select is not immediately displayed.
7693d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
77046d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * @param timeout the amount of time to wait (in milliseconds)
77146d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * @return true if the UI element is displayed, else false if timeout elapsed while waiting
772dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
773e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
774e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    public boolean waitForExists(long timeout) {
775f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine        Tracer.trace(timeout);
776e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        if(findAccessibilityNodeInfo(timeout) != null) {
777e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            return true;
778e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
779e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        return false;
780e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
781e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
782e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
78346d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * Waits a specified length of time for a UI element to become undetectable.
7843d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
78546d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * This method waits until a UI element is no longer matchable, or until the
78646d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * timeout has elapsed.
78746d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     *
78846d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * A UI element becomes undetectable when the {@link UiSelector} of the object is
78946d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * unable to find a match because the element has either changed its state or is no
79046d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * longer displayed.
79146d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     *
79246d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * You can use this method when attempting to wait for some long operation
79346d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * to compete, such as downloading a large file or connecting to a remote server.
79446d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     *
79546d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * @param timeout time to wait (in milliseconds)
79646d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * @return true if the element is gone before timeout elapsed, else false if timeout elapsed
79746d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * but a matching element is still found.
798dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
799e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
800e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    public boolean waitUntilGone(long timeout) {
801f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine        Tracer.trace(timeout);
802e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        long startMills = SystemClock.uptimeMillis();
803e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        long currentMills = 0;
804e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        while (currentMills <= timeout) {
805e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            if(findAccessibilityNodeInfo(0) == null)
806e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                return true;
807e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            currentMills = SystemClock.uptimeMillis() - startMills;
808e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            if(timeout > 0)
809e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                SystemClock.sleep(WAIT_FOR_SELECTOR_POLL);
810e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
811e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        return false;
812e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
813e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
814e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
81546d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     * Check if UI element exists.
81646d9444c7a39dc1c9fc60a5dcf4e79749d9b3859Adam Momtaz     *
817e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * This methods performs a {@link #waitForExists(long)} with zero timeout. This
818e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * basically returns immediately whether the UI element represented by this UiObject
819e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * exists or not. If you need to wait longer for this UI element, then see
820e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * {@link #waitForExists(long)}.
8213d50587be8ff021369c90554d814839335b445b0Adam Momtaz     *
822e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @return true if the UI element represented by this UiObject does exist
823dbba713661688a285e701a006ce2d199296ac328Guang Zhu     * @since API Level 16
824e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
825e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    public boolean exists() {
826f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine        Tracer.trace();
827e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        return waitForExists(0);
828e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
829e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
830e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    private String safeStringReturn(CharSequence cs) {
831e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        if(cs == null)
832e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            return "";
833e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        return cs.toString();
834e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
835e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu}
836