1 /* 2 * Copyright (C) 2013 DroidDriver committers 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 17 package io.appium.droiddriver.scroll; 18 19 import android.app.UiAutomation; 20 import android.widget.ProgressBar; 21 22 import io.appium.droiddriver.DroidDriver; 23 import io.appium.droiddriver.finders.By; 24 import io.appium.droiddriver.finders.Finder; 25 import io.appium.droiddriver.scroll.Direction.Axis; 26 import io.appium.droiddriver.scroll.Direction.DirectionConverter; 27 import io.appium.droiddriver.scroll.Direction.PhysicalDirection; 28 29 /** 30 * Static utility classes and methods pertaining to {@link Scroller} instances. 31 */ 32 public class Scrollers { 33 /** 34 * Augments the delegate {@link ScrollStepStrategy} - after a successful 35 * scroll, waits until ProgressBar is gone. 36 */ 37 public static abstract class ProgressBarScrollStepStrategy extends ForwardingScrollStepStrategy { 38 @Override scroll(DroidDriver driver, Finder containerFinder, PhysicalDirection direction)39 public boolean scroll(DroidDriver driver, Finder containerFinder, PhysicalDirection direction) { 40 if (super.scroll(driver, containerFinder, direction)) { 41 driver.checkGone(By.className(ProgressBar.class)); 42 return true; 43 } 44 return false; 45 } 46 47 /** Convenience method to wrap {@code delegate} with this class */ wrap(final ScrollStepStrategy delegate)48 public static ScrollStepStrategy wrap(final ScrollStepStrategy delegate) { 49 return new ProgressBarScrollStepStrategy() { 50 @Override 51 protected ScrollStepStrategy delegate() { 52 return delegate; 53 } 54 }; 55 } 56 } 57 58 /** 59 * Returns a new default Scroller that works in simple cases. In complex cases 60 * you may try a {@link StepBasedScroller} with a custom 61 * {@link ScrollStepStrategy}: 62 * <ul> 63 * <li>If the Scroller is used with InstrumentationDriver, 64 * StaticSentinelStrategy may work and it's the simplest.</li> 65 * <li>Otherwise, DynamicSentinelStrategy should work in all cases, including 66 * the case of dynamic list, which shows more items when scrolling beyond the 67 * end. On the other hand, it's complex and needs more configuration.</li> 68 * </ul> 69 * Note if a {@link StepBasedScroller} is returned, it is constructed with 70 * arguments that apply to typical cases. You may want to customize them for 71 * specific cases. For instance, {@code perScrollTimeoutMillis} can be 0L if 72 * there are no asynchronously updated views. To that extent, this method 73 * serves as an example of how to construct {@link Scroller}s rather than 74 * providing the "official" {@link Scroller}. 75 */ 76 public static Scroller newScroller(UiAutomation uiAutomation) { 77 if (uiAutomation != null) { 78 return new StepBasedScroller(100/* maxScrolls */, 1000L/* perScrollTimeoutMillis */, 79 Axis.VERTICAL, new AccessibilityEventScrollStepStrategy(uiAutomation, 1000L, 80 DirectionConverter.STANDARD_CONVERTER), true/* startFromBeginning */); 81 } 82 // TODO: A {@link Scroller} that directly jumps to the view if an 83 // InstrumentationDriver is used. 84 return new StepBasedScroller(100/* maxScrolls */, 1000L/* perScrollTimeoutMillis */, 85 Axis.VERTICAL, StaticSentinelStrategy.DEFAULT, true/* startFromBeginning */); 86 } 87 } 88