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.
5 #include "cc/layers/layer.h"
6 #include "content/browser/android/overscroll_refresh.h"
7 #include "testing/gtest/include/gtest/gtest.h"
8 #include "ui/android/resources/resource_manager.h"
12 class OverscrollRefreshTest
: public OverscrollRefreshClient
,
13 public ui::ResourceManager
,
14 public testing::Test
{
16 OverscrollRefreshTest()
17 : refresh_triggered_(false), still_refreshing_(false) {}
19 // OverscrollRefreshClient implementation.
20 void TriggerRefresh() override
{
21 refresh_triggered_
= true;
22 still_refreshing_
= true;
25 bool IsStillRefreshing() const override
{ return still_refreshing_
; }
27 // ResourceManager implementation.
28 base::android::ScopedJavaLocalRef
<jobject
> GetJavaObject() override
{
29 return base::android::ScopedJavaLocalRef
<jobject
>();
32 Resource
* GetResource(ui::AndroidResourceType res_type
, int res_id
) override
{
36 void PreloadResource(ui::AndroidResourceType res_type
, int res_id
) override
{}
38 bool GetAndResetRefreshTriggered() {
39 bool triggered
= refresh_triggered_
;
40 refresh_triggered_
= false;
44 void PullBeyondActivationThreshold(OverscrollRefresh
* effect
) {
45 for (int i
= 0; i
< OverscrollRefresh::kMinPullsToActivate
; ++i
)
46 EXPECT_TRUE(effect
->WillHandleScrollUpdate(gfx::Vector2dF(0, 100)));
51 scoped_ptr
<OverscrollRefresh
> CreateEffect() {
52 const float kDragTargetPixels
= 100;
53 const bool kMirror
= false;
54 scoped_ptr
<OverscrollRefresh
> effect(
55 new OverscrollRefresh(this, this, kDragTargetPixels
, kMirror
));
57 const gfx::SizeF
kViewportSize(512, 512);
58 const gfx::Vector2dF kScrollOffset
;
59 const bool kOverflowYHidden
= false;
60 effect
->UpdateDisplay(kViewportSize
, kScrollOffset
, kOverflowYHidden
);
65 void SignalRefreshCompleted() { still_refreshing_
= false; }
68 bool refresh_triggered_
;
69 bool still_refreshing_
;
72 TEST_F(OverscrollRefreshTest
, Basic
) {
73 scoped_ptr
<OverscrollRefresh
> effect
= CreateEffect();
75 EXPECT_FALSE(effect
->IsActive());
76 EXPECT_FALSE(effect
->IsAwaitingScrollUpdateAck());
78 effect
->OnScrollBegin();
79 EXPECT_FALSE(effect
->IsActive());
80 EXPECT_TRUE(effect
->IsAwaitingScrollUpdateAck());
82 // The initial scroll should not be consumed, as it should first be offered
84 gfx::Vector2dF
scroll_up(0, 10);
85 EXPECT_FALSE(effect
->WillHandleScrollUpdate(scroll_up
));
86 EXPECT_FALSE(effect
->IsActive());
87 EXPECT_TRUE(effect
->IsAwaitingScrollUpdateAck());
89 // The unconsumed, overscrolling scroll will trigger the effect->
90 effect
->OnScrollUpdateAck(false);
91 EXPECT_TRUE(effect
->IsActive());
92 EXPECT_FALSE(effect
->IsAwaitingScrollUpdateAck());
94 // Further scrolls will be consumed.
95 EXPECT_TRUE(effect
->WillHandleScrollUpdate(gfx::Vector2dF(0, 50)));
96 EXPECT_TRUE(effect
->IsActive());
98 // Even scrolls in the down direction should be consumed.
99 EXPECT_TRUE(effect
->WillHandleScrollUpdate(gfx::Vector2dF(0, -50)));
100 EXPECT_TRUE(effect
->IsActive());
102 // Feed enough scrolls to the effect to exceeds the threshold.
103 PullBeyondActivationThreshold(effect
.get());
104 EXPECT_TRUE(effect
->IsActive());
106 // Ending the scroll while beyond the threshold should trigger a refresh.
107 gfx::Vector2dF zero_velocity
;
108 EXPECT_FALSE(GetAndResetRefreshTriggered());
109 effect
->OnScrollEnd(zero_velocity
);
110 EXPECT_TRUE(effect
->IsActive());
111 EXPECT_TRUE(GetAndResetRefreshTriggered());
112 SignalRefreshCompleted();
114 // Ensure animation doesn't explode.
115 base::TimeTicks initial_time
= base::TimeTicks::Now();
116 base::TimeTicks current_time
= initial_time
;
117 scoped_refptr
<cc::Layer
> layer
= cc::Layer::Create();
118 while (effect
->Animate(current_time
, layer
.get()))
119 current_time
+= base::TimeDelta::FromMilliseconds(16);
121 // The effect should terminate in a timely fashion.
122 EXPECT_GT(current_time
.ToInternalValue(), initial_time
.ToInternalValue());
124 current_time
.ToInternalValue(),
125 (initial_time
+ base::TimeDelta::FromSeconds(10)).ToInternalValue());
126 EXPECT_FALSE(effect
->IsActive());
129 TEST_F(OverscrollRefreshTest
, AnimationTerminatesEvenIfRefreshNeverTerminates
) {
130 scoped_ptr
<OverscrollRefresh
> effect
= CreateEffect();
131 effect
->OnScrollBegin();
132 ASSERT_FALSE(effect
->WillHandleScrollUpdate(gfx::Vector2dF(0, 10)));
133 ASSERT_TRUE(effect
->IsAwaitingScrollUpdateAck());
134 effect
->OnScrollUpdateAck(false);
135 ASSERT_TRUE(effect
->IsActive());
136 PullBeyondActivationThreshold(effect
.get());
137 ASSERT_TRUE(effect
->IsActive());
138 effect
->OnScrollEnd(gfx::Vector2dF(0, 0));
139 ASSERT_TRUE(GetAndResetRefreshTriggered());
141 // Verify that the animation terminates even if the triggered refresh
142 // action never terminates (i.e., |still_refreshing_| is always true).
143 base::TimeTicks initial_time
= base::TimeTicks::Now();
144 base::TimeTicks current_time
= initial_time
;
145 scoped_refptr
<cc::Layer
> layer
= cc::Layer::Create();
146 while (effect
->Animate(current_time
, layer
.get()))
147 current_time
+= base::TimeDelta::FromMilliseconds(16);
149 EXPECT_GT(current_time
.ToInternalValue(), initial_time
.ToInternalValue());
151 current_time
.ToInternalValue(),
152 (initial_time
+ base::TimeDelta::FromSeconds(10)).ToInternalValue());
153 EXPECT_FALSE(effect
->IsActive());
156 TEST_F(OverscrollRefreshTest
, NotTriggeredIfBelowThreshold
) {
157 scoped_ptr
<OverscrollRefresh
> effect
= CreateEffect();
158 effect
->OnScrollBegin();
159 ASSERT_FALSE(effect
->WillHandleScrollUpdate(gfx::Vector2dF(0, 10)));
160 ASSERT_TRUE(effect
->IsAwaitingScrollUpdateAck());
161 effect
->OnScrollUpdateAck(false);
162 ASSERT_TRUE(effect
->IsActive());
164 // Terminating the pull before it exceeds the threshold will prevent refresh.
165 EXPECT_TRUE(effect
->WillHandleScrollUpdate(gfx::Vector2dF(0, 10)));
166 effect
->OnScrollEnd(gfx::Vector2dF());
167 EXPECT_FALSE(GetAndResetRefreshTriggered());
170 TEST_F(OverscrollRefreshTest
, NotTriggeredIfInitialYOffsetIsNotZero
) {
171 scoped_ptr
<OverscrollRefresh
> effect
= CreateEffect();
173 // A positive y scroll offset at the start of scroll will prevent activation,
174 // even if the subsequent scroll overscrolls upward.
175 gfx::SizeF
viewport_size(512, 512);
176 gfx::Vector2dF
nonzero_offset(0, 10);
177 bool overflow_y_hidden
= false;
178 effect
->UpdateDisplay(viewport_size
, nonzero_offset
, overflow_y_hidden
);
179 effect
->OnScrollBegin();
181 ASSERT_FALSE(effect
->WillHandleScrollUpdate(gfx::Vector2dF(0, 10)));
182 EXPECT_FALSE(effect
->IsActive());
183 EXPECT_FALSE(effect
->IsAwaitingScrollUpdateAck());
184 effect
->OnScrollUpdateAck(false);
185 EXPECT_FALSE(effect
->IsActive());
186 EXPECT_FALSE(effect
->IsAwaitingScrollUpdateAck());
187 EXPECT_FALSE(effect
->WillHandleScrollUpdate(gfx::Vector2dF(0, 500)));
188 effect
->OnScrollEnd(gfx::Vector2dF());
189 EXPECT_FALSE(GetAndResetRefreshTriggered());
192 TEST_F(OverscrollRefreshTest
, NotTriggeredIfOverflowYHidden
) {
193 scoped_ptr
<OverscrollRefresh
> effect
= CreateEffect();
195 // "overflow-y: hidden" on the root layer will prevent activation,
196 // even if the subsequent scroll overscrolls upward.
197 gfx::SizeF
viewport_size(512, 512);
198 gfx::Vector2dF zero_offset
;
199 bool overflow_y_hidden
= true;
200 effect
->UpdateDisplay(viewport_size
, zero_offset
, overflow_y_hidden
);
201 effect
->OnScrollBegin();
202 ASSERT_FALSE(effect
->WillHandleScrollUpdate(gfx::Vector2dF(0, 10)));
203 EXPECT_FALSE(effect
->IsActive());
204 EXPECT_FALSE(effect
->IsAwaitingScrollUpdateAck());
205 effect
->OnScrollUpdateAck(false);
206 EXPECT_FALSE(effect
->IsActive());
207 EXPECT_FALSE(effect
->IsAwaitingScrollUpdateAck());
208 EXPECT_FALSE(effect
->WillHandleScrollUpdate(gfx::Vector2dF(0, 500)));
209 effect
->OnScrollEnd(gfx::Vector2dF());
210 EXPECT_FALSE(GetAndResetRefreshTriggered());
213 TEST_F(OverscrollRefreshTest
, NotTriggeredIfInitialScrollDownward
) {
214 scoped_ptr
<OverscrollRefresh
> effect
= CreateEffect();
215 effect
->OnScrollBegin();
217 // A downward initial scroll will prevent activation, even if the subsequent
218 // scroll overscrolls upward.
219 ASSERT_FALSE(effect
->WillHandleScrollUpdate(gfx::Vector2dF(0, -10)));
220 EXPECT_FALSE(effect
->IsActive());
221 EXPECT_FALSE(effect
->IsAwaitingScrollUpdateAck());
223 effect
->OnScrollUpdateAck(false);
224 EXPECT_FALSE(effect
->IsActive());
225 EXPECT_FALSE(effect
->IsAwaitingScrollUpdateAck());
226 EXPECT_FALSE(effect
->WillHandleScrollUpdate(gfx::Vector2dF(0, 500)));
227 effect
->OnScrollEnd(gfx::Vector2dF());
228 EXPECT_FALSE(GetAndResetRefreshTriggered());
231 TEST_F(OverscrollRefreshTest
, NotTriggeredIfInitialScrollOrTouchConsumed
) {
232 scoped_ptr
<OverscrollRefresh
> effect
= CreateEffect();
233 effect
->OnScrollBegin();
234 ASSERT_FALSE(effect
->WillHandleScrollUpdate(gfx::Vector2dF(0, 10)));
235 ASSERT_TRUE(effect
->IsAwaitingScrollUpdateAck());
237 // Consumption of the initial touchmove or scroll should prevent future
239 effect
->OnScrollUpdateAck(true);
240 EXPECT_FALSE(effect
->IsActive());
241 EXPECT_FALSE(effect
->IsAwaitingScrollUpdateAck());
242 EXPECT_FALSE(effect
->WillHandleScrollUpdate(gfx::Vector2dF(0, 500)));
243 effect
->OnScrollUpdateAck(false);
244 EXPECT_FALSE(effect
->IsActive());
245 EXPECT_FALSE(effect
->IsAwaitingScrollUpdateAck());
246 EXPECT_FALSE(effect
->WillHandleScrollUpdate(gfx::Vector2dF(0, 500)));
247 effect
->OnScrollEnd(gfx::Vector2dF());
248 EXPECT_FALSE(GetAndResetRefreshTriggered());
251 TEST_F(OverscrollRefreshTest
, NotTriggeredIfInitialScrollsJanked
) {
252 scoped_ptr
<OverscrollRefresh
> effect
= CreateEffect();
253 effect
->OnScrollBegin();
254 ASSERT_FALSE(effect
->WillHandleScrollUpdate(gfx::Vector2dF(0, 10)));
255 ASSERT_TRUE(effect
->IsAwaitingScrollUpdateAck());
256 effect
->OnScrollUpdateAck(false);
257 ASSERT_TRUE(effect
->IsActive());
259 // It should take more than just one or two large scrolls to trigger,
260 // mitigating likelihood of jank triggering the effect->
261 EXPECT_TRUE(effect
->WillHandleScrollUpdate(gfx::Vector2dF(0, 500)));
262 EXPECT_TRUE(effect
->WillHandleScrollUpdate(gfx::Vector2dF(0, 500)));
263 effect
->OnScrollEnd(gfx::Vector2dF());
264 EXPECT_FALSE(GetAndResetRefreshTriggered());
267 TEST_F(OverscrollRefreshTest
, NotTriggeredIfFlungDownward
) {
268 scoped_ptr
<OverscrollRefresh
> effect
= CreateEffect();
269 effect
->OnScrollBegin();
270 ASSERT_FALSE(effect
->WillHandleScrollUpdate(gfx::Vector2dF(0, 10)));
271 ASSERT_TRUE(effect
->IsAwaitingScrollUpdateAck());
272 effect
->OnScrollUpdateAck(false);
273 ASSERT_TRUE(effect
->IsActive());
275 // Ensure the pull exceeds the necessary threshold.
276 PullBeyondActivationThreshold(effect
.get());
277 ASSERT_TRUE(effect
->IsActive());
279 // Terminating the pull with a down-directed fling should prevent triggering.
280 effect
->OnScrollEnd(gfx::Vector2dF(0, -1000));
281 EXPECT_FALSE(GetAndResetRefreshTriggered());
284 TEST_F(OverscrollRefreshTest
, NotTriggeredIfReleasedWithoutActivation
) {
285 scoped_ptr
<OverscrollRefresh
> effect
= CreateEffect();
286 effect
->OnScrollBegin();
287 ASSERT_FALSE(effect
->WillHandleScrollUpdate(gfx::Vector2dF(0, 10)));
288 ASSERT_TRUE(effect
->IsAwaitingScrollUpdateAck());
289 effect
->OnScrollUpdateAck(false);
290 ASSERT_TRUE(effect
->IsActive());
292 // Ensure the pull exceeds the necessary threshold.
293 PullBeyondActivationThreshold(effect
.get());
294 ASSERT_TRUE(effect
->IsActive());
296 // An early release should prevent the refresh action from firing.
297 effect
->ReleaseWithoutActivation();
298 effect
->OnScrollEnd(gfx::Vector2dF());
299 EXPECT_FALSE(GetAndResetRefreshTriggered());
301 // The early release should trigger a dismissal animation.
302 EXPECT_TRUE(effect
->IsActive());
303 base::TimeTicks initial_time
= base::TimeTicks::Now();
304 base::TimeTicks current_time
= initial_time
;
305 scoped_refptr
<cc::Layer
> layer
= cc::Layer::Create();
306 while (effect
->Animate(current_time
, layer
.get()))
307 current_time
+= base::TimeDelta::FromMilliseconds(16);
309 EXPECT_GT(current_time
.ToInternalValue(), initial_time
.ToInternalValue());
310 EXPECT_FALSE(effect
->IsActive());
311 EXPECT_FALSE(GetAndResetRefreshTriggered());
314 } // namespace content