| // Copyright 2017 The Chromium Authors | 
 | // Use of this source code is governed by a BSD-style license that can be | 
 | // found in the LICENSE file. | 
 |  | 
 | #include "content/browser/renderer_host/overscroll_controller.h" | 
 |  | 
 | #include <memory> | 
 |  | 
 | #include "base/containers/queue.h" | 
 | #include "base/test/scoped_feature_list.h" | 
 | #include "content/browser/renderer_host/overscroll_controller_delegate.h" | 
 | #include "content/common/features.h" | 
 | #include "content/public/browser/overscroll_configuration.h" | 
 | #include "content/public/test/scoped_overscroll_modes.h" | 
 | #include "content/test/test_overscroll_delegate.h" | 
 | #include "testing/gtest/include/gtest/gtest.h" | 
 | #include "third_party/blink/public/common/input/synthetic_web_input_event_builders.h" | 
 | #include "third_party/blink/public/common/input/web_input_event.h" | 
 |  | 
 | namespace content { | 
 |  | 
 | class OverscrollControllerTest : public ::testing::Test { | 
 |  public: | 
 |   OverscrollControllerTest(const OverscrollControllerTest&) = delete; | 
 |   OverscrollControllerTest& operator=(const OverscrollControllerTest&) = delete; | 
 |  | 
 |  protected: | 
 |   OverscrollControllerTest() {} | 
 |   ~OverscrollControllerTest() override {} | 
 |  | 
 |   void SetUp() override { | 
 |     OverscrollConfig::ResetTouchpadOverscrollHistoryNavigationEnabled(); | 
 |     scoped_feature_list_.InitAndEnableFeature( | 
 |         features::kTouchpadOverscrollHistoryNavigation); | 
 |     delegate_ = std::make_unique<TestOverscrollDelegate>(gfx::Size(400, 300)); | 
 |     controller_ = std::make_unique<OverscrollController>(); | 
 |     controller_->set_delegate(delegate_->GetWeakPtr()); | 
 |   } | 
 |  | 
 |   void TearDown() override { | 
 |     controller_ = nullptr; | 
 |     delegate_ = nullptr; | 
 |   } | 
 |  | 
 |   // Creates and sends a mouse-wheel event to the overscroll controller. Returns | 
 |   // |true| if the event is consumed by the overscroll controller. | 
 |   bool SimulateMouseWheel(float dx, float dy) { | 
 |     DCHECK(!current_event_); | 
 |     current_event_ = std::make_unique<blink::WebMouseWheelEvent>( | 
 |         blink::SyntheticWebMouseWheelEventBuilder::Build( | 
 |             0, 0, dx, dy, 0, ui::ScrollGranularity::kScrollByPrecisePixel)); | 
 |     return controller_->WillHandleEvent(*current_event_); | 
 |   } | 
 |  | 
 |   // Creates and sends a gesture event to the overscroll controller. Returns | 
 |   // |true| if the event is consumed by the overscroll controller. | 
 |   bool SimulateGestureEvent(blink::WebInputEvent::Type type, | 
 |                             blink::WebGestureDevice source_device, | 
 |                             base::TimeTicks timestamp) { | 
 |     DCHECK(!current_event_); | 
 |     current_event_ = std::make_unique<blink::WebGestureEvent>( | 
 |         blink::SyntheticWebGestureEventBuilder::Build(type, source_device)); | 
 |     current_event_->SetTimeStamp(timestamp); | 
 |     return controller_->WillHandleEvent(*current_event_); | 
 |   } | 
 |  | 
 |   // Creates and sends a gesture-scroll-update event to the overscroll | 
 |   // controller. Returns |true| if the event is consumed by the overscroll | 
 |   // controller. | 
 |   bool SimulateGestureScrollUpdate(float dx, | 
 |                                    float dy, | 
 |                                    blink::WebGestureDevice device, | 
 |                                    base::TimeTicks timestamp, | 
 |                                    bool inertial_update) { | 
 |     DCHECK(!current_event_); | 
 |     auto event = std::make_unique<blink::WebGestureEvent>( | 
 |         blink::SyntheticWebGestureEventBuilder::BuildScrollUpdate(dx, dy, 0, | 
 |                                                                   device)); | 
 |     event->SetTimeStamp(timestamp); | 
 |     if (inertial_update) { | 
 |       event->data.scroll_update.inertial_phase = | 
 |           blink::WebGestureEvent::InertialPhaseState::kMomentum; | 
 |     } | 
 |     current_event_ = std::move(event); | 
 |     return controller_->WillHandleEvent(*current_event_); | 
 |   } | 
 |  | 
 |   // Creates and sends a gesture-fling-start event to the overscroll controller. | 
 |   // Returns |true| if the event is consumed by the overscroll controller. | 
 |   bool SimulateGestureFlingStart(float velocity_x, | 
 |                                  float velocity_y, | 
 |                                  blink::WebGestureDevice device, | 
 |                                  base::TimeTicks timestamp) { | 
 |     DCHECK(!current_event_); | 
 |     current_event_ = std::make_unique<blink::WebGestureEvent>( | 
 |         blink::SyntheticWebGestureEventBuilder::BuildFling(velocity_x, | 
 |                                                            velocity_y, device)); | 
 |     current_event_->SetTimeStamp(timestamp); | 
 |     return controller_->WillHandleEvent(*current_event_); | 
 |   } | 
 |  | 
 |   // Notifies the overscroll controller that the current event is ACKed. | 
 |   void SimulateAck(bool processed) { | 
 |     DCHECK(current_event_); | 
 |     controller_->ReceivedEventACK(*current_event_, processed); | 
 |     current_event_ = nullptr; | 
 |   } | 
 |  | 
 |   TestOverscrollDelegate* delegate() const { return delegate_.get(); } | 
 |  | 
 |   OverscrollMode controller_mode() const { | 
 |     return controller_->overscroll_mode_; | 
 |   } | 
 |  | 
 |   OverscrollSource controller_source() const { | 
 |     return controller_->overscroll_source_; | 
 |   } | 
 |  | 
 |  private: | 
 |   std::unique_ptr<TestOverscrollDelegate> delegate_; | 
 |   std::unique_ptr<OverscrollController> controller_; | 
 |  | 
 |   // Keeps track of the last event that has been processed by the overscroll | 
 |   // controller which is not yet ACKed. Will be null if no event is processed or | 
 |   // the last event is ACKed. | 
 |   std::unique_ptr<blink::WebInputEvent> current_event_; | 
 |  | 
 |   base::test::ScopedFeatureList scoped_feature_list_; | 
 | }; | 
 |  | 
 | // Tests that if a mouse-wheel is consumed by content before overscroll is | 
 | // initiated, overscroll will not initiate anymore. | 
 | TEST_F(OverscrollControllerTest, MouseWheelConsumedPreventsOverscroll) { | 
 |   const base::TimeTicks timestamp = | 
 |       blink::WebInputEvent::GetStaticTimeStampForTests(); | 
 |  | 
 |   // Simulate a mouse-wheel, ACK it as not processed, simulate the corresponding | 
 |   // gesture scroll-update event, and ACK it as not processed. Since it is not | 
 |   // passing the start threshold, no overscroll should happen. | 
 |   EXPECT_FALSE(SimulateMouseWheel(10, 0)); | 
 |   SimulateAck(false); | 
 |   EXPECT_FALSE(SimulateGestureScrollUpdate( | 
 |       10, 0, blink::WebGestureDevice::kTouchpad, timestamp, false)); | 
 |   SimulateAck(false); | 
 |   EXPECT_EQ(OVERSCROLL_NONE, controller_mode()); | 
 |   EXPECT_EQ(OverscrollSource::NONE, controller_source()); | 
 |   EXPECT_EQ(OVERSCROLL_NONE, delegate()->current_mode()); | 
 |   EXPECT_EQ(OVERSCROLL_NONE, delegate()->completed_mode()); | 
 |  | 
 |   // Simulate a mouse-wheel and ACK it as processed. No gesture scroll-update | 
 |   // needs to be simulated. Still no overscroll. | 
 |   EXPECT_FALSE(SimulateMouseWheel(10, 0)); | 
 |   SimulateAck(true); | 
 |   EXPECT_EQ(OVERSCROLL_NONE, controller_mode()); | 
 |   EXPECT_EQ(OverscrollSource::NONE, controller_source()); | 
 |   EXPECT_EQ(OVERSCROLL_NONE, delegate()->current_mode()); | 
 |   EXPECT_EQ(OVERSCROLL_NONE, delegate()->completed_mode()); | 
 |  | 
 |   // Simulate a mouse-wheel and the corresponding gesture scroll-update both | 
 |   // ACKed as not processed. Although the scroll passes overscroll start | 
 |   // threshold, no overscroll should happen since the previous mouse-wheel was | 
 |   // marked as processed. | 
 |   EXPECT_FALSE(SimulateMouseWheel(100, 0)); | 
 |   SimulateAck(false); | 
 |   EXPECT_FALSE(SimulateGestureScrollUpdate( | 
 |       100, 0, blink::WebGestureDevice::kTouchpad, timestamp, false)); | 
 |   SimulateAck(false); | 
 |   EXPECT_EQ(OVERSCROLL_NONE, controller_mode()); | 
 |   EXPECT_EQ(OverscrollSource::NONE, controller_source()); | 
 |   EXPECT_EQ(OVERSCROLL_NONE, delegate()->current_mode()); | 
 |   EXPECT_EQ(OVERSCROLL_NONE, delegate()->completed_mode()); | 
 | } | 
 |  | 
 | // Verifying the inertial scroll event completes overscroll. After that we will | 
 | // ignore the following inertial scroll events until new sequence start. | 
 | TEST_F(OverscrollControllerTest, | 
 |        InertialGestureScrollUpdateCompletesOverscroll) { | 
 |   const base::TimeTicks timestamp = | 
 |       blink::WebInputEvent::GetStaticTimeStampForTests(); | 
 |  | 
 |   EXPECT_FALSE( | 
 |       SimulateGestureEvent(blink::WebInputEvent::Type::kGestureScrollBegin, | 
 |                            blink::WebGestureDevice::kTouchpad, timestamp)); | 
 |   SimulateAck(false); | 
 |  | 
 |   EXPECT_FALSE(SimulateGestureScrollUpdate( | 
 |       200, 0, blink::WebGestureDevice::kTouchpad, timestamp, false)); | 
 |   SimulateAck(false); | 
 |   EXPECT_EQ(OVERSCROLL_EAST, controller_mode()); | 
 |   EXPECT_EQ(OverscrollSource::TOUCHPAD, controller_source()); | 
 |   EXPECT_EQ(OVERSCROLL_EAST, delegate()->current_mode()); | 
 |   EXPECT_EQ(OVERSCROLL_NONE, delegate()->completed_mode()); | 
 |  | 
 |   // Inertial update event complete the overscroll action. | 
 |   EXPECT_FALSE(SimulateGestureScrollUpdate( | 
 |       100, 0, blink::WebGestureDevice::kTouchpad, timestamp, true)); | 
 |   SimulateAck(false); | 
 |   EXPECT_EQ(OVERSCROLL_NONE, controller_mode()); | 
 |   EXPECT_EQ(OverscrollSource::NONE, controller_source()); | 
 |   EXPECT_EQ(OVERSCROLL_NONE, delegate()->current_mode()); | 
 |   EXPECT_EQ(OVERSCROLL_EAST, delegate()->completed_mode()); | 
 |  | 
 |   // Next Inertial update event would be consumed by overscroll controller. | 
 |   EXPECT_TRUE(SimulateGestureScrollUpdate( | 
 |       100, 0, blink::WebGestureDevice::kTouchpad, timestamp, true)); | 
 | } | 
 |  | 
 | // Ensure inertial gesture scroll update can not start overscroll. | 
 | TEST_F(OverscrollControllerTest, InertialGSUsDoNotStartOverscroll) { | 
 |   base::TimeTicks timestamp = | 
 |       blink::WebInputEvent::GetStaticTimeStampForTests(); | 
 |   // Inertial update event complete the overscroll action. | 
 |   EXPECT_FALSE(SimulateGestureScrollUpdate( | 
 |       100, 0, blink::WebGestureDevice::kTouchpad, timestamp, true)); | 
 |   SimulateAck(false); | 
 |   EXPECT_EQ(OVERSCROLL_NONE, controller_mode()); | 
 |   EXPECT_EQ(OverscrollSource::NONE, controller_source()); | 
 |   EXPECT_EQ(OVERSCROLL_NONE, delegate()->current_mode()); | 
 |   EXPECT_EQ(OVERSCROLL_NONE, delegate()->completed_mode()); | 
 | } | 
 |  | 
 | // After 300ms inertial gesture scroll updates, overscroll must get cancelled | 
 | // if not completed. | 
 | TEST_F(OverscrollControllerTest, OnlyProcessLimitedInertialGSUEvents) { | 
 |   base::TimeTicks timestamp = | 
 |       blink::WebInputEvent::GetStaticTimeStampForTests(); | 
 |  | 
 |   EXPECT_FALSE( | 
 |       SimulateGestureEvent(blink::WebInputEvent::Type::kGestureScrollBegin, | 
 |                            blink::WebGestureDevice::kTouchpad, timestamp)); | 
 |   SimulateAck(false); | 
 |  | 
 |   EXPECT_FALSE(SimulateGestureScrollUpdate( | 
 |       61, 0, blink::WebGestureDevice::kTouchpad, timestamp, false)); | 
 |   SimulateAck(false); | 
 |   EXPECT_EQ(OVERSCROLL_EAST, controller_mode()); | 
 |   EXPECT_EQ(OverscrollSource::TOUCHPAD, controller_source()); | 
 |   EXPECT_EQ(OVERSCROLL_EAST, delegate()->current_mode()); | 
 |   EXPECT_EQ(OVERSCROLL_NONE, delegate()->completed_mode()); | 
 |  | 
 |   // First inertial. | 
 |   timestamp += base::Seconds(1); | 
 |   EXPECT_TRUE(SimulateGestureScrollUpdate( | 
 |       1, 0, blink::WebGestureDevice::kTouchpad, timestamp, true)); | 
 |   SimulateAck(true); | 
 |   EXPECT_EQ(OVERSCROLL_EAST, controller_mode()); | 
 |   EXPECT_EQ(OverscrollSource::TOUCHPAD, controller_source()); | 
 |   EXPECT_EQ(OVERSCROLL_EAST, delegate()->current_mode()); | 
 |   EXPECT_EQ(OVERSCROLL_NONE, delegate()->completed_mode()); | 
 |  | 
 |   // Not cancel in 10ms. | 
 |   timestamp += base::Milliseconds(10); | 
 |   EXPECT_TRUE(SimulateGestureScrollUpdate( | 
 |       1, 0, blink::WebGestureDevice::kTouchpad, timestamp, true)); | 
 |   SimulateAck(true); | 
 |   EXPECT_EQ(OVERSCROLL_EAST, controller_mode()); | 
 |   EXPECT_EQ(OverscrollSource::TOUCHPAD, controller_source()); | 
 |   EXPECT_EQ(OVERSCROLL_EAST, delegate()->current_mode()); | 
 |   EXPECT_EQ(OVERSCROLL_NONE, delegate()->completed_mode()); | 
 |  | 
 |   // Cancel after 300ms. | 
 |   timestamp += base::Milliseconds(291); | 
 |   EXPECT_TRUE(SimulateGestureScrollUpdate( | 
 |       1, 0, blink::WebGestureDevice::kTouchpad, timestamp, true)); | 
 |   SimulateAck(true); | 
 |   EXPECT_EQ(OVERSCROLL_NONE, controller_mode()); | 
 |   EXPECT_EQ(OverscrollSource::NONE, controller_source()); | 
 |   EXPECT_EQ(OVERSCROLL_NONE, delegate()->current_mode()); | 
 |   EXPECT_EQ(OVERSCROLL_NONE, delegate()->completed_mode()); | 
 |  | 
 |   // Next event should be ignored. | 
 |   timestamp += base::Milliseconds(100); | 
 |   EXPECT_TRUE(SimulateGestureScrollUpdate( | 
 |       1, 0, blink::WebGestureDevice::kTouchpad, timestamp, true)); | 
 | } | 
 |  | 
 | // Verifies that when pull-to-refresh is disabled, it is not triggered for | 
 | // neither touchpad nor touchscreen. | 
 | TEST_F(OverscrollControllerTest, PullToRefreshDisabled) { | 
 |   ScopedPullToRefreshMode scoped_mode( | 
 |       OverscrollConfig::PullToRefreshMode::kDisabled); | 
 |  | 
 |   base::TimeTicks timestamp = | 
 |       blink::WebInputEvent::GetStaticTimeStampForTests(); | 
 |  | 
 |   EXPECT_FALSE( | 
 |       SimulateGestureEvent(blink::WebInputEvent::Type::kGestureScrollBegin, | 
 |                            blink::WebGestureDevice::kTouchpad, timestamp)); | 
 |   SimulateAck(false); | 
 |  | 
 |   // Simulate a touchpad gesture scroll-update event that passes the start | 
 |   // threshold and ACK it as not processed. Pull-to-refresh should not be | 
 |   // triggered. | 
 |   EXPECT_FALSE(SimulateGestureScrollUpdate( | 
 |       0, 80, blink::WebGestureDevice::kTouchpad, timestamp, false)); | 
 |   SimulateAck(false); | 
 |   EXPECT_EQ(OVERSCROLL_NONE, controller_mode()); | 
 |   EXPECT_EQ(OverscrollSource::NONE, controller_source()); | 
 |   EXPECT_EQ(OVERSCROLL_NONE, delegate()->current_mode()); | 
 |   EXPECT_EQ(OVERSCROLL_NONE, delegate()->completed_mode()); | 
 |  | 
 |   timestamp += base::Seconds(1); | 
 |  | 
 |   // Simulate a touchpad zero-velocity fling-start which would normally end | 
 |   // pull-to-refresh, and ACK it as not processed. Nothing should happen. | 
 |   EXPECT_FALSE(SimulateGestureFlingStart( | 
 |       0, 0, blink::WebGestureDevice::kTouchpad, timestamp)); | 
 |   SimulateAck(false); | 
 |   EXPECT_EQ(OVERSCROLL_NONE, controller_mode()); | 
 |   EXPECT_EQ(OverscrollSource::NONE, controller_source()); | 
 |   EXPECT_EQ(OVERSCROLL_NONE, delegate()->current_mode()); | 
 |   EXPECT_EQ(OVERSCROLL_NONE, delegate()->completed_mode()); | 
 |  | 
 |   timestamp += base::Seconds(1); | 
 |  | 
 |   EXPECT_FALSE( | 
 |       SimulateGestureEvent(blink::WebInputEvent::Type::kGestureScrollBegin, | 
 |                            blink::WebGestureDevice::kTouchscreen, timestamp)); | 
 |   SimulateAck(false); | 
 |  | 
 |   // Simulate a touchscreen gesture scroll-update event that passes the start | 
 |   // threshold and ACK it as not processed. Pull-to-refresh should not be | 
 |   // triggered. | 
 |   EXPECT_FALSE(SimulateGestureScrollUpdate( | 
 |       0, 80, blink::WebGestureDevice::kTouchscreen, timestamp, false)); | 
 |   SimulateAck(false); | 
 |   EXPECT_EQ(OVERSCROLL_NONE, controller_mode()); | 
 |   EXPECT_EQ(OverscrollSource::NONE, controller_source()); | 
 |   EXPECT_EQ(OVERSCROLL_NONE, delegate()->current_mode()); | 
 |   EXPECT_EQ(OVERSCROLL_NONE, delegate()->completed_mode()); | 
 |  | 
 |   timestamp += base::Seconds(1); | 
 |  | 
 |   // Simulate a touchscreen gesture scroll-end which would normally end | 
 |   // pull-to-refresh, and ACK it as not processed. Nothing should happen. | 
 |   EXPECT_FALSE( | 
 |       SimulateGestureEvent(blink::WebInputEvent::Type::kGestureScrollEnd, | 
 |                            blink::WebGestureDevice::kTouchscreen, timestamp)); | 
 |   SimulateAck(false); | 
 |   EXPECT_EQ(OVERSCROLL_NONE, controller_mode()); | 
 |   EXPECT_EQ(OverscrollSource::NONE, controller_source()); | 
 |   EXPECT_EQ(OVERSCROLL_NONE, delegate()->current_mode()); | 
 |   EXPECT_EQ(OVERSCROLL_NONE, delegate()->completed_mode()); | 
 | } | 
 |  | 
 | // Verifies that when pull-to-refresh is enabled, it is triggered for both | 
 | // touchpad and touchscreen. | 
 | TEST_F(OverscrollControllerTest, PullToRefreshEnabled) { | 
 |   ScopedPullToRefreshMode scoped_mode( | 
 |       OverscrollConfig::PullToRefreshMode::kEnabled); | 
 |  | 
 |   base::TimeTicks timestamp = | 
 |       blink::WebInputEvent::GetStaticTimeStampForTests(); | 
 |  | 
 |   EXPECT_FALSE( | 
 |       SimulateGestureEvent(blink::WebInputEvent::Type::kGestureScrollBegin, | 
 |                            blink::WebGestureDevice::kTouchpad, timestamp)); | 
 |   SimulateAck(false); | 
 |  | 
 |   // Simulate a touchpad gesture scroll-update event that passes the start | 
 |   // threshold and ACK it as not processed. Pull-to-refresh should be triggered. | 
 |   EXPECT_FALSE(SimulateGestureScrollUpdate( | 
 |       0, 80, blink::WebGestureDevice::kTouchpad, timestamp, false)); | 
 |   SimulateAck(false); | 
 |   EXPECT_EQ(OVERSCROLL_SOUTH, controller_mode()); | 
 |   EXPECT_EQ(OverscrollSource::TOUCHPAD, controller_source()); | 
 |   EXPECT_EQ(OVERSCROLL_SOUTH, delegate()->current_mode()); | 
 |   EXPECT_EQ(OVERSCROLL_NONE, delegate()->completed_mode()); | 
 |  | 
 |   timestamp += base::Seconds(1); | 
 |  | 
 |   // Simulate a touchpad zero-velocity fling-start and ACK it as not processed.. | 
 |   // It should abort pull-to-refresh. | 
 |   EXPECT_FALSE(SimulateGestureFlingStart( | 
 |       0, 0, blink::WebGestureDevice::kTouchpad, timestamp)); | 
 |   SimulateAck(false); | 
 |   EXPECT_EQ(OVERSCROLL_NONE, controller_mode()); | 
 |   EXPECT_EQ(OverscrollSource::NONE, controller_source()); | 
 |   EXPECT_EQ(OVERSCROLL_NONE, delegate()->current_mode()); | 
 |   EXPECT_EQ(OVERSCROLL_NONE, delegate()->completed_mode()); | 
 |  | 
 |   timestamp += base::Seconds(1); | 
 |  | 
 |   EXPECT_FALSE( | 
 |       SimulateGestureEvent(blink::WebInputEvent::Type::kGestureScrollBegin, | 
 |                            blink::WebGestureDevice::kTouchscreen, timestamp)); | 
 |   SimulateAck(false); | 
 |  | 
 |   // Simulate a touchscreen gesture scroll-update event that passes the start | 
 |   // threshold and ACK it as not processed. Pull-to-refresh should be triggered. | 
 |   EXPECT_FALSE(SimulateGestureScrollUpdate( | 
 |       0, 80, blink::WebGestureDevice::kTouchscreen, timestamp, false)); | 
 |   SimulateAck(false); | 
 |   EXPECT_EQ(OVERSCROLL_SOUTH, controller_mode()); | 
 |   EXPECT_EQ(OverscrollSource::TOUCHSCREEN, controller_source()); | 
 |   EXPECT_EQ(OVERSCROLL_SOUTH, delegate()->current_mode()); | 
 |   EXPECT_EQ(OVERSCROLL_NONE, delegate()->completed_mode()); | 
 |  | 
 |   timestamp += base::Seconds(1); | 
 |  | 
 |   // Simulate a touchscreen gesture scroll-end and ACK it as not processed. It | 
 |   // should abort pull-to-refresh. | 
 |   EXPECT_FALSE( | 
 |       SimulateGestureEvent(blink::WebInputEvent::Type::kGestureScrollEnd, | 
 |                            blink::WebGestureDevice::kTouchscreen, timestamp)); | 
 |   SimulateAck(false); | 
 |   EXPECT_EQ(OVERSCROLL_NONE, controller_mode()); | 
 |   EXPECT_EQ(OverscrollSource::NONE, controller_source()); | 
 |   EXPECT_EQ(OVERSCROLL_NONE, delegate()->current_mode()); | 
 |   EXPECT_EQ(OVERSCROLL_NONE, delegate()->completed_mode()); | 
 | } | 
 |  | 
 | // Verifies that when pull-to-refresh is enabled only for touchscreen, it is | 
 | // triggered for touchscreen but not for touchpad. | 
 | TEST_F(OverscrollControllerTest, PullToRefreshEnabledTouchscreen) { | 
 |   ScopedPullToRefreshMode scoped_mode( | 
 |       OverscrollConfig::PullToRefreshMode::kEnabledTouchschreen); | 
 |  | 
 |   base::TimeTicks timestamp = | 
 |       blink::WebInputEvent::GetStaticTimeStampForTests(); | 
 |  | 
 |   EXPECT_FALSE( | 
 |       SimulateGestureEvent(blink::WebInputEvent::Type::kGestureScrollBegin, | 
 |                            blink::WebGestureDevice::kTouchpad, timestamp)); | 
 |   SimulateAck(false); | 
 |  | 
 |   // Simulate a touchpad gesture scroll-update event that passes the start | 
 |   // threshold and ACK it as not processed. Pull-to-refresh should not be | 
 |   // triggered. | 
 |   EXPECT_FALSE(SimulateGestureScrollUpdate( | 
 |       0, 80, blink::WebGestureDevice::kTouchpad, timestamp, false)); | 
 |   SimulateAck(false); | 
 |   EXPECT_EQ(OVERSCROLL_NONE, controller_mode()); | 
 |   EXPECT_EQ(OverscrollSource::NONE, controller_source()); | 
 |   EXPECT_EQ(OVERSCROLL_NONE, delegate()->current_mode()); | 
 |   EXPECT_EQ(OVERSCROLL_NONE, delegate()->completed_mode()); | 
 |  | 
 |   timestamp += base::Seconds(1); | 
 |  | 
 |   // Simulate a touchpad zero-velocity fling-start which would normally end | 
 |   // pull-to-refresh, and ACK it as not processed. Nothing should happen. | 
 |   EXPECT_FALSE(SimulateGestureFlingStart( | 
 |       0, 0, blink::WebGestureDevice::kTouchpad, timestamp)); | 
 |   SimulateAck(false); | 
 |   EXPECT_EQ(OVERSCROLL_NONE, controller_mode()); | 
 |   EXPECT_EQ(OverscrollSource::NONE, controller_source()); | 
 |   EXPECT_EQ(OVERSCROLL_NONE, delegate()->current_mode()); | 
 |   EXPECT_EQ(OVERSCROLL_NONE, delegate()->completed_mode()); | 
 |  | 
 |   timestamp += base::Seconds(1); | 
 |  | 
 |   EXPECT_FALSE( | 
 |       SimulateGestureEvent(blink::WebInputEvent::Type::kGestureScrollBegin, | 
 |                            blink::WebGestureDevice::kTouchscreen, timestamp)); | 
 |   SimulateAck(false); | 
 |  | 
 |   // Simulate a touchscreen gesture scroll-update event that passes the start | 
 |   // threshold and ACK it as not processed. Pull-to-refresh should be triggered. | 
 |   EXPECT_FALSE(SimulateGestureScrollUpdate( | 
 |       0, 80, blink::WebGestureDevice::kTouchscreen, timestamp, false)); | 
 |   SimulateAck(false); | 
 |   EXPECT_EQ(OVERSCROLL_SOUTH, controller_mode()); | 
 |   EXPECT_EQ(OverscrollSource::TOUCHSCREEN, controller_source()); | 
 |   EXPECT_EQ(OVERSCROLL_SOUTH, delegate()->current_mode()); | 
 |   EXPECT_EQ(OVERSCROLL_NONE, delegate()->completed_mode()); | 
 |  | 
 |   timestamp += base::Seconds(1); | 
 |  | 
 |   // Simulate a touchscreen gesture scroll-end and ACK it as not processed. It | 
 |   // should abort pull-to-refresh. | 
 |   EXPECT_FALSE( | 
 |       SimulateGestureEvent(blink::WebInputEvent::Type::kGestureScrollEnd, | 
 |                            blink::WebGestureDevice::kTouchscreen, timestamp)); | 
 |   SimulateAck(false); | 
 |   EXPECT_EQ(OVERSCROLL_NONE, controller_mode()); | 
 |   EXPECT_EQ(OverscrollSource::NONE, controller_source()); | 
 |   EXPECT_EQ(OVERSCROLL_NONE, delegate()->current_mode()); | 
 |   EXPECT_EQ(OVERSCROLL_NONE, delegate()->completed_mode()); | 
 | } | 
 |  | 
 | // Ensure disabling kTouchpadOverscrollHistoryNavigation will prevent overscroll | 
 | // from touchpad. | 
 | TEST_F(OverscrollControllerTest, DisableTouchpadOverscrollHistoryNavigation) { | 
 |   base::test::ScopedFeatureList feature_list; | 
 |   feature_list.InitAndDisableFeature( | 
 |       features::kTouchpadOverscrollHistoryNavigation); | 
 |   ASSERT_FALSE(OverscrollConfig::TouchpadOverscrollHistoryNavigationEnabled()); | 
 |  | 
 |   const base::TimeTicks timestamp = | 
 |       blink::WebInputEvent::GetStaticTimeStampForTests(); | 
 |  | 
 |   EXPECT_FALSE(SimulateGestureScrollUpdate( | 
 |       200, 0, blink::WebGestureDevice::kTouchpad, timestamp, false)); | 
 |   SimulateAck(false); | 
 |  | 
 |   EXPECT_EQ(OVERSCROLL_NONE, controller_mode()); | 
 |   EXPECT_EQ(OverscrollSource::NONE, controller_source()); | 
 |   EXPECT_EQ(OVERSCROLL_NONE, delegate()->current_mode()); | 
 |   EXPECT_EQ(OVERSCROLL_NONE, delegate()->completed_mode()); | 
 | } | 
 |  | 
 | // Verifies that if an overscroll happens before cool off period after a page | 
 | // scroll, it does not trigger pull-to-refresh. Verifies following sequence of | 
 | // scrolls: | 
 | //  1) Page scroll; | 
 | //  2) Scroll before cool off -> PTR not triggered; | 
 | //  3) Scroll before cool off -> PTR not triggered; | 
 | //  4) Scroll after cool off  -> PTR triggered; | 
 | //  5) Scroll before cool off -> PTR triggered. | 
 | TEST_F(OverscrollControllerTest, PullToRefreshBeforeCoolOff) { | 
 |   ScopedPullToRefreshMode scoped_mode( | 
 |       OverscrollConfig::PullToRefreshMode::kEnabled); | 
 |  | 
 |   // 1) Page scroll. | 
 |   base::TimeTicks timestamp = | 
 |       blink::WebInputEvent::GetStaticTimeStampForTests(); | 
 |  | 
 |   EXPECT_FALSE( | 
 |       SimulateGestureEvent(blink::WebInputEvent::Type::kGestureScrollBegin, | 
 |                            blink::WebGestureDevice::kTouchscreen, timestamp)); | 
 |   SimulateAck(false); | 
 |  | 
 |   // Simulate a touchscreen gesture scroll-update event that passes the start | 
 |   // threshold and ACK it as processed. Pull-to-refresh should not be triggered. | 
 |   EXPECT_FALSE(SimulateGestureScrollUpdate( | 
 |       0, 80, blink::WebGestureDevice::kTouchscreen, timestamp, false)); | 
 |   SimulateAck(true); | 
 |   EXPECT_EQ(OVERSCROLL_NONE, controller_mode()); | 
 |   EXPECT_EQ(OverscrollSource::NONE, controller_source()); | 
 |   EXPECT_EQ(OVERSCROLL_NONE, delegate()->current_mode()); | 
 |   EXPECT_EQ(OVERSCROLL_NONE, delegate()->completed_mode()); | 
 |  | 
 |   timestamp += base::Seconds(1); | 
 |  | 
 |   // Simulate a touchscreen gesture scroll-end which would normally end | 
 |   // pull-to-refresh, and ACK it as not processed. Nothing should happen. | 
 |   EXPECT_FALSE( | 
 |       SimulateGestureEvent(blink::WebInputEvent::Type::kGestureScrollEnd, | 
 |                            blink::WebGestureDevice::kTouchscreen, timestamp)); | 
 |   SimulateAck(false); | 
 |   EXPECT_EQ(OVERSCROLL_NONE, controller_mode()); | 
 |   EXPECT_EQ(OverscrollSource::NONE, controller_source()); | 
 |   EXPECT_EQ(OVERSCROLL_NONE, delegate()->current_mode()); | 
 |   EXPECT_EQ(OVERSCROLL_NONE, delegate()->completed_mode()); | 
 |  | 
 |   // 2) Scroll before cool off -> PTR not triggered. | 
 |   timestamp += base::Milliseconds(500); | 
 |  | 
 |   EXPECT_FALSE( | 
 |       SimulateGestureEvent(blink::WebInputEvent::Type::kGestureScrollBegin, | 
 |                            blink::WebGestureDevice::kTouchscreen, timestamp)); | 
 |   SimulateAck(false); | 
 |  | 
 |   // Simulate a touchscreen gesture scroll-update event that passes the start | 
 |   // threshold and ACK it as not processed. Pull-to-refresh should not be | 
 |   // triggered. | 
 |   EXPECT_FALSE(SimulateGestureScrollUpdate( | 
 |       0, 80, blink::WebGestureDevice::kTouchscreen, timestamp, false)); | 
 |   SimulateAck(false); | 
 |   EXPECT_EQ(OVERSCROLL_NONE, controller_mode()); | 
 |   EXPECT_EQ(OverscrollSource::NONE, controller_source()); | 
 |   EXPECT_EQ(OVERSCROLL_NONE, delegate()->current_mode()); | 
 |   EXPECT_EQ(OVERSCROLL_NONE, delegate()->completed_mode()); | 
 |  | 
 |   timestamp += base::Seconds(1); | 
 |  | 
 |   // Simulate a touchscreen gesture scroll-end which would normally end | 
 |   // pull-to-refresh, and ACK it as not processed. Nothing should happen. | 
 |   EXPECT_FALSE( | 
 |       SimulateGestureEvent(blink::WebInputEvent::Type::kGestureScrollEnd, | 
 |                            blink::WebGestureDevice::kTouchscreen, timestamp)); | 
 |   SimulateAck(false); | 
 |   EXPECT_EQ(OVERSCROLL_NONE, controller_mode()); | 
 |   EXPECT_EQ(OverscrollSource::NONE, controller_source()); | 
 |   EXPECT_EQ(OVERSCROLL_NONE, delegate()->current_mode()); | 
 |   EXPECT_EQ(OVERSCROLL_NONE, delegate()->completed_mode()); | 
 |  | 
 |   // 3) Scroll before cool off -> PTR not triggered. | 
 |   timestamp += base::Milliseconds(500); | 
 |  | 
 |   EXPECT_FALSE( | 
 |       SimulateGestureEvent(blink::WebInputEvent::Type::kGestureScrollBegin, | 
 |                            blink::WebGestureDevice::kTouchscreen, timestamp)); | 
 |   SimulateAck(false); | 
 |  | 
 |   // Simulate a touchscreen gesture scroll-update event that passes the start | 
 |   // threshold and ACK it as not processed. Pull-to-refresh should not be | 
 |   // triggered. | 
 |   EXPECT_FALSE(SimulateGestureScrollUpdate( | 
 |       0, 80, blink::WebGestureDevice::kTouchscreen, timestamp, false)); | 
 |   SimulateAck(false); | 
 |   EXPECT_EQ(OVERSCROLL_NONE, controller_mode()); | 
 |   EXPECT_EQ(OverscrollSource::NONE, controller_source()); | 
 |   EXPECT_EQ(OVERSCROLL_NONE, delegate()->current_mode()); | 
 |   EXPECT_EQ(OVERSCROLL_NONE, delegate()->completed_mode()); | 
 |  | 
 |   timestamp += base::Seconds(1); | 
 |  | 
 |   // Simulate a touchscreen gesture scroll-end which would normally end | 
 |   // pull-to-refresh, and ACK it as not processed. Nothing should happen. | 
 |   EXPECT_FALSE( | 
 |       SimulateGestureEvent(blink::WebInputEvent::Type::kGestureScrollEnd, | 
 |                            blink::WebGestureDevice::kTouchscreen, timestamp)); | 
 |   SimulateAck(false); | 
 |   EXPECT_EQ(OVERSCROLL_NONE, controller_mode()); | 
 |   EXPECT_EQ(OverscrollSource::NONE, controller_source()); | 
 |   EXPECT_EQ(OVERSCROLL_NONE, delegate()->current_mode()); | 
 |   EXPECT_EQ(OVERSCROLL_NONE, delegate()->completed_mode()); | 
 |  | 
 |   // 4) Scroll after cool off -> PTR triggered. | 
 |   timestamp += base::Seconds(1); | 
 |  | 
 |   EXPECT_FALSE( | 
 |       SimulateGestureEvent(blink::WebInputEvent::Type::kGestureScrollBegin, | 
 |                            blink::WebGestureDevice::kTouchscreen, timestamp)); | 
 |   SimulateAck(false); | 
 |  | 
 |   // Simulate a touchscreen gesture scroll-update event that passes the start | 
 |   // threshold and ACK it as not processed. Pull-to-refresh should be triggered. | 
 |   EXPECT_FALSE(SimulateGestureScrollUpdate( | 
 |       0, 80, blink::WebGestureDevice::kTouchscreen, timestamp, false)); | 
 |   SimulateAck(false); | 
 |   EXPECT_EQ(OVERSCROLL_SOUTH, controller_mode()); | 
 |   EXPECT_EQ(OverscrollSource::TOUCHSCREEN, controller_source()); | 
 |   EXPECT_EQ(OVERSCROLL_SOUTH, delegate()->current_mode()); | 
 |   EXPECT_EQ(OVERSCROLL_NONE, delegate()->completed_mode()); | 
 |  | 
 |   timestamp += base::Seconds(1); | 
 |  | 
 |   // Simulate a touchscreen gesture scroll-end which will end pull-to-refresh, | 
 |   // and ACK it as not processed. Pull-to-refresh should be aborted. | 
 |   EXPECT_FALSE( | 
 |       SimulateGestureEvent(blink::WebInputEvent::Type::kGestureScrollEnd, | 
 |                            blink::WebGestureDevice::kTouchscreen, timestamp)); | 
 |   SimulateAck(false); | 
 |   EXPECT_EQ(OVERSCROLL_NONE, controller_mode()); | 
 |   EXPECT_EQ(OverscrollSource::NONE, controller_source()); | 
 |   EXPECT_EQ(OVERSCROLL_NONE, delegate()->current_mode()); | 
 |   EXPECT_EQ(OVERSCROLL_NONE, delegate()->completed_mode()); | 
 |  | 
 |   // 5) Scroll before cool off -> PTR triggered. | 
 |   timestamp += base::Milliseconds(500); | 
 |  | 
 |   EXPECT_FALSE( | 
 |       SimulateGestureEvent(blink::WebInputEvent::Type::kGestureScrollBegin, | 
 |                            blink::WebGestureDevice::kTouchscreen, timestamp)); | 
 |   SimulateAck(false); | 
 |  | 
 |   // Simulate a touchscreen gesture scroll-update event that passes the start | 
 |   // threshold and ACK it as not processed. Pull-to-refresh should be triggered. | 
 |   EXPECT_FALSE(SimulateGestureScrollUpdate( | 
 |       0, 80, blink::WebGestureDevice::kTouchscreen, timestamp, false)); | 
 |   SimulateAck(false); | 
 |   EXPECT_EQ(OVERSCROLL_SOUTH, controller_mode()); | 
 |   EXPECT_EQ(OverscrollSource::TOUCHSCREEN, controller_source()); | 
 |   EXPECT_EQ(OVERSCROLL_SOUTH, delegate()->current_mode()); | 
 |   EXPECT_EQ(OVERSCROLL_NONE, delegate()->completed_mode()); | 
 |  | 
 |   timestamp += base::Seconds(1); | 
 |  | 
 |   // Simulate a touchscreen gesture scroll-end which will end pull-to-refresh, | 
 |   // and ACK it as not processed. Pull-to-refresh should be aborted. | 
 |   EXPECT_FALSE( | 
 |       SimulateGestureEvent(blink::WebInputEvent::Type::kGestureScrollEnd, | 
 |                            blink::WebGestureDevice::kTouchscreen, timestamp)); | 
 |   SimulateAck(false); | 
 |   EXPECT_EQ(OVERSCROLL_NONE, controller_mode()); | 
 |   EXPECT_EQ(OverscrollSource::NONE, controller_source()); | 
 |   EXPECT_EQ(OVERSCROLL_NONE, delegate()->current_mode()); | 
 |   EXPECT_EQ(OVERSCROLL_NONE, delegate()->completed_mode()); | 
 | } | 
 |  | 
 | // Verifies that if an overscroll happens after cool off period after a page | 
 | // scroll, it triggers pull-to-refresh. Verifies the following sequence of | 
 | // scrolls: | 
 | //  1) Page scroll; | 
 | //  2) Scroll after cool off  -> PTR triggered; | 
 | //  3) Scroll before cool off -> PTR triggered; | 
 | TEST_F(OverscrollControllerTest, PullToRefreshAfterCoolOff) { | 
 |   ScopedPullToRefreshMode scoped_mode( | 
 |       OverscrollConfig::PullToRefreshMode::kEnabled); | 
 |  | 
 |   // 1) Page scroll. | 
 |   base::TimeTicks timestamp = | 
 |       blink::WebInputEvent::GetStaticTimeStampForTests(); | 
 |  | 
 |   EXPECT_FALSE( | 
 |       SimulateGestureEvent(blink::WebInputEvent::Type::kGestureScrollBegin, | 
 |                            blink::WebGestureDevice::kTouchscreen, timestamp)); | 
 |   SimulateAck(false); | 
 |  | 
 |   // Simulate a touchscreen gesture scroll-update event that passes the start | 
 |   // threshold and ACK it as processed. Pull-to-refresh should not be triggered. | 
 |   EXPECT_FALSE(SimulateGestureScrollUpdate( | 
 |       0, 80, blink::WebGestureDevice::kTouchscreen, timestamp, false)); | 
 |   SimulateAck(true); | 
 |   EXPECT_EQ(OVERSCROLL_NONE, controller_mode()); | 
 |   EXPECT_EQ(OverscrollSource::NONE, controller_source()); | 
 |   EXPECT_EQ(OVERSCROLL_NONE, delegate()->current_mode()); | 
 |   EXPECT_EQ(OVERSCROLL_NONE, delegate()->completed_mode()); | 
 |  | 
 |   timestamp += base::Seconds(1); | 
 |  | 
 |   // Simulate a touchscreen gesture scroll-end which would normally end | 
 |   // pull-to-refresh, and ACK it as not processed. Nothing should happen. | 
 |   EXPECT_FALSE( | 
 |       SimulateGestureEvent(blink::WebInputEvent::Type::kGestureScrollEnd, | 
 |                            blink::WebGestureDevice::kTouchscreen, timestamp)); | 
 |   SimulateAck(false); | 
 |   EXPECT_EQ(OVERSCROLL_NONE, controller_mode()); | 
 |   EXPECT_EQ(OverscrollSource::NONE, controller_source()); | 
 |   EXPECT_EQ(OVERSCROLL_NONE, delegate()->current_mode()); | 
 |   EXPECT_EQ(OVERSCROLL_NONE, delegate()->completed_mode()); | 
 |  | 
 |   // 2) Scroll after cool off -> PTR triggered. | 
 |   timestamp += base::Seconds(1); | 
 |  | 
 |   EXPECT_FALSE( | 
 |       SimulateGestureEvent(blink::WebInputEvent::Type::kGestureScrollBegin, | 
 |                            blink::WebGestureDevice::kTouchscreen, timestamp)); | 
 |   SimulateAck(false); | 
 |  | 
 |   // Simulate a touchscreen gesture scroll-update event that passes the start | 
 |   // threshold and ACK it as not processed. Pull-to-refresh should be triggered. | 
 |   EXPECT_FALSE(SimulateGestureScrollUpdate( | 
 |       0, 80, blink::WebGestureDevice::kTouchscreen, timestamp, false)); | 
 |   SimulateAck(false); | 
 |   EXPECT_EQ(OVERSCROLL_SOUTH, controller_mode()); | 
 |   EXPECT_EQ(OverscrollSource::TOUCHSCREEN, controller_source()); | 
 |   EXPECT_EQ(OVERSCROLL_SOUTH, delegate()->current_mode()); | 
 |   EXPECT_EQ(OVERSCROLL_NONE, delegate()->completed_mode()); | 
 |  | 
 |   timestamp += base::Seconds(1); | 
 |  | 
 |   // Simulate a touchscreen gesture scroll-end which will end pull-to-refresh, | 
 |   // and ACK it as not processed. Pull-to-refresh should be aborted. | 
 |   EXPECT_FALSE( | 
 |       SimulateGestureEvent(blink::WebInputEvent::Type::kGestureScrollEnd, | 
 |                            blink::WebGestureDevice::kTouchscreen, timestamp)); | 
 |   SimulateAck(false); | 
 |   EXPECT_EQ(OVERSCROLL_NONE, controller_mode()); | 
 |   EXPECT_EQ(OverscrollSource::NONE, controller_source()); | 
 |   EXPECT_EQ(OVERSCROLL_NONE, delegate()->current_mode()); | 
 |   EXPECT_EQ(OVERSCROLL_NONE, delegate()->completed_mode()); | 
 |  | 
 |   // 3) Scroll before cool off -> PTR triggered. | 
 |   timestamp += base::Milliseconds(500); | 
 |  | 
 |   EXPECT_FALSE( | 
 |       SimulateGestureEvent(blink::WebInputEvent::Type::kGestureScrollBegin, | 
 |                            blink::WebGestureDevice::kTouchscreen, timestamp)); | 
 |   SimulateAck(false); | 
 |  | 
 |   // Simulate a touchscreen gesture scroll-update event that passes the start | 
 |   // threshold and ACK it as not processed. Pull-to-refresh should be triggered. | 
 |   EXPECT_FALSE(SimulateGestureScrollUpdate( | 
 |       0, 80, blink::WebGestureDevice::kTouchscreen, timestamp, false)); | 
 |   SimulateAck(false); | 
 |   EXPECT_EQ(OVERSCROLL_SOUTH, controller_mode()); | 
 |   EXPECT_EQ(OverscrollSource::TOUCHSCREEN, controller_source()); | 
 |   EXPECT_EQ(OVERSCROLL_SOUTH, delegate()->current_mode()); | 
 |   EXPECT_EQ(OVERSCROLL_NONE, delegate()->completed_mode()); | 
 |  | 
 |   timestamp += base::Seconds(1); | 
 |  | 
 |   // Simulate a touchscreen gesture scroll-end which will end pull-to-refresh, | 
 |   // and ACK it as not processed. Pull-to-refresh should be aborted. | 
 |   EXPECT_FALSE( | 
 |       SimulateGestureEvent(blink::WebInputEvent::Type::kGestureScrollEnd, | 
 |                            blink::WebGestureDevice::kTouchscreen, timestamp)); | 
 |   SimulateAck(false); | 
 |   EXPECT_EQ(OVERSCROLL_NONE, controller_mode()); | 
 |   EXPECT_EQ(OverscrollSource::NONE, controller_source()); | 
 |   EXPECT_EQ(OVERSCROLL_NONE, delegate()->current_mode()); | 
 |   EXPECT_EQ(OVERSCROLL_NONE, delegate()->completed_mode()); | 
 | } | 
 |  | 
 | }  // namespace content |