UiScrollable.java revision e54d649fb83a0a44516e5c25a9ac1992c8950e59
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 Zhupackage com.android.uiautomator.core;
17e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
18e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhuimport android.graphics.Rect;
19e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhuimport android.util.Log;
20e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhuimport android.view.accessibility.AccessibilityNodeInfo;
21e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
22e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu/**
23e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * UiScrollable is a {@link UiCollection} however this class provides additional functionality
24e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * where the tests need to deal with scrollable contents or desire to enumerate lists of
25e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * items. This calls can perform automatic searches within a scrollable container. Whether
26e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * the content scrolls vertically or horizontally can be set by calling
27e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * {@link #setAsVerticalList()} which is the default, or {@link #setAsHorizontalList()}.
28e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */
29e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhupublic class UiScrollable extends UiCollection {
30e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    private static final String LOG_TAG = UiScrollable.class.getSimpleName();
31e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
32e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    // More steps slows the swipe and prevents contents from being flung too far
33e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    private static final int SCROLL_STEPS = 55;
34e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
35e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    private static final int FLING_STEPS = 5;
36e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
37e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    // Restrict a swipe's starting and ending points inside a 10% margin of the target
38e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    private static final double DEFAULT_SWIPE_DEADZONE_PCT = 0.1;
39e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
40e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    // Limits the number of swipes/scrolls performed during a search
41e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    private static int mMaxSearchSwipes = 30;
42e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
43e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    // Used in ScrollForward() and ScrollBackward() to determine swipe direction
44e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    protected boolean mIsVerticalList = true;
45e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
46e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    private double mSwipeDeadZonePercentage = DEFAULT_SWIPE_DEADZONE_PCT;
47e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
48e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
49e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * UiScrollable is a {@link UiCollection} and as such requires a {@link By} selector to identify
50e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * the UI element it represents. In the case of UiScrollable, the selector specified is
51e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * considered a container where further calls to enumerate or find children will be performed
52e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * in.
53e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @param container a {@link By} selector
54e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
55e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    public UiScrollable(By container) {
56e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        // wrap the container selector with container so that QueryController can handle
57e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        // this type of enumeration search accordingly
58e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        super(container);
59e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
60e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
61e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
62e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * Set the direction of swipes when performing scroll search
63e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
64e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    public void setAsVerticalList() {
65e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        mIsVerticalList = true;
66e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
67e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
68e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
69e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * Set the direction of swipes when performing scroll search
70e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
71e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    public void setAsHorizontalList() {
72e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        mIsVerticalList = false;
73e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
74e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
75e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
76e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * Used privately when performing swipe searches to decide if an element has become
77e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * visible or not.
78e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @param selector
79e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @return true if found else false
80e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
81e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    protected boolean exists(By selector) {
82e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        if(getQueryController().findAccessibilityNodeInfo(selector) != null) {
83e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            return true;
84e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
85e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        return false;
86e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
87e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
88e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
89e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * Searches for child UI element within the constraints of this UiScrollable {@link By}
90e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * selector. It looks for any child matching the <code>childPattern</code> argument that has
91e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * a child UI element anywhere within its sub hierarchy that has content-description text.
92e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * The returned UiObject will point at the <code>childPattern</code> instance that matched the
93e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * search and not at the identifying child element that matched the content description.</p>
94e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * By default this operation will perform scroll search while attempting to find the
95e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * UI element.
96e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * See {@link #getChildByDescription(By, String, boolean)}
97e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @param childPattern {@link By} selector of the child pattern to match and return
98e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @param text String of the identifying child contents of of the <code>childPattern</code>
99e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @return {@link UiObject} pointing at and instance of <code>childPattern</code>
100e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @throws UiObjectNotFoundException
101e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
102e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    @Override
103e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    public UiObject getChildByDescription(By childPattern, String text)
104e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            throws UiObjectNotFoundException {
105e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        return getChildByDescription(childPattern, text, true);
106e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
107e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
108e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
109e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * Searches for child UI element within the constraints of this UiScrollable {@link By}
110e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * selector. It looks for any child matching the <code>childPattern</code> argument that has
111e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * a child UI element anywhere within its sub hierarchy that has content-description text.
112e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * The returned UiObject will point at the <code>childPattern</code> instance that matched the
113e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * search and not at the identifying child element that matched the content description.
114e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @param childPattern {@link By} selector of the child pattern to match and return
115e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @param text String may be a partial match for the content-description of a child element.
116e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @param allowScrollSearch set to true if scrolling is allowed
117e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @return {@link UiObject} pointing at and instance of <code>childPattern</code>
118e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @throws UiObjectNotFoundException
119e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
120e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    public UiObject getChildByDescription(By childPattern, String text, boolean allowScrollSearch)
121e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            throws UiObjectNotFoundException {
122e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        if (text != null) {
123e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            if (allowScrollSearch) {
124e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                scrollIntoView(By.selector().descriptionContains(text));
125e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            }
126e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            return super.getChildByDescription(childPattern, text);
127e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
128e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        throw new UiObjectNotFoundException("for description= \"" + text + "\"");
129e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
130e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
131e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
132e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * Searches for child UI element within the constraints of this UiScrollable {@link By}
133e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * selector. It looks for any child matching the <code>childPattern</code> argument and
134e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * return the <code>instance</code> specified. The operation is performed only on the visible
135e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * items and no scrolling is performed in this case.
136e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @param childPattern {@link By} selector of the child pattern to match and return
137e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @param instance int the desired matched instance of this <code>childPattern</code>
138e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @return {@link UiObject} pointing at and instance of <code>childPattern</code>
139e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
140e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    @Override
141e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    public UiObject getChildByInstance(By childPattern, int instance)
142e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            throws UiObjectNotFoundException {
143e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        By patternSelector = By.patternBuilder(getSelector(),
144e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                By.patternBuilder(childPattern).instance(instance));
145e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        return new UiObject(patternSelector);
146e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
147e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
148e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
149e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * Searches for child UI element within the constraints of this UiScrollable {@link By}
150e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * selector. It looks for any child matching the <code>childPattern</code> argument that has
151e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * a child UI element anywhere within its sub hierarchy that has text attribute =
152e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * <code>text</code>. The returned UiObject will point at the <code>childPattern</code>
153e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * instance that matched the search and not at the identifying child element that matched the
154e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * text attribute.</p>
155e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * By default this operation will perform scroll search while attempting to find the UI
156e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * element.
157e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * See {@link #getChildByText(By, String, boolean)}
158e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @param childPattern {@link By} selector of the child pattern to match and return
159e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @param text String of the identifying child contents of of the <code>childPattern</code>
160e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @return {@link UiObject} pointing at and instance of <code>childPattern</code>
161e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @throws UiObjectNotFoundException
162e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
163e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    @Override
164e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    public UiObject getChildByText(By childPattern, String text)
165e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            throws UiObjectNotFoundException {
166e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        return getChildByText(childPattern, text, true);
167e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
168e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
169e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
170e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * Searches for child UI element within the constraints of this UiScrollable {@link By}
171e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * selector. It looks for any child matching the <code>childPattern</code> argument that has
172e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * a child UI element anywhere within its sub hierarchy that has the text attribute =
173e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * <code>text</code>.
174e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * The returned UiObject will point at the <code>childPattern</code> instance that matched the
175e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * search and not at the identifying child element that matched the text attribute.
176e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @param childPattern {@link By} selector of the child pattern to match and return
177e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @param text String of the identifying child contents of of the <code>childPattern</code>
178e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @param allowScrollSearch set to true if scrolling is allowed
179e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @return {@link UiObject} pointing at and instance of <code>childPattern</code>
180e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @throws UiObjectNotFoundException
181e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
182e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    public UiObject getChildByText(By childPattern, String text, boolean allowScrollSearch)
183e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            throws UiObjectNotFoundException {
184e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
185e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        if (text != null) {
186e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            if (allowScrollSearch) {
187e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                scrollIntoView(By.selector().text(text));
188e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            }
189e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            return super.getChildByText(childPattern, text);
190e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
191e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        throw new UiObjectNotFoundException("for text= \"" + text + "\"");
192e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
193e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
194e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
195e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * Performs a swipe Up on the associated UI element until the requested content-description
196e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * is found or until swipe attempts have been exhausted. See {@link #setMaxSearchSwipes(int)}
197e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @param text to look for anywhere within the contents of this scrollable.
198e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @return true if item us found else false
199e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
200e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    public boolean scrollDescriptionIntoView(String text) {
201e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        return scrollIntoView(By.selector().description(text));
202e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
203e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
204e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
205e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * Perform a scroll search for a UI element matching the {@link By} selector argument. Also
206e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * see {@link #scrollDescriptionIntoView(String)} and {@link #scrollTextIntoView(String)}.
207e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @param selector {@link By} selector
208e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @return true if the item was found and now is in view else false
209e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
210e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    public boolean scrollIntoView(By selector) {
211e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        // if we happen to be on top of the text we want then return here
212e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        if (exists(getSelector().childSelector(selector))) {
213e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            return (true);
214e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        } else {
215e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            // we will need to reset the search from the beginning to start search
216e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            scrollToBeginning(mMaxSearchSwipes);
217e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            if (exists(getSelector().childSelector(selector))) {
218e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                return (true);
219e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            }
220e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            for (int x = 0; x < mMaxSearchSwipes; x++) {
221e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                if(!scrollForward()) {
222e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                    return false;
223e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                }
224e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
225e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                if(exists(getSelector().childSelector(selector))) {
226e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                    return true;
227e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                }
228e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            }
229e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
230e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        return false;
231e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
232e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
233e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
234e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * Performs a swipe up on the associated display element until the requested text
235e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * appears or until swipe attempts have been exhausted. See {@link #setMaxSearchSwipes(int)}
236e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @param text to look for
237e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @return true if item us found else false
238e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
239e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    public boolean scrollTextIntoView(String text) {
240e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        return scrollIntoView(By.selector().text(text));
241e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
242e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
243e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
244e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * {@link #getChildByDescription(String, boolean)} and {@link #getChildByText(String, boolean)}
245e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * use an arguments that specifies if scrolling is allowed while searching for the UI element.
246e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * The number of scrolls allowed to perform a search can be modified by this method.
247e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * The current value can be read by calling {@link #getMaxSearchSwipes()}
248e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @param swipes
249e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
250e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    public void setMaxSearchSwipes(int swipes) {
251e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        mMaxSearchSwipes = swipes;
252e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
253e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
254e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
255e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * {@link #getChildByDescription(String, boolean)} and {@link #getChildByText(String, boolean)}
256e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * use an arguments that specifies if scrolling is allowed while searching for the UI element.
257e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * The number of scrolls currently allowed to perform a search can be read by this method.
258e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * See {@link #setMaxSearchSwipes(int)}
259e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @return max value of the number of swipes currently allowed during a scroll search
260e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
261e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    public int getMaxSearchSwipes() {
262e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        return mMaxSearchSwipes;
263e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
264e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
265e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
266e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * A convenience version of {@link UiScrollable#scrollForward(int)}, performs a fling
267e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     *
268e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @return true if scrolled and false if can't scroll anymore
269e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
270e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    public boolean flingForward() {
271e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        return scrollForward(FLING_STEPS);
272e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
273e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
274e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
275e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * A convenience version of {@link UiScrollable#scrollForward(int)}, performs a regular scroll
276e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     *
277e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @return true if scrolled and false if can't scroll anymore
278e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
279e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    public boolean scrollForward() {
280e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        return scrollForward(SCROLL_STEPS);
281e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
282e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
283e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
284e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * Perform a scroll forward. If this list is set to vertical (see {@link #setAsVerticalList()}
285e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * default) then the swipes will be executed from the bottom to top. If this list is set
286e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * to horizontal (see {@link #setAsHorizontalList()}) then the swipes will be executed from
287e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * the right to left.
288e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     *
289e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @param steps use steps to control the speed, so that it may be a scroll, or fling
290e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @return true if scrolled and false if can't scroll anymore
291e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
292e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    public boolean scrollForward(int steps) {
293e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        Log.d(LOG_TAG, "scrollForward() on selector = " + getSelector());
294e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT);
295e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        if(node == null) {
296e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            // Object Not Found
297e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            return false;
298e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
299e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        Rect rect = new Rect();;
300e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        node.getBoundsInScreen(rect);
301e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
302e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        int downX = 0;
303e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        int downY = 0;
304e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        int upX = 0;
305e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        int upY = 0;
306e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
307e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        // scrolling is by default assumed vertically unless the object is explicitly
308e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        // set otherwise by setAsHorizontalContainer()
309e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        if(mIsVerticalList) {
310e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            int swipeAreaAdjust = (int)(rect.height() * getSwipeDeadZonePercentage());
311e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            // scroll vertically: swipe down -> up
312e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            downX = rect.centerX();
313e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            downY = rect.bottom - swipeAreaAdjust;
314e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            upX = rect.centerX();
315e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            upY = rect.top + swipeAreaAdjust;
316e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        } else {
317e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            int swipeAreaAdjust = (int)(rect.width() * getSwipeDeadZonePercentage());
318e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            // scroll horizontally: swipe right -> left
319e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            // TODO: Assuming device is not in right to left language
320e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            downX = rect.right - swipeAreaAdjust;
321e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            downY = rect.centerY();
322e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            upX = rect.left + swipeAreaAdjust;
323e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            upY = rect.centerY();
324e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
325e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        return getInteractionController().scrollSwipe(downX, downY, upX, upY, steps);
326e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
327e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
328e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
329e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * A convenience version of {@link UiScrollable#scrollBackward(int)}, performs a fling
330e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     *
331e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @return true if scrolled and false if can't scroll anymore
332e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
333e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    public boolean flingBackward() {
334e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        return scrollBackward(FLING_STEPS);
335e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
336e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
337e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
338e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * A convenience version of {@link UiScrollable#scrollBackward(int)}, performs a regular scroll
339e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     *
340e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @return true if scrolled and false if can't scroll anymore
341e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
342e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    public boolean scrollBackward() {
343e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        return scrollBackward(SCROLL_STEPS);
344e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
345e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
346e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
347e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * Perform a scroll backward. If this list is set to vertical (see {@link #setAsVerticalList()}
348e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * default) then the swipes will be executed from the top to bottom. If this list is set
349e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * to horizontal (see {@link #setAsHorizontalList()}) then the swipes will be executed from
350e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * the left to right.
351e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     *
352e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @param steps use steps to control the speed, so that it may be a scroll, or fling
353e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @return true if scrolled and false if can't scroll anymore
354e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
355e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    public boolean scrollBackward(int steps) {
356e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        Log.d(LOG_TAG, "scrollBackward() on selector = " + getSelector());
357e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT);
358e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        if(node == null) {
359e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            // Object Not Found
360e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            return false;
361e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
362e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        Rect rect = new Rect();;
363e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        node.getBoundsInScreen(rect);
364e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
365e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        int downX = 0;
366e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        int downY = 0;
367e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        int upX = 0;
368e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        int upY = 0;
369e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
370e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        // scrolling is by default assumed vertically unless the object is explicitly
371e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        // set otherwise by setAsHorizontalContainer()
372e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        if(mIsVerticalList) {
373e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            int swipeAreaAdjust = (int)(rect.height() * getSwipeDeadZonePercentage());
374e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            Log.d(LOG_TAG, "scrollToBegining() using vertical scroll");
375e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            // scroll vertically: swipe up -> down
376e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            downX = rect.centerX();
377e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            downY = rect.top + swipeAreaAdjust;
378e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            upX = rect.centerX();
379e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            upY = rect.bottom - swipeAreaAdjust;
380e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        } else {
381e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            int swipeAreaAdjust = (int)(rect.width() * getSwipeDeadZonePercentage());
382e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            Log.d(LOG_TAG, "scrollToBegining() using hotizontal scroll");
383e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            // scroll horizontally: swipe left -> right
384e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            // TODO: Assuming device is not in right to left language
385e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            downX = rect.left + swipeAreaAdjust;
386e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            downY = rect.centerY();
387e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            upX = rect.right - swipeAreaAdjust;
388e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            upY = rect.centerY();
389e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
390e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        return getInteractionController().scrollSwipe(downX, downY, upX, upY, steps);
391e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
392e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
393e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
394e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * Scrolls to the beginning of a scrollable UI element. The beginning could be the top most
395e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * in case of vertical lists or the left most in case of horizontal lists.
396e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     *
397e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @param steps use steps to control the speed, so that it may be a scroll, or fling
398e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @return true on scrolled else false
399e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
400e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    public boolean scrollToBeginning(int maxSwipes, int steps) {
401e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        Log.d(LOG_TAG, "scrollToBeginning() on selector = " + getSelector());
402e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        // protect against potential hanging and return after preset attempts
403e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        for(int x = 0; x < maxSwipes; x++) {
404e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            if(!scrollBackward(steps)) {
405e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                break;
406e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            }
407e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
408e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        return true;
409e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
410e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
411e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
412e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * A convenience version of {@link UiScrollable#scrollToBeginning(int, int)} with regular scroll
413e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     *
414e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @param maxSwipes
415e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @return true on scrolled else false
416e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
417e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    public boolean scrollToBeginning(int maxSwipes) {
418e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        return scrollToBeginning(maxSwipes, SCROLL_STEPS);
419e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
420e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
421e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
422e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * A convenience version of {@link UiScrollable#scrollToBeginning(int, int)} with fling
423e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     *
424e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @param maxSwipes
425e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @return true on scrolled else false
426e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
427e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    public boolean flingToBeginning(int maxSwipes) {
428e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        return scrollToBeginning(maxSwipes, FLING_STEPS);
429e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
430e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
431e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
432e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * Scrolls to the end of a scrollable UI element. The end could be the bottom most
433e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * in case of vertical controls or the right most for horizontal controls
434e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     *
435e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @param steps use steps to control the speed, so that it may be a scroll, or fling
436e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @return true on scrolled else false
437e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
438e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    public boolean scrollToEnd(int maxSwipes, int steps) {
439e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        // protect against potential hanging and return after preset attempts
440e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        for(int x = 0; x < maxSwipes; x++) {
441e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            if(!scrollForward(steps)) {
442e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu                break;
443e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu            }
444e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        }
445e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        return true;
446e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
447e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
448e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
449e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * A convenience version of {@link UiScrollable#scrollToEnd(int, int)} with regular scroll
450e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     *
451e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @param maxSwipes
452e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @return true on scrolled else false
453e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
454e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    public boolean scrollToEnd(int maxSwipes) {
455e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        return scrollToEnd(maxSwipes, SCROLL_STEPS);
456e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
457e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
458e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    /**
459e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * A convenience version of {@link UiScrollable#scrollToEnd(int, int)} with fling
460e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     *
461e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @param maxSwipes
462e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     * @return true on scrolled else false
463e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu     */
464e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    public boolean flingToEnd(int maxSwipes) {
465e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        return scrollToEnd(maxSwipes, FLING_STEPS);
466e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
467e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
468e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    public double getSwipeDeadZonePercentage() {
469e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        return mSwipeDeadZonePercentage;
470e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
471e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu
472e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    public void setSwipeDeadZonePercentage(double swipeDeadZonePercentage) {
473e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu        mSwipeDeadZonePercentage = swipeDeadZonePercentage;
474e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu    }
475e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu}
476