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. 25dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 26e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 27e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhupublic class UiScrollable extends UiCollection { 28e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu private static final String LOG_TAG = UiScrollable.class.getSimpleName(); 29e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 30e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // More steps slows the swipe and prevents contents from being flung too far 31e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu private static final int SCROLL_STEPS = 55; 32e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 33e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu private static final int FLING_STEPS = 5; 34e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 35e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // Restrict a swipe's starting and ending points inside a 10% margin of the target 36e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu private static final double DEFAULT_SWIPE_DEADZONE_PCT = 0.1; 37e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 38e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // Limits the number of swipes/scrolls performed during a search 39e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu private static int mMaxSearchSwipes = 30; 40e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 41e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // Used in ScrollForward() and ScrollBackward() to determine swipe direction 42f612e6a05f47b28ae0f5715545658c08dd759dd7Guang Zhu private boolean mIsVerticalList = true; 43e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 44e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu private double mSwipeDeadZonePercentage = DEFAULT_SWIPE_DEADZONE_PCT; 45e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 46e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 473d50587be8ff021369c90554d814839335b445b0Adam Momtaz * UiScrollable is a {@link UiCollection} and as such requires a {@link UiSelector} to 483d50587be8ff021369c90554d814839335b445b0Adam Momtaz * identify the container UI element of the scrollable collection. Further operations on 493d50587be8ff021369c90554d814839335b445b0Adam Momtaz * the items in the container will require specifying UiSelector as an item selector. 503d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 514ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz * @param container a {@link UiSelector} selector 52dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 53e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 544ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz public UiScrollable(UiSelector container) { 55e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // wrap the container selector with container so that QueryController can handle 56e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // this type of enumeration search accordingly 57e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu super(container); 58e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 59e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 60e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 61e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * Set the direction of swipes when performing scroll search 62ee4b48cd50f6e4e24ba7f538b8a77c839c1087f5Adam Momtaz * @return reference to itself 63dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 64e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 65ee4b48cd50f6e4e24ba7f538b8a77c839c1087f5Adam Momtaz public UiScrollable setAsVerticalList() { 66f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(); 67e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu mIsVerticalList = true; 68ee4b48cd50f6e4e24ba7f538b8a77c839c1087f5Adam Momtaz return this; 69e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 70e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 71e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 72e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * Set the direction of swipes when performing scroll search 73ee4b48cd50f6e4e24ba7f538b8a77c839c1087f5Adam Momtaz * @return reference to itself 74dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 75e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 76ee4b48cd50f6e4e24ba7f538b8a77c839c1087f5Adam Momtaz public UiScrollable setAsHorizontalList() { 77f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(); 78e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu mIsVerticalList = false; 79ee4b48cd50f6e4e24ba7f538b8a77c839c1087f5Adam Momtaz return this; 80e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 81e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 82e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 83e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * Used privately when performing swipe searches to decide if an element has become 84e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * visible or not. 853d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 86e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @param selector 87e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if found else false 88dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 89e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 904ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz protected boolean exists(UiSelector selector) { 91e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(getQueryController().findAccessibilityNodeInfo(selector) != null) { 92e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return true; 93e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 94e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return false; 95e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 96e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 97e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 984ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz * Searches for child UI element within the constraints of this UiScrollable {@link UiSelector} 993d50587be8ff021369c90554d814839335b445b0Adam Momtaz * container. It looks for any child matching the <code>childPattern</code> argument within its 1003d50587be8ff021369c90554d814839335b445b0Adam Momtaz * hierarchy with a matching content-description text. The returned UiObject will represent the 1013d50587be8ff021369c90554d814839335b445b0Adam Momtaz * UI element matching the <code>childPattern</code> and not the sub element that matched the 1023d50587be8ff021369c90554d814839335b445b0Adam Momtaz * content description.</p> 1033d50587be8ff021369c90554d814839335b445b0Adam Momtaz * By default this operation will perform scroll search while attempting to find the UI element 1044ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz * See {@link #getChildByDescription(UiSelector, String, boolean)} 1053d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 1064ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz * @param childPattern {@link UiSelector} selector of the child pattern to match and return 107e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @param text String of the identifying child contents of of the <code>childPattern</code> 108e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return {@link UiObject} pointing at and instance of <code>childPattern</code> 109e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 110dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 111e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 112e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu @Override 1134ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz public UiObject getChildByDescription(UiSelector childPattern, String text) 114e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throws UiObjectNotFoundException { 115f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(childPattern, text); 116e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return getChildByDescription(childPattern, text, true); 117e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 118e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 119e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 1203d50587be8ff021369c90554d814839335b445b0Adam Momtaz * See {@link #getChildByDescription(UiSelector, String)} 1213d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 1224ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz * @param childPattern {@link UiSelector} selector of the child pattern to match and return 123e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @param text String may be a partial match for the content-description of a child element. 124e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @param allowScrollSearch set to true if scrolling is allowed 125e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return {@link UiObject} pointing at and instance of <code>childPattern</code> 126e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 127dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 128e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 1294ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz public UiObject getChildByDescription(UiSelector childPattern, String text, 1304ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz boolean allowScrollSearch) throws UiObjectNotFoundException { 131f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(childPattern, text, allowScrollSearch); 132e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if (text != null) { 133e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if (allowScrollSearch) { 1344ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz scrollIntoView(new UiSelector().descriptionContains(text)); 135e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 136e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return super.getChildByDescription(childPattern, text); 137e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 138e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException("for description= \"" + text + "\""); 139e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 140e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 141e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 1424ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz * Searches for child UI element within the constraints of this UiScrollable {@link UiSelector} 143e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * selector. It looks for any child matching the <code>childPattern</code> argument and 144e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * return the <code>instance</code> specified. The operation is performed only on the visible 145e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * items and no scrolling is performed in this case. 1463d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 1474ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz * @param childPattern {@link UiSelector} selector of the child pattern to match and return 148e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @param instance int the desired matched instance of this <code>childPattern</code> 149e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return {@link UiObject} pointing at and instance of <code>childPattern</code> 150dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 151e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 152e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu @Override 1534ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz public UiObject getChildByInstance(UiSelector childPattern, int instance) 154e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throws UiObjectNotFoundException { 155f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(childPattern, instance); 1564ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz UiSelector patternSelector = UiSelector.patternBuilder(getSelector(), 1574ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz UiSelector.patternBuilder(childPattern).instance(instance)); 158e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return new UiObject(patternSelector); 159e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 160e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 161e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 1624ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz * Searches for child UI element within the constraints of this UiScrollable {@link UiSelector} 1633d50587be8ff021369c90554d814839335b445b0Adam Momtaz * container. It looks for any child matching the <code>childPattern</code> argument that has 1643d50587be8ff021369c90554d814839335b445b0Adam Momtaz * a sub UI element anywhere within its sub hierarchy that has text attribute 165e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * <code>text</code>. The returned UiObject will point at the <code>childPattern</code> 1663d50587be8ff021369c90554d814839335b445b0Adam Momtaz * instance that matched the search and not at the text matched sub element</p> 167e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * By default this operation will perform scroll search while attempting to find the UI 168e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * element. 1694ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz * See {@link #getChildByText(UiSelector, String, boolean)} 1703d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 1714ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz * @param childPattern {@link UiSelector} selector of the child pattern to match and return 172e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @param text String of the identifying child contents of of the <code>childPattern</code> 173e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return {@link UiObject} pointing at and instance of <code>childPattern</code> 174e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 175dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 176e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 177e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu @Override 1784ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz public UiObject getChildByText(UiSelector childPattern, String text) 179e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throws UiObjectNotFoundException { 180f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(childPattern, text); 181e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return getChildByText(childPattern, text, true); 182e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 183e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 184e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 1853d50587be8ff021369c90554d814839335b445b0Adam Momtaz * See {@link #getChildByText(UiSelector, String)} 1863d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 1874ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz * @param childPattern {@link UiSelector} selector of the child pattern to match and return 188e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @param text String of the identifying child contents of of the <code>childPattern</code> 189e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @param allowScrollSearch set to true if scrolling is allowed 190e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return {@link UiObject} pointing at and instance of <code>childPattern</code> 191e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @throws UiObjectNotFoundException 192dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 193e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 1944ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz public UiObject getChildByText(UiSelector childPattern, String text, boolean allowScrollSearch) 195e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throws UiObjectNotFoundException { 196f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(childPattern, text, allowScrollSearch); 197e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if (text != null) { 198e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if (allowScrollSearch) { 1994ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz scrollIntoView(new UiSelector().text(text)); 200e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 201e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return super.getChildByText(childPattern, text); 202e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 203e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu throw new UiObjectNotFoundException("for text= \"" + text + "\""); 204e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 205e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 206e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 2073d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Performs a swipe Up on the UI element until the requested content-description 2083d50587be8ff021369c90554d814839335b445b0Adam Momtaz * is visible or until swipe attempts have been exhausted. See {@link #setMaxSearchSwipes(int)} 2093d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 210e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @param text to look for anywhere within the contents of this scrollable. 211e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if item us found else false 212dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 213e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 2146b6adccb07300778cd665ca83c0e3672d97de41dGuang Zhu public boolean scrollDescriptionIntoView(String text) throws UiObjectNotFoundException { 215f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(text); 2164ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz return scrollIntoView(new UiSelector().description(text)); 217e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 218e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 219e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 2204ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz * Perform a scroll search for a UI element matching the {@link UiSelector} selector argument. 2213d50587be8ff021369c90554d814839335b445b0Adam Momtaz * See {@link #scrollDescriptionIntoView(String)} and {@link #scrollTextIntoView(String)}. 2223d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 223ee4b48cd50f6e4e24ba7f538b8a77c839c1087f5Adam Momtaz * @param obj {@link UiObject} 224ee4b48cd50f6e4e24ba7f538b8a77c839c1087f5Adam Momtaz * @return true if the item was found and now is in view else false 225dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 226ee4b48cd50f6e4e24ba7f538b8a77c839c1087f5Adam Momtaz */ 227ee4b48cd50f6e4e24ba7f538b8a77c839c1087f5Adam Momtaz public boolean scrollIntoView(UiObject obj) throws UiObjectNotFoundException { 228f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(obj.getSelector()); 229ee4b48cd50f6e4e24ba7f538b8a77c839c1087f5Adam Momtaz return scrollIntoView(obj.getSelector()); 230ee4b48cd50f6e4e24ba7f538b8a77c839c1087f5Adam Momtaz } 231ee4b48cd50f6e4e24ba7f538b8a77c839c1087f5Adam Momtaz 232ee4b48cd50f6e4e24ba7f538b8a77c839c1087f5Adam Momtaz /** 233ee4b48cd50f6e4e24ba7f538b8a77c839c1087f5Adam Momtaz * Perform a scroll search for a UI element matching the {@link UiSelector} selector argument. 234ee4b48cd50f6e4e24ba7f538b8a77c839c1087f5Adam Momtaz * See {@link #scrollDescriptionIntoView(String)} and {@link #scrollTextIntoView(String)}. 235ee4b48cd50f6e4e24ba7f538b8a77c839c1087f5Adam Momtaz * 2364ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz * @param selector {@link UiSelector} selector 237e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if the item was found and now is in view else false 238dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 239e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 2406b6adccb07300778cd665ca83c0e3672d97de41dGuang Zhu public boolean scrollIntoView(UiSelector selector) throws UiObjectNotFoundException { 241f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(selector); 242e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // if we happen to be on top of the text we want then return here 243e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if (exists(getSelector().childSelector(selector))) { 244e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return (true); 245e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } else { 246e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // we will need to reset the search from the beginning to start search 247e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu scrollToBeginning(mMaxSearchSwipes); 248e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if (exists(getSelector().childSelector(selector))) { 249e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return (true); 250e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 251e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu for (int x = 0; x < mMaxSearchSwipes; x++) { 252e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(!scrollForward()) { 253e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return false; 254e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 255e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 256e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(exists(getSelector().childSelector(selector))) { 257e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return true; 258e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 259e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 260e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 261e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return false; 262e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 263e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 264e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 2653d50587be8ff021369c90554d814839335b445b0Adam Momtaz * Performs a swipe up on the UI element until the requested text is visible 2663d50587be8ff021369c90554d814839335b445b0Adam Momtaz * or until swipe attempts have been exhausted. See {@link #setMaxSearchSwipes(int)} 2673d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 268e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @param text to look for 269e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if item us found else false 270dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 271e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 2726b6adccb07300778cd665ca83c0e3672d97de41dGuang Zhu public boolean scrollTextIntoView(String text) throws UiObjectNotFoundException { 273f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(text); 2744ab790eccf6d5c27f542056b87d26d38f7caeeb3Adam Momtaz return scrollIntoView(new UiSelector().text(text)); 275e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 276e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 277e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 2781893caed0ad4e73b0676f206282d490c2d345316Thanh Le * {@link #getChildByDescription(UiSelector, String)} and 2791893caed0ad4e73b0676f206282d490c2d345316Thanh Le * {@link #getChildByText(UiSelector, String)} use an arguments that specifies if scrolling is 2801893caed0ad4e73b0676f206282d490c2d345316Thanh Le * allowed while searching for the UI element. The number of scrolls allowed to perform a 2811893caed0ad4e73b0676f206282d490c2d345316Thanh Le * search can be modified by this method. The current value can be read by calling 2821893caed0ad4e73b0676f206282d490c2d345316Thanh Le * {@link #getMaxSearchSwipes()} 2833d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 2843d50587be8ff021369c90554d814839335b445b0Adam Momtaz * @param swipes is the number of search swipes until abort 285ee4b48cd50f6e4e24ba7f538b8a77c839c1087f5Adam Momtaz * @return reference to itself 286dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 287e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 288ee4b48cd50f6e4e24ba7f538b8a77c839c1087f5Adam Momtaz public UiScrollable setMaxSearchSwipes(int swipes) { 289f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(swipes); 290e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu mMaxSearchSwipes = swipes; 291ee4b48cd50f6e4e24ba7f538b8a77c839c1087f5Adam Momtaz return this; 292e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 293e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 294e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 2951893caed0ad4e73b0676f206282d490c2d345316Thanh Le * {@link #getChildByDescription(UiSelector, String)} and 2961893caed0ad4e73b0676f206282d490c2d345316Thanh Le * {@link #getChildByText(UiSelector, String)} use an arguments that specifies if scrolling is 2971893caed0ad4e73b0676f206282d490c2d345316Thanh Le * allowed while searching for the UI element. The number of scrolls currently allowed to 2981893caed0ad4e73b0676f206282d490c2d345316Thanh Le * perform a search can be read by this method. 299e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * See {@link #setMaxSearchSwipes(int)} 3003d50587be8ff021369c90554d814839335b445b0Adam Momtaz * 301e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return max value of the number of swipes currently allowed during a scroll search 302dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 303e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 304e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public int getMaxSearchSwipes() { 305f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(); 306e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return mMaxSearchSwipes; 307e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 308e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 309e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 310e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * A convenience version of {@link UiScrollable#scrollForward(int)}, performs a fling 311e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * 312e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if scrolled and false if can't scroll anymore 313dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 314e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 3156b6adccb07300778cd665ca83c0e3672d97de41dGuang Zhu public boolean flingForward() throws UiObjectNotFoundException { 316f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(); 317e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return scrollForward(FLING_STEPS); 318e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 319e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 320e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 321e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * A convenience version of {@link UiScrollable#scrollForward(int)}, performs a regular scroll 322e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * 323e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if scrolled and false if can't scroll anymore 324dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 325e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 3266b6adccb07300778cd665ca83c0e3672d97de41dGuang Zhu public boolean scrollForward() throws UiObjectNotFoundException { 327f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(); 328e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return scrollForward(SCROLL_STEPS); 329e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 330e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 331e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 332e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * Perform a scroll forward. If this list is set to vertical (see {@link #setAsVerticalList()} 333e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * default) then the swipes will be executed from the bottom to top. If this list is set 334e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * to horizontal (see {@link #setAsHorizontalList()}) then the swipes will be executed from 3353d50587be8ff021369c90554d814839335b445b0Adam Momtaz * the right to left. Caution is required on devices configured with right to left languages 3363d50587be8ff021369c90554d814839335b445b0Adam Momtaz * like Arabic and Hebrew. 337e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * 338e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @param steps use steps to control the speed, so that it may be a scroll, or fling 339e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if scrolled and false if can't scroll anymore 340dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 341e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 3426b6adccb07300778cd665ca83c0e3672d97de41dGuang Zhu public boolean scrollForward(int steps) throws UiObjectNotFoundException { 343f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(steps); 344e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu Log.d(LOG_TAG, "scrollForward() on selector = " + getSelector()); 345e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT); 346e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(node == null) { 3476b6adccb07300778cd665ca83c0e3672d97de41dGuang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 348e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 3491893caed0ad4e73b0676f206282d490c2d345316Thanh Le Rect rect = new Rect(); 350e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu node.getBoundsInScreen(rect); 351e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 352e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu int downX = 0; 353e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu int downY = 0; 354e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu int upX = 0; 355e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu int upY = 0; 356e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 357e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // scrolling is by default assumed vertically unless the object is explicitly 358e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // set otherwise by setAsHorizontalContainer() 359e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(mIsVerticalList) { 360e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu int swipeAreaAdjust = (int)(rect.height() * getSwipeDeadZonePercentage()); 361e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // scroll vertically: swipe down -> up 362e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu downX = rect.centerX(); 363e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu downY = rect.bottom - swipeAreaAdjust; 364e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu upX = rect.centerX(); 365e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu upY = rect.top + swipeAreaAdjust; 366e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } else { 367e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu int swipeAreaAdjust = (int)(rect.width() * getSwipeDeadZonePercentage()); 368e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // scroll horizontally: swipe right -> left 369e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // TODO: Assuming device is not in right to left language 370e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu downX = rect.right - swipeAreaAdjust; 371e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu downY = rect.centerY(); 372e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu upX = rect.left + swipeAreaAdjust; 373e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu upY = rect.centerY(); 374e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 375e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return getInteractionController().scrollSwipe(downX, downY, upX, upY, steps); 376e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 377e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 378e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 3793d50587be8ff021369c90554d814839335b445b0Adam Momtaz * See {@link UiScrollable#scrollBackward(int)} 380e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * 381e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if scrolled and false if can't scroll anymore 382dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 383e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 3846b6adccb07300778cd665ca83c0e3672d97de41dGuang Zhu public boolean flingBackward() throws UiObjectNotFoundException { 385f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(); 386e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return scrollBackward(FLING_STEPS); 387e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 388e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 389e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 3903d50587be8ff021369c90554d814839335b445b0Adam Momtaz * See {@link UiScrollable#scrollBackward(int)} 391e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * 392e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if scrolled and false if can't scroll anymore 393dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 394e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 3956b6adccb07300778cd665ca83c0e3672d97de41dGuang Zhu public boolean scrollBackward() throws UiObjectNotFoundException { 396f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(); 397e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return scrollBackward(SCROLL_STEPS); 398e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 399e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 400e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 401e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * Perform a scroll backward. If this list is set to vertical (see {@link #setAsVerticalList()} 402e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * default) then the swipes will be executed from the top to bottom. If this list is set 403e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * to horizontal (see {@link #setAsHorizontalList()}) then the swipes will be executed from 4043d50587be8ff021369c90554d814839335b445b0Adam Momtaz * the left to right. Caution is required on devices configured with right to left languages 4053d50587be8ff021369c90554d814839335b445b0Adam Momtaz * like Arabic and Hebrew. 406e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * 407e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @param steps use steps to control the speed, so that it may be a scroll, or fling 408e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true if scrolled and false if can't scroll anymore 409dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 410e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 4116b6adccb07300778cd665ca83c0e3672d97de41dGuang Zhu public boolean scrollBackward(int steps) throws UiObjectNotFoundException { 412f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(steps); 413e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu Log.d(LOG_TAG, "scrollBackward() on selector = " + getSelector()); 414e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT); 4156b6adccb07300778cd665ca83c0e3672d97de41dGuang Zhu if (node == null) { 4166b6adccb07300778cd665ca83c0e3672d97de41dGuang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 417e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 4181893caed0ad4e73b0676f206282d490c2d345316Thanh Le Rect rect = new Rect(); 419e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu node.getBoundsInScreen(rect); 420e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 421e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu int downX = 0; 422e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu int downY = 0; 423e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu int upX = 0; 424e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu int upY = 0; 425e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 426e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // scrolling is by default assumed vertically unless the object is explicitly 427e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // set otherwise by setAsHorizontalContainer() 428e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(mIsVerticalList) { 429e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu int swipeAreaAdjust = (int)(rect.height() * getSwipeDeadZonePercentage()); 430e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu Log.d(LOG_TAG, "scrollToBegining() using vertical scroll"); 431e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // scroll vertically: swipe up -> down 432e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu downX = rect.centerX(); 433e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu downY = rect.top + swipeAreaAdjust; 434e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu upX = rect.centerX(); 435e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu upY = rect.bottom - swipeAreaAdjust; 436e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } else { 437e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu int swipeAreaAdjust = (int)(rect.width() * getSwipeDeadZonePercentage()); 438e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu Log.d(LOG_TAG, "scrollToBegining() using hotizontal scroll"); 439e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // scroll horizontally: swipe left -> right 440e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // TODO: Assuming device is not in right to left language 441e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu downX = rect.left + swipeAreaAdjust; 442e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu downY = rect.centerY(); 443e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu upX = rect.right - swipeAreaAdjust; 444e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu upY = rect.centerY(); 445e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 446e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return getInteractionController().scrollSwipe(downX, downY, upX, upY, steps); 447e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 448e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 449e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 450e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * Scrolls to the beginning of a scrollable UI element. The beginning could be the top most 4513d50587be8ff021369c90554d814839335b445b0Adam Momtaz * in case of vertical lists or the left most in case of horizontal lists. Caution is required 4523d50587be8ff021369c90554d814839335b445b0Adam Momtaz * on devices configured with right to left languages like Arabic and Hebrew. 453e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * 454e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @param steps use steps to control the speed, so that it may be a scroll, or fling 455e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true on scrolled else false 456dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 457e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 4586b6adccb07300778cd665ca83c0e3672d97de41dGuang Zhu public boolean scrollToBeginning(int maxSwipes, int steps) throws UiObjectNotFoundException { 459f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(maxSwipes, steps); 460e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu Log.d(LOG_TAG, "scrollToBeginning() on selector = " + getSelector()); 461e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // protect against potential hanging and return after preset attempts 462e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu for(int x = 0; x < maxSwipes; x++) { 463e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(!scrollBackward(steps)) { 464e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu break; 465e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 466e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 467e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return true; 468e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 469e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 470e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 4713d50587be8ff021369c90554d814839335b445b0Adam Momtaz * See {@link UiScrollable#scrollToBeginning(int, int)} 472e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * 473e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @param maxSwipes 474e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true on scrolled else false 475dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 476e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 4776b6adccb07300778cd665ca83c0e3672d97de41dGuang Zhu public boolean scrollToBeginning(int maxSwipes) throws UiObjectNotFoundException { 478f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(maxSwipes); 479e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return scrollToBeginning(maxSwipes, SCROLL_STEPS); 480e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 481e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 482e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 4833d50587be8ff021369c90554d814839335b445b0Adam Momtaz * See {@link UiScrollable#scrollToBeginning(int, int)} 484e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * 485e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @param maxSwipes 486e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true on scrolled else false 487dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 488e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 4896b6adccb07300778cd665ca83c0e3672d97de41dGuang Zhu public boolean flingToBeginning(int maxSwipes) throws UiObjectNotFoundException { 490f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(maxSwipes); 491e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return scrollToBeginning(maxSwipes, FLING_STEPS); 492e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 493e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 494e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 495e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * Scrolls to the end of a scrollable UI element. The end could be the bottom most 4963d50587be8ff021369c90554d814839335b445b0Adam Momtaz * in case of vertical controls or the right most for horizontal controls. Caution 4973d50587be8ff021369c90554d814839335b445b0Adam Momtaz * is required on devices configured with right to left languages like Arabic and Hebrew. 498e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * 499e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @param steps use steps to control the speed, so that it may be a scroll, or fling 500e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true on scrolled else false 501dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 502e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 5036b6adccb07300778cd665ca83c0e3672d97de41dGuang Zhu public boolean scrollToEnd(int maxSwipes, int steps) throws UiObjectNotFoundException { 504f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(maxSwipes, steps); 505e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu // protect against potential hanging and return after preset attempts 506e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu for(int x = 0; x < maxSwipes; x++) { 507e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu if(!scrollForward(steps)) { 508e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu break; 509e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 510e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 511e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return true; 512e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 513e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 514e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 5151893caed0ad4e73b0676f206282d490c2d345316Thanh Le * See {@link UiScrollable#scrollToEnd(int, int)} 516e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * 517e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @param maxSwipes 518e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true on scrolled else false 519dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 520e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 5216b6adccb07300778cd665ca83c0e3672d97de41dGuang Zhu public boolean scrollToEnd(int maxSwipes) throws UiObjectNotFoundException { 522f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(maxSwipes); 523e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return scrollToEnd(maxSwipes, SCROLL_STEPS); 524e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 525e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 526e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu /** 5273d50587be8ff021369c90554d814839335b445b0Adam Momtaz * See {@link UiScrollable#scrollToEnd(int, int)} 528e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * 529e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @param maxSwipes 530e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu * @return true on scrolled else false 531dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 532e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu */ 5336b6adccb07300778cd665ca83c0e3672d97de41dGuang Zhu public boolean flingToEnd(int maxSwipes) throws UiObjectNotFoundException { 534f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(maxSwipes); 535e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return scrollToEnd(maxSwipes, FLING_STEPS); 536e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 537e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 538a46ac3504426564954292b13380120e8cc6b1527Adam Momtaz /** 539a46ac3504426564954292b13380120e8cc6b1527Adam Momtaz * Returns the percentage of a widget's size that's considered as no touch zone when swiping 540a46ac3504426564954292b13380120e8cc6b1527Adam Momtaz * 541a46ac3504426564954292b13380120e8cc6b1527Adam Momtaz * Dead zones are set as percentage of a widget's total width or height where 542a46ac3504426564954292b13380120e8cc6b1527Adam Momtaz * swipe start point cannot start or swipe end point cannot end. It is like a margin 543a46ac3504426564954292b13380120e8cc6b1527Adam Momtaz * around the actual dimensions of the widget. Swipes will always be start and 544a46ac3504426564954292b13380120e8cc6b1527Adam Momtaz * end inside this margin. 545a46ac3504426564954292b13380120e8cc6b1527Adam Momtaz * 546a46ac3504426564954292b13380120e8cc6b1527Adam Momtaz * This is important when the widget being swiped may not respond to the swipe if 547a46ac3504426564954292b13380120e8cc6b1527Adam Momtaz * started at a point too near to the edge. The default is 10% from either edge. 548a46ac3504426564954292b13380120e8cc6b1527Adam Momtaz * 549a46ac3504426564954292b13380120e8cc6b1527Adam Momtaz * @return a value between 0 and 1 550dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 551a46ac3504426564954292b13380120e8cc6b1527Adam Momtaz */ 552e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu public double getSwipeDeadZonePercentage() { 553f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(); 554e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu return mSwipeDeadZonePercentage; 555e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 556e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu 557a46ac3504426564954292b13380120e8cc6b1527Adam Momtaz /** 558a46ac3504426564954292b13380120e8cc6b1527Adam Momtaz * Sets the percentage of a widget's size that's considered as no touch zone when swiping 559a46ac3504426564954292b13380120e8cc6b1527Adam Momtaz * 560a46ac3504426564954292b13380120e8cc6b1527Adam Momtaz * Dead zones are set as percentage of a widget's total width or height where 561a46ac3504426564954292b13380120e8cc6b1527Adam Momtaz * swipe start point cannot start or swipe end point cannot end. It is like a margin 562a46ac3504426564954292b13380120e8cc6b1527Adam Momtaz * around the actual dimensions of the widget. Swipes will always start and 563a46ac3504426564954292b13380120e8cc6b1527Adam Momtaz * end inside this margin. 564a46ac3504426564954292b13380120e8cc6b1527Adam Momtaz * 565a46ac3504426564954292b13380120e8cc6b1527Adam Momtaz * This is important when the widget being swiped may not respond to the swipe if 566a46ac3504426564954292b13380120e8cc6b1527Adam Momtaz * started at a point too near to the edge. The default is 10% from either edge 567a46ac3504426564954292b13380120e8cc6b1527Adam Momtaz * 568a46ac3504426564954292b13380120e8cc6b1527Adam Momtaz * @param swipeDeadZonePercentage is a value between 0 and 1 569ee4b48cd50f6e4e24ba7f538b8a77c839c1087f5Adam Momtaz * @return reference to itself 570dbba713661688a285e701a006ce2d199296ac328Guang Zhu * @since API Level 16 571a46ac3504426564954292b13380120e8cc6b1527Adam Momtaz */ 572ee4b48cd50f6e4e24ba7f538b8a77c839c1087f5Adam Momtaz public UiScrollable setSwipeDeadZonePercentage(double swipeDeadZonePercentage) { 573f406deb12db531785300f04e219fef28ef60b126Maxim Siniavine Tracer.trace(swipeDeadZonePercentage); 574e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu mSwipeDeadZonePercentage = swipeDeadZonePercentage; 575ee4b48cd50f6e4e24ba7f538b8a77c839c1087f5Adam Momtaz return this; 576e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu } 577e54d649fb83a0a44516e5c25a9ac1992c8950e59Guang Zhu} 578