#include "ui/android/overscroll_refresh.h"
#include "base/android/scoped_java_ref.h"
#include "cc/input/overscroll_behavior.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/android/overscroll_refresh_handler.h"
#include "ui/gfx/geometry/point_f.h"
namespace ui {
const float kDipScale = 1.f;
const gfx::PointF kStartPos(2.f, 2.f);
const float kDefaultEdgeWidth =
OverscrollRefresh::kDefaultNavigationEdgeWidth * kDipScale;
class OverscrollRefreshTest : public OverscrollRefreshHandler,
public testing::Test {
public:
OverscrollRefreshTest() : OverscrollRefreshHandler(nullptr) {}
bool PullStart(OverscrollAction type,
float startx,
float starty,
bool navigateForward) override {
started_ = true;
return true;
}
void PullUpdate(float x_delta, float y_delta) override { delta_ += y_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;
}
void TestOverscrollBehavior(const cc::OverscrollBehavior& ob,
const gfx::Vector2dF& scroll_delta,
bool started) {
OverscrollRefresh effect(this, kDefaultEdgeWidth);
effect.OnScrollBegin(kStartPos);
EXPECT_FALSE(effect.WillHandleScrollUpdate(scroll_delta));
EXPECT_FALSE(effect.IsActive());
EXPECT_TRUE(effect.IsAwaitingScrollUpdateAck());
effect.OnOverscrolled(ob);
EXPECT_EQ(started, GetAndResetPullStarted());
EXPECT_EQ(!started, GetAndResetPullReset());
}
private:
float delta_ = 0;
bool started_ = false;
bool released_ = false;
bool reset_ = false;
bool refresh_allowed_ = false;
};
TEST_F(OverscrollRefreshTest, Basic) {
OverscrollRefresh effect(this, kDefaultEdgeWidth);
EXPECT_FALSE(effect.IsActive());
EXPECT_FALSE(effect.IsAwaitingScrollUpdateAck());
effect.OnScrollBegin(kStartPos);
EXPECT_FALSE(effect.IsActive());
EXPECT_TRUE(effect.IsAwaitingScrollUpdateAck());
gfx::Vector2dF scroll_up(0, 10);
EXPECT_FALSE(effect.WillHandleScrollUpdate(scroll_up));
EXPECT_FALSE(effect.IsActive());
EXPECT_TRUE(effect.IsAwaitingScrollUpdateAck());
effect.OnOverscrolled(cc::OverscrollBehavior());
EXPECT_TRUE(effect.IsActive());
EXPECT_FALSE(effect.IsAwaitingScrollUpdateAck());
EXPECT_TRUE(GetAndResetPullStarted());
EXPECT_TRUE(effect.WillHandleScrollUpdate(gfx::Vector2dF(0, 50)));
EXPECT_EQ(50.f, GetAndResetPullDelta());
EXPECT_TRUE(effect.IsActive());
EXPECT_TRUE(effect.WillHandleScrollUpdate(gfx::Vector2dF(0, -50)));
EXPECT_EQ(-50.f, GetAndResetPullDelta());
EXPECT_TRUE(effect.IsActive());
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, kDefaultEdgeWidth);
gfx::PointF nonzero_offset(0, 10);
gfx::SizeF viewport(100, 100);
bool overflow_y_hidden = false;
effect.OnFrameUpdated(viewport, nonzero_offset, overflow_y_hidden);
effect.OnScrollBegin(kStartPos);
effect.OnFrameUpdated(viewport, gfx::PointF(), overflow_y_hidden);
ASSERT_FALSE(effect.WillHandleScrollUpdate(gfx::Vector2dF(0, 10)));
EXPECT_FALSE(effect.IsActive());
EXPECT_FALSE(effect.IsAwaitingScrollUpdateAck());
effect.OnOverscrolled(cc::OverscrollBehavior());
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, kDefaultEdgeWidth);
gfx::PointF zero_offset;
bool overflow_y_hidden = true;
gfx::SizeF viewport(100, 100);
effect.OnFrameUpdated(viewport, zero_offset, overflow_y_hidden);
effect.OnScrollBegin(kStartPos);
ASSERT_FALSE(effect.WillHandleScrollUpdate(gfx::Vector2dF(0, 10)));
EXPECT_FALSE(effect.IsActive());
EXPECT_FALSE(effect.IsAwaitingScrollUpdateAck());
effect.OnOverscrolled(cc::OverscrollBehavior());
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, kDefaultEdgeWidth);
effect.OnScrollBegin(kStartPos);
ASSERT_FALSE(effect.WillHandleScrollUpdate(gfx::Vector2dF(0, -10)));
EXPECT_FALSE(effect.IsActive());
EXPECT_FALSE(effect.IsAwaitingScrollUpdateAck());
effect.OnOverscrolled(cc::OverscrollBehavior());
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, kDefaultEdgeWidth);
effect.OnScrollBegin(kStartPos);
ASSERT_FALSE(effect.WillHandleScrollUpdate(gfx::Vector2dF(0, 10)));
ASSERT_TRUE(effect.IsAwaitingScrollUpdateAck());
effect.Reset();
effect.OnOverscrolled(cc::OverscrollBehavior());
EXPECT_FALSE(effect.IsActive());
EXPECT_FALSE(effect.IsAwaitingScrollUpdateAck());
EXPECT_FALSE(effect.WillHandleScrollUpdate(gfx::Vector2dF(0, 500)));
effect.OnOverscrolled(cc::OverscrollBehavior());
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, kDefaultEdgeWidth);
effect.OnScrollBegin(kStartPos);
ASSERT_FALSE(effect.WillHandleScrollUpdate(gfx::Vector2dF(0, 10)));
ASSERT_TRUE(effect.IsAwaitingScrollUpdateAck());
effect.OnOverscrolled(cc::OverscrollBehavior());
ASSERT_TRUE(effect.IsActive());
EXPECT_TRUE(GetAndResetPullStarted());
effect.OnScrollEnd(gfx::Vector2dF(0, -1000));
EXPECT_TRUE(GetAndResetPullReleased());
EXPECT_FALSE(GetAndResetRefreshAllowed());
}
TEST_F(OverscrollRefreshTest, NotTriggeredIfReleasedWithoutActivation) {
OverscrollRefresh effect(this, kDefaultEdgeWidth);
effect.OnScrollBegin(kStartPos);
ASSERT_FALSE(effect.WillHandleScrollUpdate(gfx::Vector2dF(0, 10)));
ASSERT_TRUE(effect.IsAwaitingScrollUpdateAck());
effect.OnOverscrolled(cc::OverscrollBehavior());
ASSERT_TRUE(effect.IsActive());
EXPECT_TRUE(GetAndResetPullStarted());
effect.ReleaseWithoutActivation();
effect.OnScrollEnd(gfx::Vector2dF());
EXPECT_TRUE(GetAndResetPullReleased());
EXPECT_FALSE(GetAndResetRefreshAllowed());
}
TEST_F(OverscrollRefreshTest, NotTriggeredIfReset) {
OverscrollRefresh effect(this, kDefaultEdgeWidth);
effect.OnScrollBegin(kStartPos);
ASSERT_FALSE(effect.WillHandleScrollUpdate(gfx::Vector2dF(0, 10)));
ASSERT_TRUE(effect.IsAwaitingScrollUpdateAck());
effect.OnOverscrolled(cc::OverscrollBehavior());
ASSERT_TRUE(effect.IsActive());
EXPECT_TRUE(GetAndResetPullStarted());
effect.Reset();
EXPECT_TRUE(GetAndResetPullReset());
effect.OnScrollEnd(gfx::Vector2dF());
EXPECT_FALSE(GetAndResetPullReleased());
}
TEST_F(OverscrollRefreshTest, OverscrollBehaviorYAutoTriggersStart) {
TestOverscrollBehavior(cc::OverscrollBehavior(), gfx::Vector2dF(0, 10), true);
}
TEST_F(OverscrollRefreshTest, OverscrollBehaviorYContainPreventsTriggerStart) {
auto ob = cc::OverscrollBehavior();
ob.y = cc::OverscrollBehavior::Type::kContain;
TestOverscrollBehavior(ob, gfx::Vector2dF(0, 10), false);
}
TEST_F(OverscrollRefreshTest, OverscrollBehaviorYNonePreventsTriggerStart) {
auto ob = cc::OverscrollBehavior();
ob.y = cc::OverscrollBehavior::Type::kNone;
TestOverscrollBehavior(ob, gfx::Vector2dF(0, 10), false);
}
TEST_F(OverscrollRefreshTest, OverscrollBehaviorXAutoTriggersStart) {
TestOverscrollBehavior(cc::OverscrollBehavior(), gfx::Vector2dF(10, 0), true);
}
TEST_F(OverscrollRefreshTest, OverscrollBehaviorXContainPreventsTriggerStart) {
auto ob = cc::OverscrollBehavior();
ob.x = cc::OverscrollBehavior::Type::kContain;
TestOverscrollBehavior(ob, gfx::Vector2dF(10, 0), false);
}
TEST_F(OverscrollRefreshTest, OverscrollBehaviorXNonePreventsTriggerStart) {
auto ob = cc::OverscrollBehavior();
ob.x = cc::OverscrollBehavior::Type::kNone;
TestOverscrollBehavior(ob, gfx::Vector2dF(10, 0), false);
}
}