SentinelStrategy.java revision 9c92f46280cf3943701e75349833c68b584992e2
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 */
16package com.google.android.droiddriver.scroll;
17
18import com.google.android.droiddriver.UiElement;
19import com.google.common.base.Predicate;
20import com.google.common.base.Predicates;
21
22import java.util.List;
23
24/**
25 * Interface for determining whether scrolling is possible based on a sentinel.
26 */
27public interface SentinelStrategy extends ScrollStepStrategy {
28
29  /**
30   * Gets sentinel based on {@link Predicate}.
31   */
32  public static abstract class Getter {
33    protected final Predicate<? super UiElement> predicate;
34    protected final String description;
35
36    protected Getter(Predicate<? super UiElement> predicate, String description) {
37      this.predicate = predicate;
38      this.description = description;
39    }
40
41    /**
42     * Gets the sentinel, which must be an immediate child of {@code container}
43     * -- not a descendant. Note this could be null if {@code container} has not
44     * finished updating.
45     */
46    public UiElement getSentinel(UiElement container) {
47      return getSentinel(container.getChildren(predicate));
48    }
49
50    protected abstract UiElement getSentinel(List<? extends UiElement> children);
51
52    @Override
53    public String toString() {
54      return description;
55    }
56  }
57
58  /**
59   * Decorates an existing {@link Getter} by adding another {@link Predicate}.
60   */
61  public static class MorePredicateGetter extends Getter {
62    private final Getter original;
63
64    public MorePredicateGetter(Getter original, Predicate<? super UiElement> extraPredicate,
65        String extraDescription) {
66      super(Predicates.and(original.predicate, extraPredicate), extraDescription
67          + original.description);
68      this.original = original;
69    }
70
71    @Override
72    protected UiElement getSentinel(List<? extends UiElement> children) {
73      return original.getSentinel(children);
74    }
75  }
76
77  /**
78   * Returns the first child as the sentinel.
79   */
80  public static final Getter FIRST_CHILD_GETTER =
81      new Getter(Predicates.alwaysTrue(), "FIRST_CHILD") {
82        @Override
83        protected UiElement getSentinel(List<? extends UiElement> children) {
84          return children.isEmpty() ? null : children.get(0);
85        }
86      };
87  /**
88   * Returns the last child as the sentinel.
89   */
90  public static final Getter LAST_CHILD_GETTER = new Getter(Predicates.alwaysTrue(), "LAST_CHILD") {
91    @Override
92    protected UiElement getSentinel(List<? extends UiElement> children) {
93      return children.isEmpty() ? null : children.get(children.size() - 1);
94    }
95  };
96  /**
97   * Returns the second last child as the sentinel. Useful when the activity
98   * always shows the last child as an anchor (for example a footer).
99   * <p>
100   * Sometimes uiautomatorviewer may not show the anchor as the last child, due
101   * to the reordering by layout described in {@link UiElement#getChildren}.
102   * This is not a problem with UiAutomationDriver because it sees the same as
103   * uiautomatorviewer does, but could be a problem with InstrumentationDriver.
104   * </p>
105   */
106  public static final Getter SECOND_LAST_CHILD_GETTER = new Getter(Predicates.alwaysTrue(),
107      "SECOND_LAST_CHILD") {
108    @Override
109    protected UiElement getSentinel(List<? extends UiElement> children) {
110      return children.size() < 2 ? null : children.get(children.size() - 2);
111    }
112  };
113  /**
114   * Returns the second child as the sentinel. Useful when the activity shows a
115   * fixed first child.
116   */
117  public static final Getter SECOND_CHILD_GETTER = new Getter(Predicates.alwaysTrue(),
118      "SECOND_CHILD") {
119    @Override
120    protected UiElement getSentinel(List<? extends UiElement> children) {
121      return children.size() <= 1 ? null : children.get(1);
122    }
123  };
124}
125