1 /* 2 * Copyright (C) 2012 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package com.android.uiautomator.core; 17 18 import android.graphics.Rect; 19 import android.util.Log; 20 import android.view.accessibility.AccessibilityNodeInfo; 21 22 /** 23 * UiScrollable is a {@link UiCollection} and provides support for searching 24 * for items in scrollable layout elements. This class can be used with 25 * horizontally or vertically scrollable controls. 26 * @since API Level 16 27 * @deprecated New tests should be written using UI Automator 2.0 which is available as part of the 28 * Android Testing Support Library. 29 */ 30 @Deprecated 31 public class UiScrollable extends UiCollection { 32 private static final String LOG_TAG = UiScrollable.class.getSimpleName(); 33 34 // More steps slows the swipe and prevents contents from being flung too far 35 private static final int SCROLL_STEPS = 55; 36 37 private static final int FLING_STEPS = 5; 38 39 // Restrict a swipe's starting and ending points inside a 10% margin of the target 40 private static final double DEFAULT_SWIPE_DEADZONE_PCT = 0.1; 41 42 // Limits the number of swipes/scrolls performed during a search 43 private static int mMaxSearchSwipes = 30; 44 45 // Used in ScrollForward() and ScrollBackward() to determine swipe direction 46 private boolean mIsVerticalList = true; 47 48 private double mSwipeDeadZonePercentage = DEFAULT_SWIPE_DEADZONE_PCT; 49 50 /** 51 * Constructor. 52 * 53 * @param container a {@link UiSelector} selector to identify the scrollable 54 * layout element. 55 * @since API Level 16 56 */ UiScrollable(UiSelector container)57 public UiScrollable(UiSelector container) { 58 // wrap the container selector with container so that QueryController can handle 59 // this type of enumeration search accordingly 60 super(container); 61 } 62 63 /** 64 * Set the direction of swipes to be vertical when performing scroll actions. 65 * @return reference to itself 66 * @since API Level 16 67 */ setAsVerticalList()68 public UiScrollable setAsVerticalList() { 69 Tracer.trace(); 70 mIsVerticalList = true; 71 return this; 72 } 73 74 /** 75 * Set the direction of swipes to be horizontal when performing scroll actions. 76 * @return reference to itself 77 * @since API Level 16 78 */ setAsHorizontalList()79 public UiScrollable setAsHorizontalList() { 80 Tracer.trace(); 81 mIsVerticalList = false; 82 return this; 83 } 84 85 /** 86 * Used privately when performing swipe searches to decide if an element has become 87 * visible or not. 88 * 89 * @param selector 90 * @return true if found else false 91 * @since API Level 16 92 */ exists(UiSelector selector)93 protected boolean exists(UiSelector selector) { 94 if(getQueryController().findAccessibilityNodeInfo(selector) != null) { 95 return true; 96 } 97 return false; 98 } 99 100 /** 101 * Searches for a child element in the present scrollable container. 102 * The search first looks for a child element that matches the selector 103 * you provided, then looks for the content-description in its children elements. 104 * If both search conditions are fulfilled, the method returns a {@ link UiObject} 105 * representing the element matching the selector (not the child element in its 106 * subhierarchy containing the content-description). By default, this method performs a 107 * scroll search. 108 * See {@link #getChildByDescription(UiSelector, String, boolean)} 109 * 110 * @param childPattern {@link UiSelector} for a child in a scollable layout element 111 * @param text Content-description to find in the children of 112 * the <code>childPattern</code> match 113 * @return {@link UiObject} representing the child element that matches the search conditions 114 * @throws UiObjectNotFoundException 115 * @since API Level 16 116 */ 117 @Override getChildByDescription(UiSelector childPattern, String text)118 public UiObject getChildByDescription(UiSelector childPattern, String text) 119 throws UiObjectNotFoundException { 120 Tracer.trace(childPattern, text); 121 return getChildByDescription(childPattern, text, true); 122 } 123 124 /** 125 * Searches for a child element in the present scrollable container. 126 * The search first looks for a child element that matches the selector 127 * you provided, then looks for the content-description in its children elements. 128 * If both search conditions are fulfilled, the method returns a {@ link UiObject} 129 * representing the element matching the selector (not the child element in its 130 * subhierarchy containing the content-description). 131 * 132 * @param childPattern {@link UiSelector} for a child in a scollable layout element 133 * @param text Content-description to find in the children of 134 * the <code>childPattern</code> match (may be a partial match) 135 * @param allowScrollSearch set to true if scrolling is allowed 136 * @return {@link UiObject} representing the child element that matches the search conditions 137 * @throws UiObjectNotFoundException 138 * @since API Level 16 139 */ getChildByDescription(UiSelector childPattern, String text, boolean allowScrollSearch)140 public UiObject getChildByDescription(UiSelector childPattern, String text, 141 boolean allowScrollSearch) throws UiObjectNotFoundException { 142 Tracer.trace(childPattern, text, allowScrollSearch); 143 if (text != null) { 144 if (allowScrollSearch) { 145 scrollIntoView(new UiSelector().descriptionContains(text)); 146 } 147 return super.getChildByDescription(childPattern, text); 148 } 149 throw new UiObjectNotFoundException("for description= \"" + text + "\""); 150 } 151 152 /** 153 * Searches for a child element in the present scrollable container that 154 * matches the selector you provided. The search is performed without 155 * scrolling and only on visible elements. 156 * 157 * @param childPattern {@link UiSelector} for a child in a scollable layout element 158 * @param instance int number representing the occurance of 159 * a <code>childPattern</code> match 160 * @return {@link UiObject} representing the child element that matches the search conditions 161 * @since API Level 16 162 */ 163 @Override getChildByInstance(UiSelector childPattern, int instance)164 public UiObject getChildByInstance(UiSelector childPattern, int instance) 165 throws UiObjectNotFoundException { 166 Tracer.trace(childPattern, instance); 167 UiSelector patternSelector = UiSelector.patternBuilder(getSelector(), 168 UiSelector.patternBuilder(childPattern).instance(instance)); 169 return new UiObject(patternSelector); 170 } 171 172 /** 173 * Searches for a child element in the present scrollable 174 * container. The search first looks for a child element that matches the 175 * selector you provided, then looks for the text in its children elements. 176 * If both search conditions are fulfilled, the method returns a {@ link UiObject} 177 * representing the element matching the selector (not the child element in its 178 * subhierarchy containing the text). By default, this method performs a 179 * scroll search. 180 * See {@link #getChildByText(UiSelector, String, boolean)} 181 * 182 * @param childPattern {@link UiSelector} selector for a child in a scrollable layout element 183 * @param text String to find in the children of the <code>childPattern</code> match 184 * @return {@link UiObject} representing the child element that matches the search conditions 185 * @throws UiObjectNotFoundException 186 * @since API Level 16 187 */ 188 @Override getChildByText(UiSelector childPattern, String text)189 public UiObject getChildByText(UiSelector childPattern, String text) 190 throws UiObjectNotFoundException { 191 Tracer.trace(childPattern, text); 192 return getChildByText(childPattern, text, true); 193 } 194 195 /** 196 * Searches for a child element in the present scrollable container. The 197 * search first looks for a child element that matches the 198 * selector you provided, then looks for the text in its children elements. 199 * If both search conditions are fulfilled, the method returns a {@ link UiObject} 200 * representing the element matching the selector (not the child element in its 201 * subhierarchy containing the text). 202 * 203 * @param childPattern {@link UiSelector} selector for a child in a scrollable layout element 204 * @param text String to find in the children of the <code>childPattern</code> match 205 * @param allowScrollSearch set to true if scrolling is allowed 206 * @return {@link UiObject} representing the child element that matches the search conditions 207 * @throws UiObjectNotFoundException 208 * @since API Level 16 209 */ getChildByText(UiSelector childPattern, String text, boolean allowScrollSearch)210 public UiObject getChildByText(UiSelector childPattern, String text, boolean allowScrollSearch) 211 throws UiObjectNotFoundException { 212 Tracer.trace(childPattern, text, allowScrollSearch); 213 if (text != null) { 214 if (allowScrollSearch) { 215 scrollIntoView(new UiSelector().text(text)); 216 } 217 return super.getChildByText(childPattern, text); 218 } 219 throw new UiObjectNotFoundException("for text= \"" + text + "\""); 220 } 221 222 /** 223 * Performs a forward scroll action on the scrollable layout element until 224 * the content-description is found, or until swipe attempts have been exhausted. 225 * See {@link #setMaxSearchSwipes(int)} 226 * 227 * @param text content-description to find within the contents of this scrollable layout element. 228 * @return true if item is found; else, false 229 * @since API Level 16 230 */ scrollDescriptionIntoView(String text)231 public boolean scrollDescriptionIntoView(String text) throws UiObjectNotFoundException { 232 Tracer.trace(text); 233 return scrollIntoView(new UiSelector().description(text)); 234 } 235 236 /** 237 * Perform a forward scroll action to move through the scrollable layout element until 238 * a visible item that matches the {@link UiObject} is found. 239 * 240 * @param obj {@link UiObject} 241 * @return true if the item was found and now is in view else false 242 * @since API Level 16 243 */ scrollIntoView(UiObject obj)244 public boolean scrollIntoView(UiObject obj) throws UiObjectNotFoundException { 245 Tracer.trace(obj.getSelector()); 246 return scrollIntoView(obj.getSelector()); 247 } 248 249 /** 250 * Perform a scroll forward action to move through the scrollable layout 251 * element until a visible item that matches the selector is found. 252 * 253 * See {@link #scrollDescriptionIntoView(String)} and {@link #scrollTextIntoView(String)}. 254 * 255 * @param selector {@link UiSelector} selector 256 * @return true if the item was found and now is in view; else, false 257 * @since API Level 16 258 */ scrollIntoView(UiSelector selector)259 public boolean scrollIntoView(UiSelector selector) throws UiObjectNotFoundException { 260 Tracer.trace(selector); 261 // if we happen to be on top of the text we want then return here 262 UiSelector childSelector = getSelector().childSelector(selector); 263 if (exists(childSelector)) { 264 return (true); 265 } else { 266 // we will need to reset the search from the beginning to start search 267 scrollToBeginning(mMaxSearchSwipes); 268 if (exists(childSelector)) { 269 return (true); 270 } 271 for (int x = 0; x < mMaxSearchSwipes; x++) { 272 boolean scrolled = scrollForward(); 273 if(exists(childSelector)) { 274 return true; 275 } 276 if (!scrolled) { 277 return false; 278 } 279 } 280 } 281 return false; 282 } 283 284 /** 285 * Scrolls forward until the UiObject is fully visible in the scrollable container. 286 * Use this method to make sure that the child item's edges are not offscreen. 287 * 288 * @param childObject {@link UiObject} representing the child element 289 * @return true if the child element is already fully visible, or 290 * if the method scrolled successfully until the child became fully visible; 291 * otherwise, false if the attempt to scroll failed. 292 * @throws UiObjectNotFoundException 293 * @hide 294 */ ensureFullyVisible(UiObject childObject)295 public boolean ensureFullyVisible(UiObject childObject) throws UiObjectNotFoundException { 296 Rect actual = childObject.getBounds(); 297 Rect visible = childObject.getVisibleBounds(); 298 if (visible.width() * visible.height() == actual.width() * actual.height()) { 299 // area match, item fully visible 300 return true; 301 } 302 boolean shouldSwipeForward = false; 303 if (mIsVerticalList) { 304 // if list is vertical, matching top edge implies obscured bottom edge 305 // so we need to scroll list forward 306 shouldSwipeForward = actual.top == visible.top; 307 } else { 308 // if list is horizontal, matching left edge implies obscured right edge, 309 // so we need to scroll list forward 310 shouldSwipeForward = actual.left == visible.left; 311 } 312 if (mIsVerticalList) { 313 if (shouldSwipeForward) { 314 return swipeUp(10); 315 } else { 316 return swipeDown(10); 317 } 318 } else { 319 if (shouldSwipeForward) { 320 return swipeLeft(10); 321 } else { 322 return swipeRight(10); 323 } 324 } 325 } 326 327 /** 328 * Performs a forward scroll action on the scrollable layout element until 329 * the text you provided is visible, or until swipe attempts have been exhausted. 330 * See {@link #setMaxSearchSwipes(int)} 331 * 332 * @param text test to look for 333 * @return true if item is found; else, false 334 * @since API Level 16 335 */ scrollTextIntoView(String text)336 public boolean scrollTextIntoView(String text) throws UiObjectNotFoundException { 337 Tracer.trace(text); 338 return scrollIntoView(new UiSelector().text(text)); 339 } 340 341 /** 342 * Sets the maximum number of scrolls allowed when performing a 343 * scroll action in search of a child element. 344 * See {@link #getChildByDescription(UiSelector, String)} and 345 * {@link #getChildByText(UiSelector, String)}. 346 * 347 * @param swipes the number of search swipes to perform until giving up 348 * @return reference to itself 349 * @since API Level 16 350 */ setMaxSearchSwipes(int swipes)351 public UiScrollable setMaxSearchSwipes(int swipes) { 352 Tracer.trace(swipes); 353 mMaxSearchSwipes = swipes; 354 return this; 355 } 356 357 /** 358 * Gets the maximum number of scrolls allowed when performing a 359 * scroll action in search of a child element. 360 * See {@link #getChildByDescription(UiSelector, String)} and 361 * {@link #getChildByText(UiSelector, String)}. 362 * 363 * @return max the number of search swipes to perform until giving up 364 * @since API Level 16 365 */ getMaxSearchSwipes()366 public int getMaxSearchSwipes() { 367 Tracer.trace(); 368 return mMaxSearchSwipes; 369 } 370 371 /** 372 * Performs a forward fling with the default number of fling steps (5). 373 * If the swipe direction is set to vertical, then the swipes will be 374 * performed from bottom to top. If the swipe 375 * direction is set to horizontal, then the swipes will be performed from 376 * right to left. Make sure to take into account devices configured with 377 * right-to-left languages like Arabic and Hebrew. 378 * 379 * @return true if scrolled, false if can't scroll anymore 380 * @since API Level 16 381 */ flingForward()382 public boolean flingForward() throws UiObjectNotFoundException { 383 Tracer.trace(); 384 return scrollForward(FLING_STEPS); 385 } 386 387 /** 388 * Performs a forward scroll with the default number of scroll steps (55). 389 * If the swipe direction is set to vertical, 390 * then the swipes will be performed from bottom to top. If the swipe 391 * direction is set to horizontal, then the swipes will be performed from 392 * right to left. Make sure to take into account devices configured with 393 * right-to-left languages like Arabic and Hebrew. 394 * 395 * @return true if scrolled, false if can't scroll anymore 396 * @since API Level 16 397 */ scrollForward()398 public boolean scrollForward() throws UiObjectNotFoundException { 399 Tracer.trace(); 400 return scrollForward(SCROLL_STEPS); 401 } 402 403 /** 404 * Performs a forward scroll. If the swipe direction is set to vertical, 405 * then the swipes will be performed from bottom to top. If the swipe 406 * direction is set to horizontal, then the swipes will be performed from 407 * right to left. Make sure to take into account devices configured with 408 * right-to-left languages like Arabic and Hebrew. 409 * 410 * @param steps number of steps. Use this to control the speed of the scroll action 411 * @return true if scrolled, false if can't scroll anymore 412 * @since API Level 16 413 */ scrollForward(int steps)414 public boolean scrollForward(int steps) throws UiObjectNotFoundException { 415 Tracer.trace(steps); 416 Log.d(LOG_TAG, "scrollForward() on selector = " + getSelector()); 417 AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT); 418 if(node == null) { 419 throw new UiObjectNotFoundException(getSelector().toString()); 420 } 421 Rect rect = new Rect(); 422 node.getBoundsInScreen(rect); 423 424 int downX = 0; 425 int downY = 0; 426 int upX = 0; 427 int upY = 0; 428 429 // scrolling is by default assumed vertically unless the object is explicitly 430 // set otherwise by setAsHorizontalContainer() 431 if(mIsVerticalList) { 432 int swipeAreaAdjust = (int)(rect.height() * getSwipeDeadZonePercentage()); 433 // scroll vertically: swipe down -> up 434 downX = rect.centerX(); 435 downY = rect.bottom - swipeAreaAdjust; 436 upX = rect.centerX(); 437 upY = rect.top + swipeAreaAdjust; 438 } else { 439 int swipeAreaAdjust = (int)(rect.width() * getSwipeDeadZonePercentage()); 440 // scroll horizontally: swipe right -> left 441 // TODO: Assuming device is not in right to left language 442 downX = rect.right - swipeAreaAdjust; 443 downY = rect.centerY(); 444 upX = rect.left + swipeAreaAdjust; 445 upY = rect.centerY(); 446 } 447 return getInteractionController().scrollSwipe(downX, downY, upX, upY, steps); 448 } 449 450 /** 451 * Performs a backwards fling action with the default number of fling 452 * steps (5). If the swipe direction is set to vertical, 453 * then the swipe will be performed from top to bottom. If the swipe 454 * direction is set to horizontal, then the swipes will be performed from 455 * left to right. Make sure to take into account devices configured with 456 * right-to-left languages like Arabic and Hebrew. 457 * 458 * @return true if scrolled, and false if can't scroll anymore 459 * @since API Level 16 460 */ flingBackward()461 public boolean flingBackward() throws UiObjectNotFoundException { 462 Tracer.trace(); 463 return scrollBackward(FLING_STEPS); 464 } 465 466 /** 467 * Performs a backward scroll with the default number of scroll steps (55). 468 * If the swipe direction is set to vertical, 469 * then the swipes will be performed from top to bottom. If the swipe 470 * direction is set to horizontal, then the swipes will be performed from 471 * left to right. Make sure to take into account devices configured with 472 * right-to-left languages like Arabic and Hebrew. 473 * 474 * @return true if scrolled, and false if can't scroll anymore 475 * @since API Level 16 476 */ scrollBackward()477 public boolean scrollBackward() throws UiObjectNotFoundException { 478 Tracer.trace(); 479 return scrollBackward(SCROLL_STEPS); 480 } 481 482 /** 483 * Performs a backward scroll. If the swipe direction is set to vertical, 484 * then the swipes will be performed from top to bottom. If the swipe 485 * direction is set to horizontal, then the swipes will be performed from 486 * left to right. Make sure to take into account devices configured with 487 * right-to-left languages like Arabic and Hebrew. 488 * 489 * @param steps number of steps. Use this to control the speed of the scroll action. 490 * @return true if scrolled, false if can't scroll anymore 491 * @since API Level 16 492 */ scrollBackward(int steps)493 public boolean scrollBackward(int steps) throws UiObjectNotFoundException { 494 Tracer.trace(steps); 495 Log.d(LOG_TAG, "scrollBackward() on selector = " + getSelector()); 496 AccessibilityNodeInfo node = findAccessibilityNodeInfo(WAIT_FOR_SELECTOR_TIMEOUT); 497 if (node == null) { 498 throw new UiObjectNotFoundException(getSelector().toString()); 499 } 500 Rect rect = new Rect(); 501 node.getBoundsInScreen(rect); 502 503 int downX = 0; 504 int downY = 0; 505 int upX = 0; 506 int upY = 0; 507 508 // scrolling is by default assumed vertically unless the object is explicitly 509 // set otherwise by setAsHorizontalContainer() 510 if(mIsVerticalList) { 511 int swipeAreaAdjust = (int)(rect.height() * getSwipeDeadZonePercentage()); 512 Log.d(LOG_TAG, "scrollToBegining() using vertical scroll"); 513 // scroll vertically: swipe up -> down 514 downX = rect.centerX(); 515 downY = rect.top + swipeAreaAdjust; 516 upX = rect.centerX(); 517 upY = rect.bottom - swipeAreaAdjust; 518 } else { 519 int swipeAreaAdjust = (int)(rect.width() * getSwipeDeadZonePercentage()); 520 Log.d(LOG_TAG, "scrollToBegining() using hotizontal scroll"); 521 // scroll horizontally: swipe left -> right 522 // TODO: Assuming device is not in right to left language 523 downX = rect.left + swipeAreaAdjust; 524 downY = rect.centerY(); 525 upX = rect.right - swipeAreaAdjust; 526 upY = rect.centerY(); 527 } 528 return getInteractionController().scrollSwipe(downX, downY, upX, upY, steps); 529 } 530 531 /** 532 * Scrolls to the beginning of a scrollable layout element. The beginning 533 * can be at the top-most edge in the case of vertical controls, or the 534 * left-most edge for horizontal controls. Make sure to take into account 535 * devices configured with right-to-left languages like Arabic and Hebrew. 536 * 537 * @param steps use steps to control the speed, so that it may be a scroll, or fling 538 * @return true on scrolled else false 539 * @since API Level 16 540 */ scrollToBeginning(int maxSwipes, int steps)541 public boolean scrollToBeginning(int maxSwipes, int steps) throws UiObjectNotFoundException { 542 Tracer.trace(maxSwipes, steps); 543 Log.d(LOG_TAG, "scrollToBeginning() on selector = " + getSelector()); 544 // protect against potential hanging and return after preset attempts 545 for(int x = 0; x < maxSwipes; x++) { 546 if(!scrollBackward(steps)) { 547 break; 548 } 549 } 550 return true; 551 } 552 553 /** 554 * Scrolls to the beginning of a scrollable layout element. The beginning 555 * can be at the top-most edge in the case of vertical controls, or the 556 * left-most edge for horizontal controls. Make sure to take into account 557 * devices configured with right-to-left languages like Arabic and Hebrew. 558 * 559 * @param maxSwipes 560 * @return true on scrolled else false 561 * @since API Level 16 562 */ scrollToBeginning(int maxSwipes)563 public boolean scrollToBeginning(int maxSwipes) throws UiObjectNotFoundException { 564 Tracer.trace(maxSwipes); 565 return scrollToBeginning(maxSwipes, SCROLL_STEPS); 566 } 567 568 /** 569 * Performs a fling gesture to reach the beginning of a scrollable layout element. 570 * The beginning can be at the top-most edge in the case of vertical controls, or 571 * the left-most edge for horizontal controls. Make sure to take into 572 * account devices configured with right-to-left languages like Arabic and Hebrew. 573 * 574 * @param maxSwipes 575 * @return true on scrolled else false 576 * @since API Level 16 577 */ flingToBeginning(int maxSwipes)578 public boolean flingToBeginning(int maxSwipes) throws UiObjectNotFoundException { 579 Tracer.trace(maxSwipes); 580 return scrollToBeginning(maxSwipes, FLING_STEPS); 581 } 582 583 /** 584 * Scrolls to the end of a scrollable layout element. The end can be at the 585 * bottom-most edge in the case of vertical controls, or the right-most edge for 586 * horizontal controls. Make sure to take into account devices configured with 587 * right-to-left languages like Arabic and Hebrew. 588 * 589 * @param steps use steps to control the speed, so that it may be a scroll, or fling 590 * @return true on scrolled else false 591 * @since API Level 16 592 */ scrollToEnd(int maxSwipes, int steps)593 public boolean scrollToEnd(int maxSwipes, int steps) throws UiObjectNotFoundException { 594 Tracer.trace(maxSwipes, steps); 595 // protect against potential hanging and return after preset attempts 596 for(int x = 0; x < maxSwipes; x++) { 597 if(!scrollForward(steps)) { 598 break; 599 } 600 } 601 return true; 602 } 603 604 /** 605 * Scrolls to the end of a scrollable layout element. The end can be at the 606 * bottom-most edge in the case of vertical controls, or the right-most edge for 607 * horizontal controls. Make sure to take into account devices configured with 608 * right-to-left languages like Arabic and Hebrew. 609 * 610 * @param maxSwipes 611 * @return true on scrolled, else false 612 * @since API Level 16 613 */ scrollToEnd(int maxSwipes)614 public boolean scrollToEnd(int maxSwipes) throws UiObjectNotFoundException { 615 Tracer.trace(maxSwipes); 616 return scrollToEnd(maxSwipes, SCROLL_STEPS); 617 } 618 619 /** 620 * Performs a fling gesture to reach the end of a scrollable layout element. 621 * The end can be at the bottom-most edge in the case of vertical controls, or 622 * the right-most edge for horizontal controls. Make sure to take into 623 * account devices configured with right-to-left languages like Arabic and Hebrew. 624 * 625 * @param maxSwipes 626 * @return true on scrolled, else false 627 * @since API Level 16 628 */ flingToEnd(int maxSwipes)629 public boolean flingToEnd(int maxSwipes) throws UiObjectNotFoundException { 630 Tracer.trace(maxSwipes); 631 return scrollToEnd(maxSwipes, FLING_STEPS); 632 } 633 634 /** 635 * Returns the percentage of a widget's size that's considered as a no-touch 636 * zone when swiping. The no-touch zone is set as a percentage of a widget's total 637 * width or height, denoting a margin around the swipable area of the widget. 638 * Swipes must start and end inside this margin. This is important when the 639 * widget being swiped may not respond to the swipe if started at a point 640 * too near to the edge. The default is 10% from either edge. 641 * 642 * @return a value between 0 and 1 643 * @since API Level 16 644 */ getSwipeDeadZonePercentage()645 public double getSwipeDeadZonePercentage() { 646 Tracer.trace(); 647 return mSwipeDeadZonePercentage; 648 } 649 650 /** 651 * Sets the percentage of a widget's size that's considered as no-touch 652 * zone when swiping. 653 * The no-touch zone is set as percentage of a widget's total width or height, 654 * denoting a margin around the swipable area of the widget. Swipes must 655 * always start and end inside this margin. This is important when the 656 * widget being swiped may not respond to the swipe if started at a point 657 * too near to the edge. The default is 10% from either edge. 658 * 659 * @param swipeDeadZonePercentage is a value between 0 and 1 660 * @return reference to itself 661 * @since API Level 16 662 */ setSwipeDeadZonePercentage(double swipeDeadZonePercentage)663 public UiScrollable setSwipeDeadZonePercentage(double swipeDeadZonePercentage) { 664 Tracer.trace(swipeDeadZonePercentage); 665 mSwipeDeadZonePercentage = swipeDeadZonePercentage; 666 return this; 667 } 668 } 669