118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu/* 218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * Copyright (C) 2012 The Android Open Source Project 318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * 418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * Licensed under the Apache License, Version 2.0 (the "License"); 518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * you may not use this file except in compliance with the License. 618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * You may obtain a copy of the License at 718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * 818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * http://www.apache.org/licenses/LICENSE-2.0 918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * 1018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * Unless required by applicable law or agreed to in writing, software 1118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * distributed under the License is distributed on an "AS IS" BASIS, 1218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * See the License for the specific language governing permissions and 1418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * limitations under the License. 1518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu */ 1618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhupackage com.android.uiautomator.core; 1718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 1818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhuimport android.graphics.Rect; 1918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhuimport android.util.Log; 2018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhuimport android.view.accessibility.AccessibilityNodeInfo; 2118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 2218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu/** 2318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * UiScrollable is a {@link UiCollection} and provides support for searching 2418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * for items in scrollable layout elements. This class can be used with 2518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * horizontally or vertically scrollable controls. 2618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @since API Level 16 2718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu */ 2818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhupublic class UiScrollable extends UiCollection { 2918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu private static final String LOG_TAG = UiScrollable.class.getSimpleName(); 3018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 3118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu // More steps slows the swipe and prevents contents from being flung too far 3218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu private static final int SCROLL_STEPS = 55; 3318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 3418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu private static final int FLING_STEPS = 5; 3518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 3618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu // Restrict a swipe's starting and ending points inside a 10% margin of the target 3718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu private static final double DEFAULT_SWIPE_DEADZONE_PCT = 0.1; 3818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 3918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu // Limits the number of swipes/scrolls performed during a search 4018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu private static int mMaxSearchSwipes = 30; 4118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 4218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu // Used in ScrollForward() and ScrollBackward() to determine swipe direction 4318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu private boolean mIsVerticalList = true; 4418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 4518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu private double mSwipeDeadZonePercentage = DEFAULT_SWIPE_DEADZONE_PCT; 4618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 4718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu /** 4818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * Constructor. 4918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * 5018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @param container a {@link UiSelector} selector to identify the scrollable 5118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * layout element. 5218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @since API Level 16 5318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu */ 5418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu public UiScrollable(UiSelector container) { 5518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu // wrap the container selector with container so that QueryController can handle 5618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu // this type of enumeration search accordingly 5718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu super(container); 5818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 5918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 6018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu /** 6118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * Set the direction of swipes to be vertical when performing scroll actions. 6218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @return reference to itself 6318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @since API Level 16 6418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu */ 6518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu public UiScrollable setAsVerticalList() { 6618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu Tracer.trace(); 6718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu mIsVerticalList = true; 6818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu return this; 6918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 7018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 7118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu /** 7218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * Set the direction of swipes to be horizontal when performing scroll actions. 7318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @return reference to itself 7418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @since API Level 16 7518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu */ 7618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu public UiScrollable setAsHorizontalList() { 7718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu Tracer.trace(); 7818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu mIsVerticalList = false; 7918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu return this; 8018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 8118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 8218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu /** 8318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * Used privately when performing swipe searches to decide if an element has become 8418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * visible or not. 8518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * 8618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @param selector 8718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @return true if found else false 8818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @since API Level 16 8918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu */ 9018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu protected boolean exists(UiSelector selector) { 9118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu if(getQueryController().findAccessibilityNodeInfo(selector) != null) { 9218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu return true; 9318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 9418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu return false; 9518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 9618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 9718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu /** 9818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * Searches for a child element in the present scrollable container. 9918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * The search first looks for a child element that matches the selector 10018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * you provided, then looks for the content-description in its children elements. 10118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * If both search conditions are fulfilled, the method returns a {@ link UiObject} 10218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * representing the element matching the selector (not the child element in its 10318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * subhierarchy containing the content-description). By default, this method performs a 10418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * scroll search. 10518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * See {@link #getChildByDescription(UiSelector, String, boolean)} 10618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * 10718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @param childPattern {@link UiSelector} for a child in a scollable layout element 10818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @param text Content-description to find in the children of 10918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * the <code>childPattern</code> match 11018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @return {@link UiObject} representing the child element that matches the search conditions 11118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @throws UiObjectNotFoundException 11218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @since API Level 16 11318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu */ 11418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu @Override 11518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu public UiObject getChildByDescription(UiSelector childPattern, String text) 11618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu throws UiObjectNotFoundException { 11718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu Tracer.trace(childPattern, text); 11818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu return getChildByDescription(childPattern, text, true); 11918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 12018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 12118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu /** 12218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * Searches for a child element in the present scrollable container. 12318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * The search first looks for a child element that matches the selector 12418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * you provided, then looks for the content-description in its children elements. 12518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * If both search conditions are fulfilled, the method returns a {@ link UiObject} 12618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * representing the element matching the selector (not the child element in its 12718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * subhierarchy containing the content-description). 12818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * 12918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @param childPattern {@link UiSelector} for a child in a scollable layout element 13018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @param text Content-description to find in the children of 13118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * the <code>childPattern</code> match (may be a partial match) 13218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @param allowScrollSearch set to true if scrolling is allowed 13318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @return {@link UiObject} representing the child element that matches the search conditions 13418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @throws UiObjectNotFoundException 13518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @since API Level 16 13618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu */ 13718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu public UiObject getChildByDescription(UiSelector childPattern, String text, 13818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu boolean allowScrollSearch) throws UiObjectNotFoundException { 13918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu Tracer.trace(childPattern, text, allowScrollSearch); 14018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu if (text != null) { 14118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu if (allowScrollSearch) { 14218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu scrollIntoView(new UiSelector().descriptionContains(text)); 14318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 14418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu return super.getChildByDescription(childPattern, text); 14518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 14618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu throw new UiObjectNotFoundException("for description= \"" + text + "\""); 14718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 14818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 14918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu /** 15018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * Searches for a child element in the present scrollable container that 15118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * matches the selector you provided. The search is performed without 15218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * scrolling and only on visible elements. 15318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * 15418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @param childPattern {@link UiSelector} for a child in a scollable layout element 15518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @param instance int number representing the occurance of 15618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * a <code>childPattern</code> match 15718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @return {@link UiObject} representing the child element that matches the search conditions 15818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @since API Level 16 15918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu */ 16018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu @Override 16118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu public UiObject getChildByInstance(UiSelector childPattern, int instance) 16218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu throws UiObjectNotFoundException { 16318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu Tracer.trace(childPattern, instance); 16418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu UiSelector patternSelector = UiSelector.patternBuilder(getSelector(), 16518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu UiSelector.patternBuilder(childPattern).instance(instance)); 16618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu return new UiObject(patternSelector); 16718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 16818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 16918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu /** 17018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * Searches for a child element in the present scrollable 17118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * container. The search first looks for a child element that matches the 17218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * selector you provided, then looks for the text in its children elements. 17318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * If both search conditions are fulfilled, the method returns a {@ link UiObject} 17418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * representing the element matching the selector (not the child element in its 17518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * subhierarchy containing the text). By default, this method performs a 17618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * scroll search. 17718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * See {@link #getChildByText(UiSelector, String, boolean)} 17818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * 17918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @param childPattern {@link UiSelector} selector for a child in a scrollable layout element 18018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @param text String to find in the children of the <code>childPattern</code> match 18118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @return {@link UiObject} representing the child element that matches the search conditions 18218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @throws UiObjectNotFoundException 18318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @since API Level 16 18418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu */ 18518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu @Override 18618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu public UiObject getChildByText(UiSelector childPattern, String text) 18718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu throws UiObjectNotFoundException { 18818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu Tracer.trace(childPattern, text); 18918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu return getChildByText(childPattern, text, true); 19018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 19118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 19218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu /** 19318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * Searches for a child element in the present scrollable container. The 19418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * search first looks for a child element that matches the 19518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * selector you provided, then looks for the text in its children elements. 19618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * If both search conditions are fulfilled, the method returns a {@ link UiObject} 19718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * representing the element matching the selector (not the child element in its 19818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * subhierarchy containing the text). 19918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * 20018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @param childPattern {@link UiSelector} selector for a child in a scrollable layout element 20118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @param text String to find in the children of the <code>childPattern</code> match 20218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @param allowScrollSearch set to true if scrolling is allowed 20318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @return {@link UiObject} representing the child element that matches the search conditions 20418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @throws UiObjectNotFoundException 20518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @since API Level 16 20618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu */ 20718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu public UiObject getChildByText(UiSelector childPattern, String text, boolean allowScrollSearch) 20818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu throws UiObjectNotFoundException { 20918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu Tracer.trace(childPattern, text, allowScrollSearch); 21018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu if (text != null) { 21118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu if (allowScrollSearch) { 21218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu scrollIntoView(new UiSelector().text(text)); 21318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 21418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu return super.getChildByText(childPattern, text); 21518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 21618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu throw new UiObjectNotFoundException("for text= \"" + text + "\""); 21718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 21818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 21918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu /** 22018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * Performs a forward scroll action on the scrollable layout element until 22118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * the content-description is found, or until swipe attempts have been exhausted. 22218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * See {@link #setMaxSearchSwipes(int)} 22318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * 22418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @param text content-description to find within the contents of this scrollable layout element. 22518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @return true if item is found; else, false 22618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @since API Level 16 22718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu */ 22818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu public boolean scrollDescriptionIntoView(String text) throws UiObjectNotFoundException { 22918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu Tracer.trace(text); 23018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu return scrollIntoView(new UiSelector().description(text)); 23118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 23218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 23318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu /** 23418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * Perform a forward scroll action to move through the scrollable layout element until 23518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * a visible item that matches the {@link UiObject} is found. 23618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * 23718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @param obj {@link UiObject} 23818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @return true if the item was found and now is in view else false 23918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @since API Level 16 24018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu */ 24118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu public boolean scrollIntoView(UiObject obj) throws UiObjectNotFoundException { 24218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu Tracer.trace(obj.getSelector()); 24318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu return scrollIntoView(obj.getSelector()); 24418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 24518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 24618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu /** 24718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * Perform a scroll forward action to move through the scrollable layout 24818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * element until a visible item that matches the selector is found. 24918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * 25018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * See {@link #scrollDescriptionIntoView(String)} and {@link #scrollTextIntoView(String)}. 25118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * 25218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @param selector {@link UiSelector} selector 25318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @return true if the item was found and now is in view; else, false 25418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @since API Level 16 25518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu */ 25618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu public boolean scrollIntoView(UiSelector selector) throws UiObjectNotFoundException { 25718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu Tracer.trace(selector); 25818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu // if we happen to be on top of the text we want then return here 25918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu UiSelector childSelector = getSelector().childSelector(selector); 26018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu if (exists(childSelector)) { 26118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu return (true); 26218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } else { 26318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu // we will need to reset the search from the beginning to start search 26418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu scrollToBeginning(mMaxSearchSwipes); 26518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu if (exists(childSelector)) { 26618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu return (true); 26718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 26818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu for (int x = 0; x < mMaxSearchSwipes; x++) { 26918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu boolean scrolled = scrollForward(); 27018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu if(exists(childSelector)) { 27118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu return true; 27218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 27318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu if (!scrolled) { 27418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu return false; 27518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 27618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 27718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 27818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu return false; 27918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 28018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 28118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu /** 28218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * Scrolls forward until the UiObject is fully visible in the scrollable container. 28318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * Use this method to make sure that the child item's edges are not offscreen. 28418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * 28518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @param childObject {@link UiObject} representing the child element 28618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @return true if the child element is already fully visible, or 28718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * if the method scrolled successfully until the child became fully visible; 28818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * otherwise, false if the attempt to scroll failed. 28918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @throws UiObjectNotFoundException 29018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @hide 29118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu */ 29218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu public boolean ensureFullyVisible(UiObject childObject) throws UiObjectNotFoundException { 29318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu Rect actual = childObject.getBounds(); 29418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu Rect visible = childObject.getVisibleBounds(); 29518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu if (visible.width() * visible.height() == actual.width() * actual.height()) { 29618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu // area match, item fully visible 29718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu return true; 29818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 29918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu boolean shouldSwipeForward = false; 30018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu if (mIsVerticalList) { 30118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu // if list is vertical, matching top edge implies obscured bottom edge 30218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu // so we need to scroll list forward 30318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu shouldSwipeForward = actual.top == visible.top; 30418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } else { 30518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu // if list is horizontal, matching left edge implies obscured right edge, 30618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu // so we need to scroll list forward 30718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu shouldSwipeForward = actual.left == visible.left; 30818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 30918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu if (mIsVerticalList) { 31018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu if (shouldSwipeForward) { 31118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu return swipeUp(10); 31218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } else { 31318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu return swipeDown(10); 31418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 31518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } else { 31618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu if (shouldSwipeForward) { 31718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu return swipeLeft(10); 31818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } else { 31918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu return swipeRight(10); 32018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 32118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 32218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 32318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 32418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu /** 32518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * Performs a forward scroll action on the scrollable layout element until 32618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * the text you provided is visible, or until swipe attempts have been exhausted. 32718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * See {@link #setMaxSearchSwipes(int)} 32818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * 32918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @param text test to look for 33018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @return true if item is found; else, false 33118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @since API Level 16 33218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu */ 33318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu public boolean scrollTextIntoView(String text) throws UiObjectNotFoundException { 33418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu Tracer.trace(text); 33518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu return scrollIntoView(new UiSelector().text(text)); 33618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 33718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 33818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu /** 33918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * Sets the maximum number of scrolls allowed when performing a 34018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * scroll action in search of a child element. 34118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * See {@link #getChildByDescription(UiSelector, String)} and 34218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * {@link #getChildByText(UiSelector, String)}. 34318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * 34418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @param swipes the number of search swipes to perform until giving up 34518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @return reference to itself 34618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @since API Level 16 34718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu */ 34818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu public UiScrollable setMaxSearchSwipes(int swipes) { 34918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu Tracer.trace(swipes); 35018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu mMaxSearchSwipes = swipes; 35118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu return this; 35218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 35318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 35418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu /** 35518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * Gets the maximum number of scrolls allowed when performing a 35618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * scroll action in search of a child element. 35718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * See {@link #getChildByDescription(UiSelector, String)} and 35818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * {@link #getChildByText(UiSelector, String)}. 35918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * 36018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @return max the number of search swipes to perform until giving up 36118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @since API Level 16 36218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu */ 36318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu public int getMaxSearchSwipes() { 36418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu Tracer.trace(); 36518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu return mMaxSearchSwipes; 36618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 36718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 36818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu /** 36918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * Performs a forward fling with the default number of fling steps (5). 37018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * If the swipe direction is set to vertical, then the swipes will be 37118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * performed from bottom to top. If the swipe 37218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * direction is set to horizontal, then the swipes will be performed from 37318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * right to left. Make sure to take into account devices configured with 37418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * right-to-left languages like Arabic and Hebrew. 37518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * 37618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @return true if scrolled, false if can't scroll anymore 37718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @since API Level 16 37818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu */ 37918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu public boolean flingForward() throws UiObjectNotFoundException { 38018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu Tracer.trace(); 38118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu return scrollForward(FLING_STEPS); 38218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 38318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 38418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu /** 38518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * Performs a forward scroll with the default number of scroll steps (55). 38618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * If the swipe direction is set to vertical, 38718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * then the swipes will be performed from bottom to top. If the swipe 38818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * direction is set to horizontal, then the swipes will be performed from 38918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * right to left. Make sure to take into account devices configured with 39018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * right-to-left languages like Arabic and Hebrew. 39118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * 39218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @return true if scrolled, false if can't scroll anymore 39318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @since API Level 16 39418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu */ 39518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu public boolean scrollForward() throws UiObjectNotFoundException { 39618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu Tracer.trace(); 39718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu return scrollForward(SCROLL_STEPS); 39818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 39918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 40018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu /** 40118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * Performs a forward scroll. If the swipe direction is set to vertical, 40218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * then the swipes will be performed from bottom to top. If the swipe 40318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * direction is set to horizontal, then the swipes will be performed from 40418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * right to left. Make sure to take into account devices configured with 40518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * right-to-left languages like Arabic and Hebrew. 40618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * 40718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @param steps number of steps. Use this to control the speed of the scroll action 40818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @return true if scrolled, false if can't scroll anymore 40918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @since API Level 16 41018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu */ 41118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu public boolean scrollForward(int steps) throws UiObjectNotFoundException { 41218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu Tracer.trace(steps); 41318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu Log.d(LOG_TAG, "scrollForward() on selector = " + getSelector()); 41418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT); 41518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu if(node == null) { 41618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 41718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 41818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu Rect rect = new Rect(); 41918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu node.getBoundsInScreen(rect); 42018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 42118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu int downX = 0; 42218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu int downY = 0; 42318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu int upX = 0; 42418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu int upY = 0; 42518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 42618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu // scrolling is by default assumed vertically unless the object is explicitly 42718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu // set otherwise by setAsHorizontalContainer() 42818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu if(mIsVerticalList) { 42918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu int swipeAreaAdjust = (int)(rect.height() * getSwipeDeadZonePercentage()); 43018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu // scroll vertically: swipe down -> up 43118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu downX = rect.centerX(); 43218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu downY = rect.bottom - swipeAreaAdjust; 43318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu upX = rect.centerX(); 43418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu upY = rect.top + swipeAreaAdjust; 43518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } else { 43618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu int swipeAreaAdjust = (int)(rect.width() * getSwipeDeadZonePercentage()); 43718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu // scroll horizontally: swipe right -> left 43818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu // TODO: Assuming device is not in right to left language 43918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu downX = rect.right - swipeAreaAdjust; 44018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu downY = rect.centerY(); 44118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu upX = rect.left + swipeAreaAdjust; 44218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu upY = rect.centerY(); 44318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 44418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu return getInteractionController().scrollSwipe(downX, downY, upX, upY, steps); 44518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 44618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 44718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu /** 44818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * Performs a backwards fling action with the default number of fling 44918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * steps (5). If the swipe direction is set to vertical, 45018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * then the swipe will be performed from top to bottom. If the swipe 45118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * direction is set to horizontal, then the swipes will be performed from 45218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * left to right. Make sure to take into account devices configured with 45318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * right-to-left languages like Arabic and Hebrew. 45418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * 45518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @return true if scrolled, and false if can't scroll anymore 45618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @since API Level 16 45718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu */ 45818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu public boolean flingBackward() throws UiObjectNotFoundException { 45918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu Tracer.trace(); 46018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu return scrollBackward(FLING_STEPS); 46118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 46218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 46318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu /** 46418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * Performs a backward scroll with the default number of scroll steps (55). 46518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * If the swipe direction is set to vertical, 46618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * then the swipes will be performed from top to bottom. If the swipe 46718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * direction is set to horizontal, then the swipes will be performed from 46818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * left to right. Make sure to take into account devices configured with 46918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * right-to-left languages like Arabic and Hebrew. 47018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * 47118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @return true if scrolled, and false if can't scroll anymore 47218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @since API Level 16 47318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu */ 47418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu public boolean scrollBackward() throws UiObjectNotFoundException { 47518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu Tracer.trace(); 47618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu return scrollBackward(SCROLL_STEPS); 47718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 47818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 47918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu /** 48018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * Performs a backward scroll. If the swipe direction is set to vertical, 48118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * then the swipes will be performed from top to bottom. If the swipe 48218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * direction is set to horizontal, then the swipes will be performed from 48318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * left to right. Make sure to take into account devices configured with 48418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * right-to-left languages like Arabic and Hebrew. 48518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * 48618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @param steps number of steps. Use this to control the speed of the scroll action. 48718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @return true if scrolled, false if can't scroll anymore 48818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @since API Level 16 48918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu */ 49018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu public boolean scrollBackward(int steps) throws UiObjectNotFoundException { 49118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu Tracer.trace(steps); 49218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu Log.d(LOG_TAG, "scrollBackward() on selector = " + getSelector()); 49318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT); 49418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu if (node == null) { 49518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu throw new UiObjectNotFoundException(getSelector().toString()); 49618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 49718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu Rect rect = new Rect(); 49818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu node.getBoundsInScreen(rect); 49918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 50018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu int downX = 0; 50118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu int downY = 0; 50218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu int upX = 0; 50318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu int upY = 0; 50418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 50518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu // scrolling is by default assumed vertically unless the object is explicitly 50618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu // set otherwise by setAsHorizontalContainer() 50718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu if(mIsVerticalList) { 50818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu int swipeAreaAdjust = (int)(rect.height() * getSwipeDeadZonePercentage()); 50918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu Log.d(LOG_TAG, "scrollToBegining() using vertical scroll"); 51018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu // scroll vertically: swipe up -> down 51118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu downX = rect.centerX(); 51218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu downY = rect.top + swipeAreaAdjust; 51318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu upX = rect.centerX(); 51418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu upY = rect.bottom - swipeAreaAdjust; 51518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } else { 51618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu int swipeAreaAdjust = (int)(rect.width() * getSwipeDeadZonePercentage()); 51718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu Log.d(LOG_TAG, "scrollToBegining() using hotizontal scroll"); 51818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu // scroll horizontally: swipe left -> right 51918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu // TODO: Assuming device is not in right to left language 52018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu downX = rect.left + swipeAreaAdjust; 52118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu downY = rect.centerY(); 52218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu upX = rect.right - swipeAreaAdjust; 52318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu upY = rect.centerY(); 52418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 52518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu return getInteractionController().scrollSwipe(downX, downY, upX, upY, steps); 52618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 52718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 52818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu /** 52918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * Scrolls to the beginning of a scrollable layout element. The beginning 53018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * can be at the top-most edge in the case of vertical controls, or the 53118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * left-most edge for horizontal controls. Make sure to take into account 53218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * devices configured with right-to-left languages like Arabic and Hebrew. 53318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * 53418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @param steps use steps to control the speed, so that it may be a scroll, or fling 53518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @return true on scrolled else false 53618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @since API Level 16 53718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu */ 53818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu public boolean scrollToBeginning(int maxSwipes, int steps) throws UiObjectNotFoundException { 53918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu Tracer.trace(maxSwipes, steps); 54018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu Log.d(LOG_TAG, "scrollToBeginning() on selector = " + getSelector()); 54118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu // protect against potential hanging and return after preset attempts 54218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu for(int x = 0; x < maxSwipes; x++) { 54318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu if(!scrollBackward(steps)) { 54418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu break; 54518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 54618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 54718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu return true; 54818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 54918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 55018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu /** 55118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * Scrolls to the beginning of a scrollable layout element. The beginning 55218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * can be at the top-most edge in the case of vertical controls, or the 55318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * left-most edge for horizontal controls. Make sure to take into account 55418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * devices configured with right-to-left languages like Arabic and Hebrew. 55518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * 55618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @param maxSwipes 55718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @return true on scrolled else false 55818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @since API Level 16 55918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu */ 56018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu public boolean scrollToBeginning(int maxSwipes) throws UiObjectNotFoundException { 56118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu Tracer.trace(maxSwipes); 56218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu return scrollToBeginning(maxSwipes, SCROLL_STEPS); 56318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 56418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 56518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu /** 56618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * Performs a fling gesture to reach the beginning of a scrollable layout element. 56718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * The beginning can be at the top-most edge in the case of vertical controls, or 56818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * the left-most edge for horizontal controls. Make sure to take into 56918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * account devices configured with right-to-left languages like Arabic and Hebrew. 57018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * 57118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @param maxSwipes 57218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @return true on scrolled else false 57318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @since API Level 16 57418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu */ 57518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu public boolean flingToBeginning(int maxSwipes) throws UiObjectNotFoundException { 57618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu Tracer.trace(maxSwipes); 57718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu return scrollToBeginning(maxSwipes, FLING_STEPS); 57818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 57918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 58018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu /** 58118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * Scrolls to the end of a scrollable layout element. The end can be at the 58218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * bottom-most edge in the case of vertical controls, or the right-most edge for 58318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * horizontal controls. Make sure to take into account devices configured with 58418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * right-to-left languages like Arabic and Hebrew. 58518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * 58618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @param steps use steps to control the speed, so that it may be a scroll, or fling 58718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @return true on scrolled else false 58818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @since API Level 16 58918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu */ 59018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu public boolean scrollToEnd(int maxSwipes, int steps) throws UiObjectNotFoundException { 59118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu Tracer.trace(maxSwipes, steps); 59218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu // protect against potential hanging and return after preset attempts 59318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu for(int x = 0; x < maxSwipes; x++) { 59418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu if(!scrollForward(steps)) { 59518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu break; 59618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 59718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 59818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu return true; 59918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 60018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 60118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu /** 60218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * Scrolls to the end of a scrollable layout element. The end can be at the 60318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * bottom-most edge in the case of vertical controls, or the right-most edge for 60418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * horizontal controls. Make sure to take into account devices configured with 60518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * right-to-left languages like Arabic and Hebrew. 60618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * 60718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @param maxSwipes 60818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @return true on scrolled, else false 60918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @since API Level 16 61018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu */ 61118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu public boolean scrollToEnd(int maxSwipes) throws UiObjectNotFoundException { 61218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu Tracer.trace(maxSwipes); 61318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu return scrollToEnd(maxSwipes, SCROLL_STEPS); 61418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 61518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 61618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu /** 61718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * Performs a fling gesture to reach the end of a scrollable layout element. 61818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * The end can be at the bottom-most edge in the case of vertical controls, or 61918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * the right-most edge for horizontal controls. Make sure to take into 62018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * account devices configured with right-to-left languages like Arabic and Hebrew. 62118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * 62218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @param maxSwipes 62318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @return true on scrolled, else false 62418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @since API Level 16 62518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu */ 62618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu public boolean flingToEnd(int maxSwipes) throws UiObjectNotFoundException { 62718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu Tracer.trace(maxSwipes); 62818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu return scrollToEnd(maxSwipes, FLING_STEPS); 62918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 63018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 63118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu /** 63218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * Returns the percentage of a widget's size that's considered as a no-touch 63318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * zone when swiping. The no-touch zone is set as a percentage of a widget's total 63418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * width or height, denoting a margin around the swipable area of the widget. 63518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * Swipes must start and end inside this margin. This is important when the 63618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * widget being swiped may not respond to the swipe if started at a point 63718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * too near to the edge. The default is 10% from either edge. 63818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * 63918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @return a value between 0 and 1 64018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @since API Level 16 64118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu */ 64218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu public double getSwipeDeadZonePercentage() { 64318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu Tracer.trace(); 64418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu return mSwipeDeadZonePercentage; 64518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 64618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu 64718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu /** 64818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * Sets the percentage of a widget's size that's considered as no-touch 64918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * zone when swiping. 65018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * The no-touch zone is set as percentage of a widget's total width or height, 65118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * denoting a margin around the swipable area of the widget. Swipes must 65218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * always start and end inside this margin. This is important when the 65318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * widget being swiped may not respond to the swipe if started at a point 65418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * too near to the edge. The default is 10% from either edge. 65518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * 65618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @param swipeDeadZonePercentage is a value between 0 and 1 65718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @return reference to itself 65818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @since API Level 16 65918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu */ 66018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu public UiScrollable setSwipeDeadZonePercentage(double swipeDeadZonePercentage) { 66118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu Tracer.trace(swipeDeadZonePercentage); 66218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu mSwipeDeadZonePercentage = swipeDeadZonePercentage; 66318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu return this; 66418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu } 66518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu} 666