Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(106)

Unified Diff: content/browser/android/overscroll_refresh_unittest.cc

Issue 679493002: [Android] Add a native pull-to-refresh overscroll effect (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Code review Created 6 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: content/browser/android/overscroll_refresh_unittest.cc
diff --git a/content/browser/android/overscroll_refresh_unittest.cc b/content/browser/android/overscroll_refresh_unittest.cc
new file mode 100644
index 0000000000000000000000000000000000000000..52ffb305512e4f871742147e4abbf860d6c09726
--- /dev/null
+++ b/content/browser/android/overscroll_refresh_unittest.cc
@@ -0,0 +1,269 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "cc/layers/layer.h"
+#include "content/browser/android/overscroll_refresh.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/base/android/system_ui_resource_manager.h"
+
+namespace content {
+
+gfx::SizeF DefaultViewportSize() {
+ return gfx::SizeF(512, 512);
+}
+
+OverscrollRefresh::ActivationAllowance kAllowActivation =
+ OverscrollRefresh::ALLOW_ACTIVATION;
+
+OverscrollRefresh::ActivationAllowance kPreventActivation =
+ OverscrollRefresh::PREVENT_ACTIVATION;
+
+class OverscrollRefreshTest : public OverscrollRefreshClient,
+ public ui::SystemUIResourceManager,
+ public testing::Test {
+ public:
+ OverscrollRefreshTest() : refresh_triggered_(false) {}
+
+ // OverscrollRefreshClient implementation.
+ void TriggerRefresh() override {
+ refresh_triggered_ = true;
+ triggered_refresh_active_ = true;
+ }
+
+ bool IsTriggeredRefreshActive() const override {
+ return triggered_refresh_active_;
+ }
+
+ // SystemUIResoruceManager implementation.
+ void PreloadResource(ui::SystemUIResourceType) override {}
+
+ bool GetAndResetRefreshTriggered() {
+ bool triggered = refresh_triggered_;
+ refresh_triggered_ = false;
+ return triggered;
+ }
+
+ protected:
+ void ResetTriggeredRefreshActive() { triggered_refresh_active_ = false; }
+
+ cc::UIResourceId GetUIResourceId(ui::SystemUIResourceType) override {
+ return 0;
+ }
+
+ private:
+ bool refresh_triggered_;
+ bool triggered_refresh_active_;
+};
+
+TEST_F(OverscrollRefreshTest, Basic) {
+ OverscrollRefresh effect(this, this);
+
+ gfx::Vector2dF origin_scroll_offset;
+ effect.UpdateDisplay(DefaultViewportSize(), origin_scroll_offset);
+ EXPECT_FALSE(effect.IsActive());
+ EXPECT_FALSE(effect.IsPendingScrollUpdateAck());
+
+ effect.OnScrollBegin();
+ EXPECT_FALSE(effect.IsActive());
+ EXPECT_TRUE(effect.IsPendingScrollUpdateAck());
+
+ // The initial scroll should not be consumed, as it should first be offered
+ // to content.
+ gfx::Vector2dF scroll_up(0, 10);
+ EXPECT_FALSE(effect.WillHandleScrollUpdate(scroll_up));
+ EXPECT_FALSE(effect.IsActive());
+ EXPECT_TRUE(effect.IsPendingScrollUpdateAck());
+
+ // The unconsumed, overscrolling scroll will trigger the effect.
+ effect.OnScrollUpdateAck(kAllowActivation);
+ EXPECT_TRUE(effect.IsActive());
+ EXPECT_FALSE(effect.IsPendingScrollUpdateAck());
+
+ // Further scrolls will be consumed.
+ EXPECT_TRUE(effect.WillHandleScrollUpdate(gfx::Vector2dF(0, 50)));
+ EXPECT_TRUE(effect.IsActive());
+
+ // Even scrolls in the down direction should be consumed.
+ EXPECT_TRUE(effect.WillHandleScrollUpdate(gfx::Vector2dF(0, -50)));
+ EXPECT_TRUE(effect.IsActive());
+
+ // Feed enough scrolls to the effect to exceeds tht threshold.
+ EXPECT_TRUE(effect.WillHandleScrollUpdate(gfx::Vector2dF(0, 100)));
+ EXPECT_TRUE(effect.WillHandleScrollUpdate(gfx::Vector2dF(0, 100)));
+ EXPECT_TRUE(effect.WillHandleScrollUpdate(gfx::Vector2dF(0, 100)));
+ EXPECT_TRUE(effect.WillHandleScrollUpdate(gfx::Vector2dF(0, 100)));
+ EXPECT_TRUE(effect.WillHandleScrollUpdate(gfx::Vector2dF(0, 100)));
+ EXPECT_TRUE(effect.IsActive());
+
+ // Ending the scroll while beyond the threshold should trigger a refresh.
+ gfx::Vector2dF zero_velocity;
+ EXPECT_FALSE(GetAndResetRefreshTriggered());
+ effect.OnScrollEnd(zero_velocity);
+ EXPECT_TRUE(effect.IsActive());
+ EXPECT_TRUE(GetAndResetRefreshTriggered());
+ ResetTriggeredRefreshActive();
+
+ // Ensure animation doesn't explode.
+ base::TimeTicks initial_time = base::TimeTicks::Now();
+ base::TimeTicks current_time = initial_time;
+ scoped_refptr<cc::Layer> layer = cc::Layer::Create();
+ while (effect.Animate(current_time, layer.get()))
+ current_time += base::TimeDelta::FromMilliseconds(16);
+
+ // The effect should terminate in a timely fashion.
+ EXPECT_GT(current_time.ToInternalValue(), initial_time.ToInternalValue());
+ EXPECT_LE(
+ current_time.ToInternalValue(),
+ (initial_time + base::TimeDelta::FromSeconds(10)).ToInternalValue());
+ EXPECT_FALSE(effect.IsActive());
+}
+
+TEST_F(OverscrollRefreshTest, AnimationTerminatesEvenIfRefreshNeverTerminates) {
+ OverscrollRefresh effect(this, this);
+ effect.UpdateDisplay(DefaultViewportSize(), gfx::Vector2dF());
+ effect.OnScrollBegin();
+ ASSERT_FALSE(effect.WillHandleScrollUpdate(gfx::Vector2dF(0, 10)));
+ ASSERT_TRUE(effect.IsPendingScrollUpdateAck());
+ effect.OnScrollUpdateAck(kAllowActivation);
+ ASSERT_TRUE(effect.IsActive());
+ EXPECT_TRUE(effect.WillHandleScrollUpdate(gfx::Vector2dF(0, 50)));
+ EXPECT_TRUE(effect.WillHandleScrollUpdate(gfx::Vector2dF(0, 50)));
+ EXPECT_TRUE(effect.WillHandleScrollUpdate(gfx::Vector2dF(0, 50)));
+ EXPECT_TRUE(effect.WillHandleScrollUpdate(gfx::Vector2dF(0, 50)));
+ EXPECT_TRUE(effect.WillHandleScrollUpdate(gfx::Vector2dF(0, 50)));
+ EXPECT_TRUE(effect.WillHandleScrollUpdate(gfx::Vector2dF(0, 50)));
+ effect.OnScrollEnd(gfx::Vector2dF(0, 0));
+ ASSERT_TRUE(GetAndResetRefreshTriggered());
+
+ // Verify that the animation terminates even if the triggered refresh
+ // action never terminates (i.e., |triggered_refresh_active_| is always true).
+ base::TimeTicks initial_time = base::TimeTicks::Now();
+ base::TimeTicks current_time = initial_time;
+ scoped_refptr<cc::Layer> layer = cc::Layer::Create();
+ while (effect.Animate(current_time, layer.get()))
+ current_time += base::TimeDelta::FromMilliseconds(16);
+
+ EXPECT_GT(current_time.ToInternalValue(), initial_time.ToInternalValue());
+ EXPECT_LE(
+ current_time.ToInternalValue(),
+ (initial_time + base::TimeDelta::FromSeconds(10)).ToInternalValue());
+ EXPECT_FALSE(effect.IsActive());
+}
+
+TEST_F(OverscrollRefreshTest, NotTriggeredIfBelowThreshold) {
+ OverscrollRefresh effect(this, this);
+ effect.UpdateDisplay(DefaultViewportSize(), gfx::Vector2dF());
+ effect.OnScrollBegin();
+ ASSERT_FALSE(effect.WillHandleScrollUpdate(gfx::Vector2dF(0, 10)));
+ ASSERT_TRUE(effect.IsPendingScrollUpdateAck());
+ effect.OnScrollUpdateAck(kAllowActivation);
+ ASSERT_TRUE(effect.IsActive());
+
+ // Terminating the pull before it exceeds the threshold will prevent refresh.
+ EXPECT_TRUE(effect.WillHandleScrollUpdate(gfx::Vector2dF(0, 10)));
+ effect.OnScrollEnd(gfx::Vector2dF());
+ EXPECT_FALSE(GetAndResetRefreshTriggered());
+}
+
+TEST_F(OverscrollRefreshTest, NotTriggeredIfInitialYOffsetIsZero) {
+ OverscrollRefresh effect(this, this);
+
+ // A positive y scroll offset at the start of scroll will prevent activation,
+ // even if the subsequent scroll overscrolls upward.
+ gfx::Vector2dF nonzero_offset(0, 10);
+ effect.UpdateDisplay(DefaultViewportSize(), nonzero_offset);
+ effect.OnScrollBegin();
+
+ effect.UpdateDisplay(DefaultViewportSize(), gfx::Vector2dF());
+ ASSERT_FALSE(effect.WillHandleScrollUpdate(gfx::Vector2dF(0, 10)));
+ EXPECT_FALSE(effect.IsActive());
+ EXPECT_FALSE(effect.IsPendingScrollUpdateAck());
+ effect.OnScrollUpdateAck(kAllowActivation);
+ EXPECT_FALSE(effect.IsActive());
+ EXPECT_FALSE(effect.IsPendingScrollUpdateAck());
+ EXPECT_FALSE(effect.WillHandleScrollUpdate(gfx::Vector2dF(0, 500)));
+ effect.OnScrollEnd(gfx::Vector2dF());
+ EXPECT_FALSE(GetAndResetRefreshTriggered());
+}
+
+TEST_F(OverscrollRefreshTest, NotTriggeredIfInitialScrollDownward) {
+ OverscrollRefresh effect(this, this);
+ effect.UpdateDisplay(DefaultViewportSize(), gfx::Vector2dF());
+ effect.OnScrollBegin();
+
+ // A downward initial scroll will prevent activation, even if the subsequent
+ // scroll overscrolls upward.
+ ASSERT_FALSE(effect.WillHandleScrollUpdate(gfx::Vector2dF(0, -10)));
+ EXPECT_FALSE(effect.IsActive());
+ EXPECT_FALSE(effect.IsPendingScrollUpdateAck());
+
+ effect.OnScrollUpdateAck(kAllowActivation);
+ EXPECT_FALSE(effect.IsActive());
+ EXPECT_FALSE(effect.IsPendingScrollUpdateAck());
+ EXPECT_FALSE(effect.WillHandleScrollUpdate(gfx::Vector2dF(0, 500)));
+ effect.OnScrollEnd(gfx::Vector2dF());
+ EXPECT_FALSE(GetAndResetRefreshTriggered());
+}
+
+TEST_F(OverscrollRefreshTest, NotTriggeredIfInitialScrollOrTouchConsumed) {
+ OverscrollRefresh effect(this, this);
+ effect.UpdateDisplay(DefaultViewportSize(), gfx::Vector2dF());
+ effect.OnScrollBegin();
+ ASSERT_FALSE(effect.WillHandleScrollUpdate(gfx::Vector2dF(0, 10)));
+ ASSERT_TRUE(effect.IsPendingScrollUpdateAck());
+
+ // Consumption of the initial touchmove or scroll should prevent future
+ // activation.
+ effect.OnScrollUpdateAck(kPreventActivation);
+ EXPECT_FALSE(effect.IsActive());
+ EXPECT_FALSE(effect.IsPendingScrollUpdateAck());
+ EXPECT_FALSE(effect.WillHandleScrollUpdate(gfx::Vector2dF(0, 500)));
+ effect.OnScrollUpdateAck(kAllowActivation);
+ EXPECT_FALSE(effect.IsActive());
+ EXPECT_FALSE(effect.IsPendingScrollUpdateAck());
+ EXPECT_FALSE(effect.WillHandleScrollUpdate(gfx::Vector2dF(0, 500)));
+ effect.OnScrollEnd(gfx::Vector2dF());
+ EXPECT_FALSE(GetAndResetRefreshTriggered());
+}
+
+TEST_F(OverscrollRefreshTest, NotTriggeredIfInitialScrollsJanked) {
+ OverscrollRefresh effect(this, this);
+ effect.UpdateDisplay(DefaultViewportSize(), gfx::Vector2dF());
+ effect.OnScrollBegin();
+ ASSERT_FALSE(effect.WillHandleScrollUpdate(gfx::Vector2dF(0, 10)));
+ ASSERT_TRUE(effect.IsPendingScrollUpdateAck());
+ effect.OnScrollUpdateAck(kAllowActivation);
+ ASSERT_TRUE(effect.IsActive());
+
+ // It should take more than just one or two large scrolls to trigger,
+ // mitigating likelihood of jank triggering the effect.
+ EXPECT_TRUE(effect.WillHandleScrollUpdate(gfx::Vector2dF(0, 500)));
+ EXPECT_TRUE(effect.WillHandleScrollUpdate(gfx::Vector2dF(0, 500)));
+ effect.OnScrollEnd(gfx::Vector2dF());
+ EXPECT_FALSE(GetAndResetRefreshTriggered());
+}
+
+TEST_F(OverscrollRefreshTest, NotTriggeredIfFlungDownward) {
+ OverscrollRefresh effect(this, this);
+ effect.UpdateDisplay(DefaultViewportSize(), gfx::Vector2dF());
+ effect.OnScrollBegin();
+ ASSERT_FALSE(effect.WillHandleScrollUpdate(gfx::Vector2dF(0, 10)));
+ ASSERT_TRUE(effect.IsPendingScrollUpdateAck());
+ effect.OnScrollUpdateAck(kAllowActivation);
+ ASSERT_TRUE(effect.IsActive());
+
+ // Ensure the pull exceeds the necessary threshold.
+ EXPECT_TRUE(effect.WillHandleScrollUpdate(gfx::Vector2dF(0, 50)));
+ EXPECT_TRUE(effect.WillHandleScrollUpdate(gfx::Vector2dF(0, 50)));
+ EXPECT_TRUE(effect.WillHandleScrollUpdate(gfx::Vector2dF(0, 50)));
+ EXPECT_TRUE(effect.WillHandleScrollUpdate(gfx::Vector2dF(0, 50)));
+ EXPECT_TRUE(effect.WillHandleScrollUpdate(gfx::Vector2dF(0, 50)));
+ EXPECT_TRUE(effect.WillHandleScrollUpdate(gfx::Vector2dF(0, 50)));
+
+ // Terminating the pull with a down-directed fling should prevent triggering.
+ effect.OnScrollEnd(gfx::Vector2dF(0, -1000));
+ EXPECT_FALSE(GetAndResetRefreshTriggered());
+}
+
+} // namespace content

Powered by Google App Engine
This is Rietveld 408576698