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/** 233d50587be8ff021369c90554d814839335b445b0Adam Momtaz * UiScrollable is a {@link UiCollection} and provides support for searching for items in a 243d50587be8ff021369c90554d814839335b445b0Adam Momtaz * scrollable UI elements. Used with horizontally or vertically scrollable UI. 25e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 26e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhupublic class UiScrollable extends UiCollection { 27e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu private static final String LOG_TAG = UiScrollable.class.getSimpleName(); 28e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 29e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // More steps slows the swipe and prevents contents from being flung too far 30e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu private static final int SCROLL_STEPS = 55; 31e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 32e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu private static final int FLING_STEPS = 5; 33e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 34e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // Restrict a swipe's starting and ending points inside a 10% margin of the target 35e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu private static final double DEFAULT_SWIPE_DEADZONE_PCT = 0.1; 36e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 37e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // Limits the number of swipes/scrolls performed during a search 38e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu private static int mMaxSearchSwipes = 30; 39e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 40e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // Used in ScrollForward() and ScrollBackward() to determine swipe direction 41f612e6a05f47b28ae0f5715545658c08dd759dd7Guang Zhu private boolean mIsVerticalList = true; 42e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 43e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu private double mSwipeDeadZonePercentage = DEFAULT_SWIPE_DEADZONE_PCT; 44e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 45e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 463d50587be8ff021369c90554d814839335b445b0Adam Momtaz * UiScrollable is a {@link UiCollection} and as such requires a {@link UiSelector} to 473d50587be8ff021369c90554d814839335b445b0Adam Momtaz * identify the container UI element of the scrollable collection. Further operations on 483d50587be8ff021369c90554d814839335b445b0Adam Momtaz * the items in the container will require specifying UiSelector as an item selector. 493d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 504ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz * @param container a {@link UiSelector} selector 51e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 524ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz public UiScrollable(UiSelector container) { 53e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // wrap the container selector with container so that QueryController can handle 54e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // this type of enumeration search accordingly 55e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu super(container); 56e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 57e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 58e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 59e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * Set the direction of swipes when performing scroll search 60ee4b48cd50f6e4e24ba7f538b8a77c839c1087f5Adam Momtaz * @return reference to itself 61e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 62ee4b48cd50f6e4e24ba7f538b8a77c839c1087f5Adam Momtaz public UiScrollable setAsVerticalList() { 63e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu mIsVerticalList = true; 64ee4b48cd50f6e4e24ba7f538b8a77c839c1087f5Adam Momtaz return this; 65e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 66e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 67e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 68e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * Set the direction of swipes when performing scroll search 69ee4b48cd50f6e4e24ba7f538b8a77c839c1087f5Adam Momtaz * @return reference to itself 70e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 71ee4b48cd50f6e4e24ba7f538b8a77c839c1087f5Adam Momtaz public UiScrollable setAsHorizontalList() { 72e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu mIsVerticalList = false; 73ee4b48cd50f6e4e24ba7f538b8a77c839c1087f5Adam Momtaz return this; 74e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 75e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 76e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 77e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * Used privately when performing swipe searches to decide if an element has become 78e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * visible or not. 793d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 80e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @param selector 81e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if found else false 82e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 834ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz protected boolean exists(UiSelector selector) { 84e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(getQueryController().findAccessibilityNodeInfo(selector) != null) { 85e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return true; 86e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 87e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return false; 88e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 89e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 90e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 914ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz * Searches for child UI element within the constraints of this UiScrollable {@link UiSelector} 923d50587be8ff021369c90554d814839335b445b0Adam Momtaz * container. It looks for any child matching the <code>childPattern</code> argument within its 933d50587be8ff021369c90554d814839335b445b0Adam Momtaz * hierarchy with a matching content-description text. The returned UiObject will represent the 943d50587be8ff021369c90554d814839335b445b0Adam Momtaz * UI element matching the <code>childPattern</code> and not the sub element that matched the 953d50587be8ff021369c90554d814839335b445b0Adam Momtaz * content description.</p> 963d50587be8ff021369c90554d814839335b445b0Adam Momtaz * By default this operation will perform scroll search while attempting to find the UI element 974ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz * See {@link #getChildByDescription(UiSelector, String, boolean)} 983d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 994ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz * @param childPattern {@link UiSelector} selector of the child pattern to match and return 100e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @param text String of the identifying child contents of of the <code>childPattern</code> 101e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return {@link UiObject} pointing at and instance of <code>childPattern</code> 102e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 103e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 104e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu @Override 1054ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz public UiObject getChildByDescription(UiSelector childPattern, String text) 106e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throws UiObjectNotFoundException { 107e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return getChildByDescription(childPattern, text, true); 108e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 109e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 110e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 1113d50587be8ff021369c90554d814839335b445b0Adam Momtaz * See {@link #getChildByDescription(UiSelector, String)} 1123d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 1134ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz * @param childPattern {@link UiSelector} selector of the child pattern to match and return 114e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @param text String may be a partial match for the content-description of a child element. 115e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @param allowScrollSearch set to true if scrolling is allowed 116e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return {@link UiObject} pointing at and instance of <code>childPattern</code> 117e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 118e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 1194ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz public UiObject getChildByDescription(UiSelector childPattern, String text, 1204ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz boolean allowScrollSearch) throws UiObjectNotFoundException { 121e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if (text != null) { 122e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if (allowScrollSearch) { 1234ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz scrollIntoView(new UiSelector().descriptionContains(text)); 124e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 125e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return super.getChildByDescription(childPattern, text); 126e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 127e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException("for description= \"" + text + "\""); 128e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 129e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 130e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 1314ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz * Searches for child UI element within the constraints of this UiScrollable {@link UiSelector} 132e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * selector. It looks for any child matching the <code>childPattern</code> argument and 133e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * return the <code>instance</code> specified. The operation is performed only on the visible 134e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * items and no scrolling is performed in this case. 1353d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 1364ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz * @param childPattern {@link UiSelector} 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 1414ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz public UiObject getChildByInstance(UiSelector childPattern, int instance) 142e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throws UiObjectNotFoundException { 1434ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz UiSelector patternSelector = UiSelector.patternBuilder(getSelector(), 1444ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz UiSelector.patternBuilder(childPattern).instance(instance)); 145e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return new UiObject(patternSelector); 146e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 147e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 148e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 1494ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz * Searches for child UI element within the constraints of this UiScrollable {@link UiSelector} 1503d50587be8ff021369c90554d814839335b445b0Adam Momtaz * container. It looks for any child matching the <code>childPattern</code> argument that has 1513d50587be8ff021369c90554d814839335b445b0Adam Momtaz * a sub 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> 1533d50587be8ff021369c90554d814839335b445b0Adam Momtaz * instance that matched the search and not at the text matched sub element</p> 154e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * By default this operation will perform scroll search while attempting to find the UI 155e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * element. 1564ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz * See {@link #getChildByText(UiSelector, String, boolean)} 1573d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 1584ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz * @param childPattern {@link UiSelector} 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 1644ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz public UiObject getChildByText(UiSelector childPattern, String text) 165e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throws UiObjectNotFoundException { 166e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return getChildByText(childPattern, text, true); 167e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 168e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 169e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 1703d50587be8ff021369c90554d814839335b445b0Adam Momtaz * See {@link #getChildByText(UiSelector, String)} 1713d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 1724ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz * @param childPattern {@link UiSelector} selector of the child pattern to match and return 173e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @param text String of the identifying child contents of of the <code>childPattern</code> 174e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @param allowScrollSearch set to true if scrolling is allowed 175e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return {@link UiObject} pointing at and instance of <code>childPattern</code> 176e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 177e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 1784ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz public UiObject getChildByText(UiSelector childPattern, String text, boolean allowScrollSearch) 179e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throws UiObjectNotFoundException { 180e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 181e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if (text != null) { 182e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if (allowScrollSearch) { 1834ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz scrollIntoView(new UiSelector().text(text)); 184e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 185e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return super.getChildByText(childPattern, text); 186e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 187e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException("for text= \"" + text + "\""); 188e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 189e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 190e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 1913d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Performs a swipe Up on the UI element until the requested content-description 1923d50587be8ff021369c90554d814839335b445b0Adam Momtaz * is visible or until swipe attempts have been exhausted. See {@link #setMaxSearchSwipes(int)} 1933d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 194e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @param text to look for anywhere within the contents of this scrollable. 195e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if item us found else false 196e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 1976b6adccb07300778cd665ca83c0e3672d97de41dGuang Zhu public boolean scrollDescriptionIntoView(String text) throws UiObjectNotFoundException { 1984ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz return scrollIntoView(new UiSelector().description(text)); 199e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 200e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 201e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 2024ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz * Perform a scroll search for a UI element matching the {@link UiSelector} selector argument. 2033d50587be8ff021369c90554d814839335b445b0Adam Momtaz * See {@link #scrollDescriptionIntoView(String)} and {@link #scrollTextIntoView(String)}. 2043d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 205ee4b48cd50f6e4e24ba7f538b8a77c839c1087f5Adam Momtaz * @param obj {@link UiObject} 206ee4b48cd50f6e4e24ba7f538b8a77c839c1087f5Adam Momtaz * @return true if the item was found and now is in view else false 207ee4b48cd50f6e4e24ba7f538b8a77c839c1087f5Adam Momtaz */ 208ee4b48cd50f6e4e24ba7f538b8a77c839c1087f5Adam Momtaz public boolean scrollIntoView(UiObject obj) throws UiObjectNotFoundException { 209ee4b48cd50f6e4e24ba7f538b8a77c839c1087f5Adam Momtaz return scrollIntoView(obj.getSelector()); 210ee4b48cd50f6e4e24ba7f538b8a77c839c1087f5Adam Momtaz } 211ee4b48cd50f6e4e24ba7f538b8a77c839c1087f5Adam Momtaz 212ee4b48cd50f6e4e24ba7f538b8a77c839c1087f5Adam Momtaz /** 213ee4b48cd50f6e4e24ba7f538b8a77c839c1087f5Adam Momtaz * Perform a scroll search for a UI element matching the {@link UiSelector} selector argument. 214ee4b48cd50f6e4e24ba7f538b8a77c839c1087f5Adam Momtaz * See {@link #scrollDescriptionIntoView(String)} and {@link #scrollTextIntoView(String)}. 215ee4b48cd50f6e4e24ba7f538b8a77c839c1087f5Adam Momtaz * 2164ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz * @param selector {@link UiSelector} selector 217e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if the item was found and now is in view else false 218e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 2196b6adccb07300778cd665ca83c0e3672d97de41dGuang Zhu public boolean scrollIntoView(UiSelector selector) throws UiObjectNotFoundException { 220e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // if we happen to be on top of the text we want then return here 221e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if (exists(getSelector().childSelector(selector))) { 222e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return (true); 223e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } else { 224e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // we will need to reset the search from the beginning to start search 225e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu scrollToBeginning(mMaxSearchSwipes); 226e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if (exists(getSelector().childSelector(selector))) { 227e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return (true); 228e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 229e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu for (int x = 0; x < mMaxSearchSwipes; x++) { 230e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(!scrollForward()) { 231e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return false; 232e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 233e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 234e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(exists(getSelector().childSelector(selector))) { 235e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return true; 236e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 237e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 238e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 239e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return false; 240e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 241e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 242e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 2433d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Performs a swipe up on the UI element until the requested text is visible 2443d50587be8ff021369c90554d814839335b445b0Adam Momtaz * or until swipe attempts have been exhausted. See {@link #setMaxSearchSwipes(int)} 2453d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 246e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @param text to look for 247e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if item us found else false 248e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 2496b6adccb07300778cd665ca83c0e3672d97de41dGuang Zhu public boolean scrollTextIntoView(String text) throws UiObjectNotFoundException { 2504ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz return scrollIntoView(new UiSelector().text(text)); 251e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 252e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 253e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 254e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * {@link #getChildByDescription(String, boolean)} and {@link #getChildByText(String, boolean)} 255e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * use an arguments that specifies if scrolling is allowed while searching for the UI element. 256e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * The number of scrolls allowed to perform a search can be modified by this method. 257e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * The current value can be read by calling {@link #getMaxSearchSwipes()} 2583d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 2593d50587be8ff021369c90554d814839335b445b0Adam Momtaz * @param swipes is the number of search swipes until abort 260ee4b48cd50f6e4e24ba7f538b8a77c839c1087f5Adam Momtaz * @return reference to itself 261e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 262ee4b48cd50f6e4e24ba7f538b8a77c839c1087f5Adam Momtaz public UiScrollable setMaxSearchSwipes(int swipes) { 263e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu mMaxSearchSwipes = swipes; 264ee4b48cd50f6e4e24ba7f538b8a77c839c1087f5Adam Momtaz return this; 265e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 266e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 267e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 268e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * {@link #getChildByDescription(String, boolean)} and {@link #getChildByText(String, boolean)} 269e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * use an arguments that specifies if scrolling is allowed while searching for the UI element. 270e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * The number of scrolls currently allowed to perform a search can be read by this method. 271e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * See {@link #setMaxSearchSwipes(int)} 2723d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 273e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return max value of the number of swipes currently allowed during a scroll search 274e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 275e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public int getMaxSearchSwipes() { 276e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return mMaxSearchSwipes; 277e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 278e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 279e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 280e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * A convenience version of {@link UiScrollable#scrollForward(int)}, performs a fling 281e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * 282e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if scrolled and false if can't scroll anymore 283e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 2846b6adccb07300778cd665ca83c0e3672d97de41dGuang Zhu public boolean flingForward() throws UiObjectNotFoundException { 285e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return scrollForward(FLING_STEPS); 286e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 287e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 288e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 289e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * A convenience version of {@link UiScrollable#scrollForward(int)}, performs a regular scroll 290e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * 291e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if scrolled and false if can't scroll anymore 292e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 2936b6adccb07300778cd665ca83c0e3672d97de41dGuang Zhu public boolean scrollForward() throws UiObjectNotFoundException { 294e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return scrollForward(SCROLL_STEPS); 295e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 296e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 297e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 298e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * Perform a scroll forward. If this list is set to vertical (see {@link #setAsVerticalList()} 299e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * default) then the swipes will be executed from the bottom to top. If this list is set 300e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * to horizontal (see {@link #setAsHorizontalList()}) then the swipes will be executed from 3013d50587be8ff021369c90554d814839335b445b0Adam Momtaz * the right to left. Caution is required on devices configured with right to left languages 3023d50587be8ff021369c90554d814839335b445b0Adam Momtaz * like Arabic and Hebrew. 303e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * 304e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @param steps use steps to control the speed, so that it may be a scroll, or fling 305e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if scrolled and false if can't scroll anymore 306e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 3076b6adccb07300778cd665ca83c0e3672d97de41dGuang Zhu public boolean scrollForward(int steps) throws UiObjectNotFoundException { 308e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu Log.d(LOG_TAG, "scrollForward() on selector = " + getSelector()); 309e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT); 310e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 3116b6adccb07300778cd665ca83c0e3672d97de41dGuang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 312e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 313e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu Rect rect = new Rect();; 314e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu node.getBoundsInScreen(rect); 315e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 316e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu int downX = 0; 317e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu int downY = 0; 318e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu int upX = 0; 319e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu int upY = 0; 320e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 321e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // scrolling is by default assumed vertically unless the object is explicitly 322e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // set otherwise by setAsHorizontalContainer() 323e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(mIsVerticalList) { 324e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu int swipeAreaAdjust = (int)(rect.height() * getSwipeDeadZonePercentage()); 325e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // scroll vertically: swipe down -> up 326e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu downX = rect.centerX(); 327e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu downY = rect.bottom - swipeAreaAdjust; 328e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu upX = rect.centerX(); 329e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu upY = rect.top + swipeAreaAdjust; 330e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } else { 331e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu int swipeAreaAdjust = (int)(rect.width() * getSwipeDeadZonePercentage()); 332e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // scroll horizontally: swipe right -> left 333e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // TODO: Assuming device is not in right to left language 334e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu downX = rect.right - swipeAreaAdjust; 335e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu downY = rect.centerY(); 336e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu upX = rect.left + swipeAreaAdjust; 337e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu upY = rect.centerY(); 338e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 339e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return getInteractionController().scrollSwipe(downX, downY, upX, upY, steps); 340e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 341e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 342e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 3433d50587be8ff021369c90554d814839335b445b0Adam Momtaz * See {@link UiScrollable#scrollBackward(int)} 344e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * 345e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if scrolled and false if can't scroll anymore 346e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 3476b6adccb07300778cd665ca83c0e3672d97de41dGuang Zhu public boolean flingBackward() throws UiObjectNotFoundException { 348e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return scrollBackward(FLING_STEPS); 349e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 350e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 351e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 3523d50587be8ff021369c90554d814839335b445b0Adam Momtaz * See {@link UiScrollable#scrollBackward(int)} 353e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * 354e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if scrolled and false if can't scroll anymore 355e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 3566b6adccb07300778cd665ca83c0e3672d97de41dGuang Zhu public boolean scrollBackward() throws UiObjectNotFoundException { 357e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return scrollBackward(SCROLL_STEPS); 358e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 359e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 360e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 361e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * Perform a scroll backward. If this list is set to vertical (see {@link #setAsVerticalList()} 362e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * default) then the swipes will be executed from the top to bottom. If this list is set 363e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * to horizontal (see {@link #setAsHorizontalList()}) then the swipes will be executed from 3643d50587be8ff021369c90554d814839335b445b0Adam Momtaz * the left to right. Caution is required on devices configured with right to left languages 3653d50587be8ff021369c90554d814839335b445b0Adam Momtaz * like Arabic and Hebrew. 366e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * 367e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @param steps use steps to control the speed, so that it may be a scroll, or fling 368e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if scrolled and false if can't scroll anymore 369e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 3706b6adccb07300778cd665ca83c0e3672d97de41dGuang Zhu public boolean scrollBackward(int steps) throws UiObjectNotFoundException { 371e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu Log.d(LOG_TAG, "scrollBackward() on selector = " + getSelector()); 372e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT); 3736b6adccb07300778cd665ca83c0e3672d97de41dGuang Zhu if (node == null) { 3746b6adccb07300778cd665ca83c0e3672d97de41dGuang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 375e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 376e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu Rect rect = new Rect();; 377e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu node.getBoundsInScreen(rect); 378e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 379e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu int downX = 0; 380e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu int downY = 0; 381e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu int upX = 0; 382e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu int upY = 0; 383e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 384e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // scrolling is by default assumed vertically unless the object is explicitly 385e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // set otherwise by setAsHorizontalContainer() 386e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(mIsVerticalList) { 387e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu int swipeAreaAdjust = (int)(rect.height() * getSwipeDeadZonePercentage()); 388e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu Log.d(LOG_TAG, "scrollToBegining() using vertical scroll"); 389e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // scroll vertically: swipe up -> down 390e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu downX = rect.centerX(); 391e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu downY = rect.top + swipeAreaAdjust; 392e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu upX = rect.centerX(); 393e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu upY = rect.bottom - swipeAreaAdjust; 394e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } else { 395e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu int swipeAreaAdjust = (int)(rect.width() * getSwipeDeadZonePercentage()); 396e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu Log.d(LOG_TAG, "scrollToBegining() using hotizontal scroll"); 397e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // scroll horizontally: swipe left -> right 398e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // TODO: Assuming device is not in right to left language 399e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu downX = rect.left + swipeAreaAdjust; 400e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu downY = rect.centerY(); 401e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu upX = rect.right - swipeAreaAdjust; 402e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu upY = rect.centerY(); 403e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 404e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return getInteractionController().scrollSwipe(downX, downY, upX, upY, steps); 405e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 406e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 407e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 408e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * Scrolls to the beginning of a scrollable UI element. The beginning could be the top most 4093d50587be8ff021369c90554d814839335b445b0Adam Momtaz * in case of vertical lists or the left most in case of horizontal lists. Caution is required 4103d50587be8ff021369c90554d814839335b445b0Adam Momtaz * on devices configured with right to left languages like Arabic and Hebrew. 411e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * 412e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @param steps use steps to control the speed, so that it may be a scroll, or fling 413e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true on scrolled else false 414e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 4156b6adccb07300778cd665ca83c0e3672d97de41dGuang Zhu public boolean scrollToBeginning(int maxSwipes, int steps) throws UiObjectNotFoundException { 416e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu Log.d(LOG_TAG, "scrollToBeginning() on selector = " + getSelector()); 417e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // protect against potential hanging and return after preset attempts 418e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu for(int x = 0; x < maxSwipes; x++) { 419e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(!scrollBackward(steps)) { 420e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu break; 421e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 422e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 423e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return true; 424e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 425e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 426e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 4273d50587be8ff021369c90554d814839335b445b0Adam Momtaz * See {@link UiScrollable#scrollToBeginning(int, int)} 428e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * 429e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @param maxSwipes 430e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true on scrolled else false 431e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 4326b6adccb07300778cd665ca83c0e3672d97de41dGuang Zhu public boolean scrollToBeginning(int maxSwipes) throws UiObjectNotFoundException { 433e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return scrollToBeginning(maxSwipes, SCROLL_STEPS); 434e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 435e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 436e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 4373d50587be8ff021369c90554d814839335b445b0Adam Momtaz * See {@link UiScrollable#scrollToBeginning(int, int)} 438e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * 439e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @param maxSwipes 440e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true on scrolled else false 441e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 4426b6adccb07300778cd665ca83c0e3672d97de41dGuang Zhu public boolean flingToBeginning(int maxSwipes) throws UiObjectNotFoundException { 443e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return scrollToBeginning(maxSwipes, FLING_STEPS); 444e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 445e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 446e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 447e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * Scrolls to the end of a scrollable UI element. The end could be the bottom most 4483d50587be8ff021369c90554d814839335b445b0Adam Momtaz * in case of vertical controls or the right most for horizontal controls. Caution 4493d50587be8ff021369c90554d814839335b445b0Adam Momtaz * is required on devices configured with right to left languages like Arabic and Hebrew. 450e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * 451e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @param steps use steps to control the speed, so that it may be a scroll, or fling 452e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true on scrolled else false 453e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 4546b6adccb07300778cd665ca83c0e3672d97de41dGuang Zhu public boolean scrollToEnd(int maxSwipes, int steps) throws UiObjectNotFoundException { 455e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // protect against potential hanging and return after preset attempts 456e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu for(int x = 0; x < maxSwipes; x++) { 457e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(!scrollForward(steps)) { 458e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu break; 459e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 460e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 461e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return true; 462e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 463e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 464e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 4653d50587be8ff021369c90554d814839335b445b0Adam Momtaz * See {@link UiScrollable#scrollToEnd(int, int) 466e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * 467e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @param maxSwipes 468e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true on scrolled else false 469e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 4706b6adccb07300778cd665ca83c0e3672d97de41dGuang Zhu public boolean scrollToEnd(int maxSwipes) throws UiObjectNotFoundException { 471e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return scrollToEnd(maxSwipes, SCROLL_STEPS); 472e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 473e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 474e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 4753d50587be8ff021369c90554d814839335b445b0Adam Momtaz * See {@link UiScrollable#scrollToEnd(int, int)} 476e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * 477e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @param maxSwipes 478e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true on scrolled else false 479e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 4806b6adccb07300778cd665ca83c0e3672d97de41dGuang Zhu public boolean flingToEnd(int maxSwipes) throws UiObjectNotFoundException { 481e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return scrollToEnd(maxSwipes, FLING_STEPS); 482e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 483e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 484a46ac3504426564954292b13380120e8cc6b1527Adam Momtaz /** 485a46ac3504426564954292b13380120e8cc6b1527Adam Momtaz * Returns the percentage of a widget's size that's considered as no touch zone when swiping 486a46ac3504426564954292b13380120e8cc6b1527Adam Momtaz * 487a46ac3504426564954292b13380120e8cc6b1527Adam Momtaz * Dead zones are set as percentage of a widget's total width or height where 488a46ac3504426564954292b13380120e8cc6b1527Adam Momtaz * swipe start point cannot start or swipe end point cannot end. It is like a margin 489a46ac3504426564954292b13380120e8cc6b1527Adam Momtaz * around the actual dimensions of the widget. Swipes will always be start and 490a46ac3504426564954292b13380120e8cc6b1527Adam Momtaz * end inside this margin. 491a46ac3504426564954292b13380120e8cc6b1527Adam Momtaz * 492a46ac3504426564954292b13380120e8cc6b1527Adam Momtaz * This is important when the widget being swiped may not respond to the swipe if 493a46ac3504426564954292b13380120e8cc6b1527Adam Momtaz * started at a point too near to the edge. The default is 10% from either edge. 494a46ac3504426564954292b13380120e8cc6b1527Adam Momtaz * 495a46ac3504426564954292b13380120e8cc6b1527Adam Momtaz * @return a value between 0 and 1 496a46ac3504426564954292b13380120e8cc6b1527Adam Momtaz */ 497e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public double getSwipeDeadZonePercentage() { 498e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return mSwipeDeadZonePercentage; 499e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 500e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 501a46ac3504426564954292b13380120e8cc6b1527Adam Momtaz /** 502a46ac3504426564954292b13380120e8cc6b1527Adam Momtaz * Sets the percentage of a widget's size that's considered as no touch zone when swiping 503a46ac3504426564954292b13380120e8cc6b1527Adam Momtaz * 504a46ac3504426564954292b13380120e8cc6b1527Adam Momtaz * Dead zones are set as percentage of a widget's total width or height where 505a46ac3504426564954292b13380120e8cc6b1527Adam Momtaz * swipe start point cannot start or swipe end point cannot end. It is like a margin 506a46ac3504426564954292b13380120e8cc6b1527Adam Momtaz * around the actual dimensions of the widget. Swipes will always start and 507a46ac3504426564954292b13380120e8cc6b1527Adam Momtaz * end inside this margin. 508a46ac3504426564954292b13380120e8cc6b1527Adam Momtaz * 509a46ac3504426564954292b13380120e8cc6b1527Adam Momtaz * This is important when the widget being swiped may not respond to the swipe if 510a46ac3504426564954292b13380120e8cc6b1527Adam Momtaz * started at a point too near to the edge. The default is 10% from either edge 511a46ac3504426564954292b13380120e8cc6b1527Adam Momtaz * 512a46ac3504426564954292b13380120e8cc6b1527Adam Momtaz * @param swipeDeadZonePercentage is a value between 0 and 1 513ee4b48cd50f6e4e24ba7f538b8a77c839c1087f5Adam Momtaz * @return reference to itself 514a46ac3504426564954292b13380120e8cc6b1527Adam Momtaz */ 515ee4b48cd50f6e4e24ba7f538b8a77c839c1087f5Adam Momtaz public UiScrollable setSwipeDeadZonePercentage(double swipeDeadZonePercentage) { 516e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu mSwipeDeadZonePercentage = swipeDeadZonePercentage; 517ee4b48cd50f6e4e24ba7f538b8a77c839c1087f5Adam Momtaz return this; 518e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 519e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu} 520