1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "ui/android/overscroll_refresh.h"
6 #include "base/android/scoped_java_ref.h"
7 #include "cc/input/overscroll_behavior.h"
8 #include "cc/layers/layer.h"
9 #include "testing/gtest/include/gtest/gtest.h"
10 #include "ui/android/overscroll_refresh_handler.h"
11
12 namespace ui {
13
14 const float kDipScale = 1.f;
15 const gfx::PointF kStartPos(2.f, 2.f);
16
17 class OverscrollRefreshTest : public OverscrollRefreshHandler,
18 public testing::Test {
19 public:
OverscrollRefreshTest()20 OverscrollRefreshTest() : OverscrollRefreshHandler(nullptr) {}
21
22 // OverscrollRefreshHandler implementation.
PullStart(OverscrollAction type,float startx,float starty,bool navigateForward)23 bool PullStart(OverscrollAction type,
24 float startx,
25 float starty,
26 bool navigateForward) override {
27 started_ = true;
28 return true;
29 }
30
PullUpdate(float x_delta,float y_delta)31 void PullUpdate(float x_delta, float y_delta) override { delta_ += y_delta; }
32
PullRelease(bool allow_refresh)33 void PullRelease(bool allow_refresh) override {
34 released_ = true;
35 refresh_allowed_ = allow_refresh;
36 }
37
PullReset()38 void PullReset() override { reset_ = true; }
39
GetAndResetPullStarted()40 bool GetAndResetPullStarted() {
41 bool result = started_;
42 started_ = false;
43 return result;
44 }
45
GetAndResetPullDelta()46 float GetAndResetPullDelta() {
47 float result = delta_;
48 delta_ = 0;
49 return result;
50 }
51
GetAndResetPullReleased()52 bool GetAndResetPullReleased() {
53 bool result = released_;
54 released_ = false;
55 return result;
56 }
57
GetAndResetRefreshAllowed()58 bool GetAndResetRefreshAllowed() {
59 bool result = refresh_allowed_;
60 refresh_allowed_ = false;
61 return result;
62 }
63
GetAndResetPullReset()64 bool GetAndResetPullReset() {
65 bool result = reset_;
66 reset_ = false;
67 return result;
68 }
69
TestOverscrollBehavior(const cc::OverscrollBehavior & ob,const gfx::Vector2dF & scroll_delta,bool started)70 void TestOverscrollBehavior(const cc::OverscrollBehavior& ob,
71 const gfx::Vector2dF& scroll_delta,
72 bool started) {
73 OverscrollRefresh effect(this, 1.f);
74 effect.OnScrollBegin(kStartPos);
75 EXPECT_FALSE(effect.WillHandleScrollUpdate(scroll_delta));
76 EXPECT_FALSE(effect.IsActive());
77 EXPECT_TRUE(effect.IsAwaitingScrollUpdateAck());
78 effect.OnOverscrolled(ob);
79 EXPECT_EQ(started, GetAndResetPullStarted());
80 EXPECT_EQ(!started, GetAndResetPullReset());
81 }
82
83 private:
84 float delta_ = 0;
85 bool started_ = false;
86 bool released_ = false;
87 bool reset_ = false;
88 bool refresh_allowed_ = false;
89 };
90
TEST_F(OverscrollRefreshTest,Basic)91 TEST_F(OverscrollRefreshTest, Basic) {
92 OverscrollRefresh effect(this, kDipScale);
93
94 EXPECT_FALSE(effect.IsActive());
95 EXPECT_FALSE(effect.IsAwaitingScrollUpdateAck());
96
97 effect.OnScrollBegin(kStartPos);
98 EXPECT_FALSE(effect.IsActive());
99 EXPECT_TRUE(effect.IsAwaitingScrollUpdateAck());
100
101 // The initial scroll should not be consumed, as it should first be offered
102 // to content.
103 gfx::Vector2dF scroll_up(0, 10);
104 EXPECT_FALSE(effect.WillHandleScrollUpdate(scroll_up));
105 EXPECT_FALSE(effect.IsActive());
106 EXPECT_TRUE(effect.IsAwaitingScrollUpdateAck());
107
108 // The unconsumed, overscrolling scroll will trigger the effect.
109 effect.OnOverscrolled(cc::OverscrollBehavior());
110 EXPECT_TRUE(effect.IsActive());
111 EXPECT_FALSE(effect.IsAwaitingScrollUpdateAck());
112 EXPECT_TRUE(GetAndResetPullStarted());
113
114 // Further scrolls will be consumed.
115 EXPECT_TRUE(effect.WillHandleScrollUpdate(gfx::Vector2dF(0, 50)));
116 EXPECT_EQ(50.f, GetAndResetPullDelta());
117 EXPECT_TRUE(effect.IsActive());
118
119 // Even scrolls in the down direction should be consumed.
120 EXPECT_TRUE(effect.WillHandleScrollUpdate(gfx::Vector2dF(0, -50)));
121 EXPECT_EQ(-50.f, GetAndResetPullDelta());
122 EXPECT_TRUE(effect.IsActive());
123
124 // Ending the scroll while beyond the threshold should trigger a refresh.
125 gfx::Vector2dF zero_velocity;
126 EXPECT_FALSE(GetAndResetPullReleased());
127 effect.OnScrollEnd(zero_velocity);
128 EXPECT_FALSE(effect.IsActive());
129 EXPECT_TRUE(GetAndResetPullReleased());
130 EXPECT_TRUE(GetAndResetRefreshAllowed());
131 }
132
TEST_F(OverscrollRefreshTest,NotTriggeredIfInitialYOffsetIsNotZero)133 TEST_F(OverscrollRefreshTest, NotTriggeredIfInitialYOffsetIsNotZero) {
134 OverscrollRefresh effect(this, kDipScale);
135
136 // A positive y scroll offset at the start of scroll will prevent activation,
137 // even if the subsequent scroll overscrolls upward.
138 gfx::Vector2dF nonzero_offset(0, 10);
139 gfx::SizeF viewport(100, 100);
140 bool overflow_y_hidden = false;
141 effect.OnFrameUpdated(viewport, nonzero_offset, overflow_y_hidden);
142 effect.OnScrollBegin(kStartPos);
143
144 effect.OnFrameUpdated(viewport, gfx::Vector2dF(), overflow_y_hidden);
145 ASSERT_FALSE(effect.WillHandleScrollUpdate(gfx::Vector2dF(0, 10)));
146 EXPECT_FALSE(effect.IsActive());
147 EXPECT_FALSE(effect.IsAwaitingScrollUpdateAck());
148 effect.OnOverscrolled(cc::OverscrollBehavior());
149 EXPECT_FALSE(effect.IsActive());
150 EXPECT_FALSE(effect.IsAwaitingScrollUpdateAck());
151 EXPECT_FALSE(effect.WillHandleScrollUpdate(gfx::Vector2dF(0, 500)));
152 effect.OnScrollEnd(gfx::Vector2dF());
153 EXPECT_FALSE(GetAndResetPullStarted());
154 EXPECT_FALSE(GetAndResetPullReleased());
155 }
156
TEST_F(OverscrollRefreshTest,NotTriggeredIfOverflowYHidden)157 TEST_F(OverscrollRefreshTest, NotTriggeredIfOverflowYHidden) {
158 OverscrollRefresh effect(this, kDipScale);
159
160 // overflow-y:hidden at the start of scroll will prevent activation.
161 gfx::Vector2dF zero_offset;
162 bool overflow_y_hidden = true;
163 gfx::SizeF viewport(100, 100);
164 effect.OnFrameUpdated(viewport, zero_offset, overflow_y_hidden);
165 effect.OnScrollBegin(kStartPos);
166
167 ASSERT_FALSE(effect.WillHandleScrollUpdate(gfx::Vector2dF(0, 10)));
168 EXPECT_FALSE(effect.IsActive());
169 EXPECT_FALSE(effect.IsAwaitingScrollUpdateAck());
170 effect.OnOverscrolled(cc::OverscrollBehavior());
171 EXPECT_FALSE(effect.IsActive());
172 EXPECT_FALSE(effect.IsAwaitingScrollUpdateAck());
173 EXPECT_FALSE(effect.WillHandleScrollUpdate(gfx::Vector2dF(0, 500)));
174 effect.OnScrollEnd(gfx::Vector2dF());
175 EXPECT_FALSE(GetAndResetPullStarted());
176 EXPECT_FALSE(GetAndResetPullReleased());
177 }
178
TEST_F(OverscrollRefreshTest,NotTriggeredIfInitialScrollDownward)179 TEST_F(OverscrollRefreshTest, NotTriggeredIfInitialScrollDownward) {
180 OverscrollRefresh effect(this, kDipScale);
181 effect.OnScrollBegin(kStartPos);
182
183 // A downward initial scroll will prevent activation, even if the subsequent
184 // scroll overscrolls upward.
185 ASSERT_FALSE(effect.WillHandleScrollUpdate(gfx::Vector2dF(0, -10)));
186 EXPECT_FALSE(effect.IsActive());
187 EXPECT_FALSE(effect.IsAwaitingScrollUpdateAck());
188
189 effect.OnOverscrolled(cc::OverscrollBehavior());
190 EXPECT_FALSE(effect.IsActive());
191 EXPECT_FALSE(effect.IsAwaitingScrollUpdateAck());
192 EXPECT_FALSE(effect.WillHandleScrollUpdate(gfx::Vector2dF(0, 500)));
193 effect.OnScrollEnd(gfx::Vector2dF());
194 EXPECT_FALSE(GetAndResetPullReleased());
195 }
196
TEST_F(OverscrollRefreshTest,NotTriggeredIfInitialScrollOrTouchConsumed)197 TEST_F(OverscrollRefreshTest, NotTriggeredIfInitialScrollOrTouchConsumed) {
198 OverscrollRefresh effect(this, kDipScale);
199 effect.OnScrollBegin(kStartPos);
200 ASSERT_FALSE(effect.WillHandleScrollUpdate(gfx::Vector2dF(0, 10)));
201 ASSERT_TRUE(effect.IsAwaitingScrollUpdateAck());
202
203 // Consumption of the initial touchmove or scroll should prevent future
204 // activation.
205 effect.Reset();
206 effect.OnOverscrolled(cc::OverscrollBehavior());
207 EXPECT_FALSE(effect.IsActive());
208 EXPECT_FALSE(effect.IsAwaitingScrollUpdateAck());
209 EXPECT_FALSE(effect.WillHandleScrollUpdate(gfx::Vector2dF(0, 500)));
210 effect.OnOverscrolled(cc::OverscrollBehavior());
211 EXPECT_FALSE(effect.IsActive());
212 EXPECT_FALSE(effect.IsAwaitingScrollUpdateAck());
213 EXPECT_FALSE(effect.WillHandleScrollUpdate(gfx::Vector2dF(0, 500)));
214 effect.OnScrollEnd(gfx::Vector2dF());
215 EXPECT_FALSE(GetAndResetPullStarted());
216 EXPECT_FALSE(GetAndResetPullReleased());
217 }
218
TEST_F(OverscrollRefreshTest,NotTriggeredIfFlungDownward)219 TEST_F(OverscrollRefreshTest, NotTriggeredIfFlungDownward) {
220 OverscrollRefresh effect(this, kDipScale);
221 effect.OnScrollBegin(kStartPos);
222 ASSERT_FALSE(effect.WillHandleScrollUpdate(gfx::Vector2dF(0, 10)));
223 ASSERT_TRUE(effect.IsAwaitingScrollUpdateAck());
224 effect.OnOverscrolled(cc::OverscrollBehavior());
225 ASSERT_TRUE(effect.IsActive());
226 EXPECT_TRUE(GetAndResetPullStarted());
227
228 // Terminating the pull with a down-directed fling should prevent triggering.
229 effect.OnScrollEnd(gfx::Vector2dF(0, -1000));
230 EXPECT_TRUE(GetAndResetPullReleased());
231 EXPECT_FALSE(GetAndResetRefreshAllowed());
232 }
233
TEST_F(OverscrollRefreshTest,NotTriggeredIfReleasedWithoutActivation)234 TEST_F(OverscrollRefreshTest, NotTriggeredIfReleasedWithoutActivation) {
235 OverscrollRefresh effect(this, kDipScale);
236 effect.OnScrollBegin(kStartPos);
237 ASSERT_FALSE(effect.WillHandleScrollUpdate(gfx::Vector2dF(0, 10)));
238 ASSERT_TRUE(effect.IsAwaitingScrollUpdateAck());
239 effect.OnOverscrolled(cc::OverscrollBehavior());
240 ASSERT_TRUE(effect.IsActive());
241 EXPECT_TRUE(GetAndResetPullStarted());
242
243 // An early release should prevent the refresh action from firing.
244 effect.ReleaseWithoutActivation();
245 effect.OnScrollEnd(gfx::Vector2dF());
246 EXPECT_TRUE(GetAndResetPullReleased());
247 EXPECT_FALSE(GetAndResetRefreshAllowed());
248 }
249
TEST_F(OverscrollRefreshTest,NotTriggeredIfReset)250 TEST_F(OverscrollRefreshTest, NotTriggeredIfReset) {
251 OverscrollRefresh effect(this, kDipScale);
252 effect.OnScrollBegin(kStartPos);
253 ASSERT_FALSE(effect.WillHandleScrollUpdate(gfx::Vector2dF(0, 10)));
254 ASSERT_TRUE(effect.IsAwaitingScrollUpdateAck());
255 effect.OnOverscrolled(cc::OverscrollBehavior());
256 ASSERT_TRUE(effect.IsActive());
257 EXPECT_TRUE(GetAndResetPullStarted());
258
259 // An early reset should prevent the refresh action from firing.
260 effect.Reset();
261 EXPECT_TRUE(GetAndResetPullReset());
262 effect.OnScrollEnd(gfx::Vector2dF());
263 EXPECT_FALSE(GetAndResetPullReleased());
264 }
265
TEST_F(OverscrollRefreshTest,OverscrollBehaviorYAutoTriggersStart)266 TEST_F(OverscrollRefreshTest, OverscrollBehaviorYAutoTriggersStart) {
267 TestOverscrollBehavior(cc::OverscrollBehavior(), gfx::Vector2dF(0, 10), true);
268 }
269
TEST_F(OverscrollRefreshTest,OverscrollBehaviorYContainPreventsTriggerStart)270 TEST_F(OverscrollRefreshTest, OverscrollBehaviorYContainPreventsTriggerStart) {
271 auto ob = cc::OverscrollBehavior();
272 ob.y = cc::OverscrollBehavior::OverscrollBehaviorType::
273 kOverscrollBehaviorTypeContain;
274 TestOverscrollBehavior(ob, gfx::Vector2dF(0, 10), false);
275 }
276
TEST_F(OverscrollRefreshTest,OverscrollBehaviorYNonePreventsTriggerStart)277 TEST_F(OverscrollRefreshTest, OverscrollBehaviorYNonePreventsTriggerStart) {
278 auto ob = cc::OverscrollBehavior();
279 ob.y = cc::OverscrollBehavior::OverscrollBehaviorType::
280 kOverscrollBehaviorTypeNone;
281 TestOverscrollBehavior(ob, gfx::Vector2dF(0, 10), false);
282 }
283
TEST_F(OverscrollRefreshTest,OverscrollBehaviorXAutoTriggersStart)284 TEST_F(OverscrollRefreshTest, OverscrollBehaviorXAutoTriggersStart) {
285 TestOverscrollBehavior(cc::OverscrollBehavior(), gfx::Vector2dF(10, 0), true);
286 }
287
TEST_F(OverscrollRefreshTest,OverscrollBehaviorXContainPreventsTriggerStart)288 TEST_F(OverscrollRefreshTest, OverscrollBehaviorXContainPreventsTriggerStart) {
289 auto ob = cc::OverscrollBehavior();
290 ob.x = cc::OverscrollBehavior::OverscrollBehaviorType::
291 kOverscrollBehaviorTypeContain;
292 TestOverscrollBehavior(ob, gfx::Vector2dF(10, 0), false);
293 }
294
TEST_F(OverscrollRefreshTest,OverscrollBehaviorXNonePreventsTriggerStart)295 TEST_F(OverscrollRefreshTest, OverscrollBehaviorXNonePreventsTriggerStart) {
296 auto ob = cc::OverscrollBehavior();
297 ob.x = cc::OverscrollBehavior::OverscrollBehaviorType::
298 kOverscrollBehaviorTypeNone;
299 TestOverscrollBehavior(ob, gfx::Vector2dF(10, 0), false);
300 }
301
302 } // namespace ui
303