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.android.droiddriver.actions.ScrollDirection;
20import com.google.android.droiddriver.scroll.Direction.LogicalDirection;
21import com.google.android.droiddriver.scroll.Direction.PhysicalToLogicalConverter;
22import com.google.common.base.Predicate;
23import com.google.common.base.Predicates;
24
25import java.util.List;
26
27/**
28 * Base {@link SentinelStrategy} for common code.
29 */
30public abstract class AbstractSentinelStrategy implements SentinelStrategy {
31
32  /**
33   * Gets sentinel based on {@link Predicate}.
34   */
35  public static abstract class GetStrategy {
36    protected final Predicate<? super UiElement> predicate;
37    protected final String description;
38
39    protected GetStrategy(Predicate<? super UiElement> predicate, String description) {
40      this.predicate = predicate;
41      this.description = description;
42    }
43
44    public UiElement getSentinel(UiElement parent) {
45      return getSentinel(parent.getChildren(predicate));
46    }
47
48    protected abstract UiElement getSentinel(List<UiElement> children);
49
50    @Override
51    public String toString() {
52      return description;
53    }
54  }
55
56  /**
57   * Decorates an existing {@link GetStrategy} by adding another
58   * {@link Predicate}.
59   */
60  public static class MorePredicateGetStrategy extends GetStrategy {
61    private final GetStrategy original;
62
63    public MorePredicateGetStrategy(GetStrategy original,
64        Predicate<? super UiElement> extraPredicate, String extraDescription) {
65      super(Predicates.and(original.predicate, extraPredicate), extraDescription
66          + original.description);
67      this.original = original;
68    }
69
70    @Override
71    protected UiElement getSentinel(List<UiElement> children) {
72      return original.getSentinel(children);
73    }
74  }
75
76  /**
77   * Returns the first child as the sentinel.
78   */
79  public static final GetStrategy FIRST_CHILD_GETTER = new GetStrategy(Predicates.alwaysTrue(),
80      "FIRST_CHILD") {
81    @Override
82    protected UiElement getSentinel(List<UiElement> children) {
83      return children.get(0);
84    }
85  };
86
87  /**
88   * Returns the last child as the sentinel.
89   */
90  public static final GetStrategy LAST_CHILD_GETTER = new GetStrategy(Predicates.alwaysTrue(),
91      "LAST_CHILD") {
92    @Override
93    protected UiElement getSentinel(List<UiElement> children) {
94      return children.get(children.size() - 1);
95    }
96  };
97
98  /**
99   * Returns the second child as the sentinel. Useful when the activity shows a
100   * fixed first child.
101   */
102  public static final GetStrategy SECOND_CHILD_GETTER = new GetStrategy(Predicates.alwaysTrue(),
103      "SECOND_CHILD") {
104    @Override
105    protected UiElement getSentinel(List<UiElement> children) {
106      return children.get(1);
107    }
108  };
109
110  protected final GetStrategy backwardGetStrategy;
111  protected final GetStrategy forwardGetStrategy;
112  protected final PhysicalToLogicalConverter physicalToLogicalConverter;
113
114  public AbstractSentinelStrategy(GetStrategy backwardGetStrategy, GetStrategy forwardGetStrategy,
115      PhysicalToLogicalConverter physicalToLogicalConverter) {
116    this.backwardGetStrategy = backwardGetStrategy;
117    this.forwardGetStrategy = forwardGetStrategy;
118    this.physicalToLogicalConverter = physicalToLogicalConverter;
119  }
120
121  protected UiElement getSentinel(UiElement parent, ScrollDirection direction) {
122    LogicalDirection logicalDirection = physicalToLogicalConverter.toLogicalDirection(direction);
123    if (logicalDirection == LogicalDirection.BACKWARD) {
124      return backwardGetStrategy.getSentinel(parent);
125    } else {
126      return forwardGetStrategy.getSentinel(parent);
127    }
128  }
129
130  @Override
131  public String toString() {
132    return String.format("{backwardGetStrategy=%s, forwardGetStrategy=%s}", backwardGetStrategy,
133        forwardGetStrategy);
134  }
135}
136