| // 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 "testing/gtest/include/gtest/gtest.h" |
| #include "ui/android/overscroll_refresh.h" |
| |
| namespace ui { |
| |
| class OverscrollRefreshTest : public OverscrollRefreshHandler, |
| public testing::Test { |
| public: |
| OverscrollRefreshTest() {} |
| |
| // OverscrollRefreshHandler implementation. |
| bool PullStart() override { |
| started_ = true; |
| return true; |
| } |
| |
| void PullUpdate(float delta) override { delta_ += delta; } |
| |
| void PullRelease(bool allow_refresh) override { |
| released_ = true; |
| refresh_allowed_ = allow_refresh; |
| } |
| |
| void PullReset() override { reset_ = true; } |
| |
| bool GetAndResetPullStarted() { |
| bool result = started_; |
| started_ = false; |
| return result; |
| } |
| |
| float GetAndResetPullDelta() { |
| float result = delta_; |
| delta_ = 0; |
| return result; |
| } |
| |
| bool GetAndResetPullReleased() { |
| bool result = released_; |
| released_ = false; |
| return result; |
| } |
| |
| bool GetAndResetRefreshAllowed() { |
| bool result = refresh_allowed_; |
| refresh_allowed_ = false; |
| return result; |
| } |
| |
| bool GetAndResetPullReset() { |
| bool result = reset_; |
| reset_ = false; |
| return result; |
| } |
| |
| private: |
| float delta_ = 0; |
| bool started_ = false; |
| bool released_ = false; |
| bool reset_ = false; |
| bool refresh_allowed_ = false; |
| }; |
| |
| TEST_F(OverscrollRefreshTest, Basic) { |
| OverscrollRefresh effect(this); |
| |
| EXPECT_FALSE(effect.IsActive()); |
| EXPECT_FALSE(effect.IsAwaitingScrollUpdateAck()); |
| |
| effect.OnScrollBegin(); |
| EXPECT_FALSE(effect.IsActive()); |
| EXPECT_TRUE(effect.IsAwaitingScrollUpdateAck()); |
| |
| // 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.IsAwaitingScrollUpdateAck()); |
| |
| // The unconsumed, overscrolling scroll will trigger the effect. |
| effect.OnScrollUpdateAck(false); |
| EXPECT_TRUE(effect.IsActive()); |
| EXPECT_FALSE(effect.IsAwaitingScrollUpdateAck()); |
| EXPECT_TRUE(GetAndResetPullStarted()); |
| |
| // Further scrolls will be consumed. |
| EXPECT_TRUE(effect.WillHandleScrollUpdate(gfx::Vector2dF(0, 50))); |
| EXPECT_EQ(50.f, GetAndResetPullDelta()); |
| EXPECT_TRUE(effect.IsActive()); |
| |
| // Even scrolls in the down direction should be consumed. |
| EXPECT_TRUE(effect.WillHandleScrollUpdate(gfx::Vector2dF(0, -50))); |
| EXPECT_EQ(-50.f, GetAndResetPullDelta()); |
| EXPECT_TRUE(effect.IsActive()); |
| |
| // Ending the scroll while beyond the threshold should trigger a refresh. |
| gfx::Vector2dF zero_velocity; |
| EXPECT_FALSE(GetAndResetPullReleased()); |
| effect.OnScrollEnd(zero_velocity); |
| EXPECT_FALSE(effect.IsActive()); |
| EXPECT_TRUE(GetAndResetPullReleased()); |
| EXPECT_TRUE(GetAndResetRefreshAllowed()); |
| } |
| |
| TEST_F(OverscrollRefreshTest, NotTriggeredIfInitialYOffsetIsNotZero) { |
| OverscrollRefresh effect(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); |
| bool overflow_y_hidden = false; |
| effect.OnFrameUpdated(nonzero_offset, overflow_y_hidden); |
| effect.OnScrollBegin(); |
| |
| effect.OnFrameUpdated(gfx::Vector2dF(), overflow_y_hidden); |
| ASSERT_FALSE(effect.WillHandleScrollUpdate(gfx::Vector2dF(0, 10))); |
| EXPECT_FALSE(effect.IsActive()); |
| EXPECT_FALSE(effect.IsAwaitingScrollUpdateAck()); |
| effect.OnScrollUpdateAck(false); |
| EXPECT_FALSE(effect.IsActive()); |
| EXPECT_FALSE(effect.IsAwaitingScrollUpdateAck()); |
| EXPECT_FALSE(effect.WillHandleScrollUpdate(gfx::Vector2dF(0, 500))); |
| effect.OnScrollEnd(gfx::Vector2dF()); |
| EXPECT_FALSE(GetAndResetPullStarted()); |
| EXPECT_FALSE(GetAndResetPullReleased()); |
| } |
| |
| TEST_F(OverscrollRefreshTest, NotTriggeredIfOverflowYHidden) { |
| OverscrollRefresh effect(this); |
| |
| // overflow-y:hidden at the start of scroll will prevent activation. |
| gfx::Vector2dF zero_offset; |
| bool overflow_y_hidden = true; |
| effect.OnFrameUpdated(zero_offset, overflow_y_hidden); |
| effect.OnScrollBegin(); |
| |
| ASSERT_FALSE(effect.WillHandleScrollUpdate(gfx::Vector2dF(0, 10))); |
| EXPECT_FALSE(effect.IsActive()); |
| EXPECT_FALSE(effect.IsAwaitingScrollUpdateAck()); |
| effect.OnScrollUpdateAck(false); |
| EXPECT_FALSE(effect.IsActive()); |
| EXPECT_FALSE(effect.IsAwaitingScrollUpdateAck()); |
| EXPECT_FALSE(effect.WillHandleScrollUpdate(gfx::Vector2dF(0, 500))); |
| effect.OnScrollEnd(gfx::Vector2dF()); |
| EXPECT_FALSE(GetAndResetPullStarted()); |
| EXPECT_FALSE(GetAndResetPullReleased()); |
| } |
| |
| TEST_F(OverscrollRefreshTest, NotTriggeredIfInitialScrollDownward) { |
| OverscrollRefresh effect(this); |
| 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.IsAwaitingScrollUpdateAck()); |
| |
| effect.OnScrollUpdateAck(false); |
| EXPECT_FALSE(effect.IsActive()); |
| EXPECT_FALSE(effect.IsAwaitingScrollUpdateAck()); |
| EXPECT_FALSE(effect.WillHandleScrollUpdate(gfx::Vector2dF(0, 500))); |
| effect.OnScrollEnd(gfx::Vector2dF()); |
| EXPECT_FALSE(GetAndResetPullReleased()); |
| } |
| |
| TEST_F(OverscrollRefreshTest, NotTriggeredIfInitialScrollOrTouchConsumed) { |
| OverscrollRefresh effect(this); |
| effect.OnScrollBegin(); |
| ASSERT_FALSE(effect.WillHandleScrollUpdate(gfx::Vector2dF(0, 10))); |
| ASSERT_TRUE(effect.IsAwaitingScrollUpdateAck()); |
| |
| // Consumption of the initial touchmove or scroll should prevent future |
| // activation. |
| effect.OnScrollUpdateAck(true); |
| EXPECT_FALSE(effect.IsActive()); |
| EXPECT_FALSE(effect.IsAwaitingScrollUpdateAck()); |
| EXPECT_FALSE(effect.WillHandleScrollUpdate(gfx::Vector2dF(0, 500))); |
| effect.OnScrollUpdateAck(false); |
| EXPECT_FALSE(effect.IsActive()); |
| EXPECT_FALSE(effect.IsAwaitingScrollUpdateAck()); |
| EXPECT_FALSE(effect.WillHandleScrollUpdate(gfx::Vector2dF(0, 500))); |
| effect.OnScrollEnd(gfx::Vector2dF()); |
| EXPECT_FALSE(GetAndResetPullStarted()); |
| EXPECT_FALSE(GetAndResetPullReleased()); |
| } |
| |
| TEST_F(OverscrollRefreshTest, NotTriggeredIfFlungDownward) { |
| OverscrollRefresh effect(this); |
| effect.OnScrollBegin(); |
| ASSERT_FALSE(effect.WillHandleScrollUpdate(gfx::Vector2dF(0, 10))); |
| ASSERT_TRUE(effect.IsAwaitingScrollUpdateAck()); |
| effect.OnScrollUpdateAck(false); |
| ASSERT_TRUE(effect.IsActive()); |
| EXPECT_TRUE(GetAndResetPullStarted()); |
| |
| // Terminating the pull with a down-directed fling should prevent triggering. |
| effect.OnScrollEnd(gfx::Vector2dF(0, -1000)); |
| EXPECT_TRUE(GetAndResetPullReleased()); |
| EXPECT_FALSE(GetAndResetRefreshAllowed()); |
| } |
| |
| TEST_F(OverscrollRefreshTest, NotTriggeredIfReleasedWithoutActivation) { |
| OverscrollRefresh effect(this); |
| effect.OnScrollBegin(); |
| ASSERT_FALSE(effect.WillHandleScrollUpdate(gfx::Vector2dF(0, 10))); |
| ASSERT_TRUE(effect.IsAwaitingScrollUpdateAck()); |
| effect.OnScrollUpdateAck(false); |
| ASSERT_TRUE(effect.IsActive()); |
| EXPECT_TRUE(GetAndResetPullStarted()); |
| |
| // An early release should prevent the refresh action from firing. |
| effect.ReleaseWithoutActivation(); |
| effect.OnScrollEnd(gfx::Vector2dF()); |
| EXPECT_TRUE(GetAndResetPullReleased()); |
| EXPECT_FALSE(GetAndResetRefreshAllowed()); |
| } |
| |
| TEST_F(OverscrollRefreshTest, NotTriggeredIfReset) { |
| OverscrollRefresh effect(this); |
| effect.OnScrollBegin(); |
| ASSERT_FALSE(effect.WillHandleScrollUpdate(gfx::Vector2dF(0, 10))); |
| ASSERT_TRUE(effect.IsAwaitingScrollUpdateAck()); |
| effect.OnScrollUpdateAck(false); |
| ASSERT_TRUE(effect.IsActive()); |
| EXPECT_TRUE(GetAndResetPullStarted()); |
| |
| // An early reset should prevent the refresh action from firing. |
| effect.Reset(); |
| EXPECT_TRUE(GetAndResetPullReset()); |
| effect.OnScrollEnd(gfx::Vector2dF()); |
| EXPECT_FALSE(GetAndResetPullReleased()); |
| } |
| |
| } // namespace ui |