|  | // 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 "base/basictypes.h" | 
|  | #include "base/logging.h" | 
|  | #include "base/memory/scoped_ptr.h" | 
|  | #include "base/message_loop/message_loop.h" | 
|  | #include "base/time/time.h" | 
|  | #include "testing/gtest/include/gtest/gtest.h" | 
|  | #include "ui/events/event_constants.h" | 
|  | #include "ui/events/gesture_detection/gesture_event_data.h" | 
|  | #include "ui/events/gesture_detection/gesture_provider.h" | 
|  | #include "ui/events/gesture_detection/motion_event.h" | 
|  | #include "ui/events/test/motion_event_test_utils.h" | 
|  | #include "ui/gfx/geometry/point_f.h" | 
|  |  | 
|  | using base::TimeDelta; | 
|  | using base::TimeTicks; | 
|  | using ui::test::MockMotionEvent; | 
|  |  | 
|  | namespace ui { | 
|  | namespace { | 
|  |  | 
|  | const float kFakeCoordX = 42.f; | 
|  | const float kFakeCoordY = 24.f; | 
|  | const TimeDelta kOneSecond = TimeDelta::FromSeconds(1); | 
|  | const TimeDelta kOneMicrosecond = TimeDelta::FromMicroseconds(1); | 
|  | const TimeDelta kDeltaTimeForFlingSequences = TimeDelta::FromMilliseconds(5); | 
|  | const float kMockTouchRadius = MockMotionEvent::TOUCH_MAJOR / 2; | 
|  | const float kMaxTwoFingerTapSeparation = 300; | 
|  |  | 
|  | GestureProvider::Config CreateDefaultConfig() { | 
|  | GestureProvider::Config sConfig; | 
|  | // The longpress timeout is non-zero only to indicate ordering with respect to | 
|  | // the showpress timeout. | 
|  | sConfig.gesture_detector_config.showpress_timeout = base::TimeDelta(); | 
|  | sConfig.gesture_detector_config.longpress_timeout = kOneMicrosecond; | 
|  |  | 
|  | // A valid doubletap timeout should always be non-zero. The value is used not | 
|  | // only to trigger the timeout that confirms the tap event, but also to gate | 
|  | // whether the second tap is in fact a double-tap (using a strict inequality | 
|  | // between times for the first up and the second down events). We use 4 | 
|  | // microseconds simply to allow several intermediate events to occur before | 
|  | // the second tap at microsecond intervals. | 
|  | sConfig.gesture_detector_config.double_tap_timeout = kOneMicrosecond * 4; | 
|  | sConfig.gesture_detector_config.double_tap_min_time = kOneMicrosecond * 2; | 
|  | return sConfig; | 
|  | } | 
|  |  | 
|  | gfx::RectF BoundsForSingleMockTouchAtLocation(float x, float y) { | 
|  | float diameter = MockMotionEvent::TOUCH_MAJOR; | 
|  | return gfx::RectF(x - diameter / 2, y - diameter / 2, diameter, diameter); | 
|  | } | 
|  |  | 
|  | }  // namespace | 
|  |  | 
|  | class GestureProviderTest : public testing::Test, public GestureProviderClient { | 
|  | public: | 
|  | GestureProviderTest() {} | 
|  | ~GestureProviderTest() override {} | 
|  |  | 
|  | static MockMotionEvent ObtainMotionEvent(base::TimeTicks event_time, | 
|  | MotionEvent::Action action, | 
|  | float x, | 
|  | float y) { | 
|  | return MockMotionEvent(action, event_time, x, y); | 
|  | } | 
|  |  | 
|  | static MockMotionEvent ObtainMotionEvent(base::TimeTicks event_time, | 
|  | MotionEvent::Action action, | 
|  | float x0, | 
|  | float y0, | 
|  | float x1, | 
|  | float y1) { | 
|  | return MockMotionEvent(action, event_time, x0, y0, x1, y1); | 
|  | } | 
|  |  | 
|  | static MockMotionEvent ObtainMotionEvent(base::TimeTicks event_time, | 
|  | MotionEvent::Action action, | 
|  | float x0, | 
|  | float y0, | 
|  | float x1, | 
|  | float y1, | 
|  | float x2, | 
|  | float y2) { | 
|  | return MockMotionEvent(action, event_time, x0, y0, x1, y1, x2, y2); | 
|  | } | 
|  |  | 
|  | static MockMotionEvent ObtainMotionEvent( | 
|  | base::TimeTicks event_time, | 
|  | MotionEvent::Action action, | 
|  | const std::vector<gfx::PointF>& positions) { | 
|  | switch (positions.size()) { | 
|  | case 1: | 
|  | return MockMotionEvent( | 
|  | action, event_time, positions[0].x(), positions[0].y()); | 
|  | case 2: | 
|  | return MockMotionEvent(action, | 
|  | event_time, | 
|  | positions[0].x(), | 
|  | positions[0].y(), | 
|  | positions[1].x(), | 
|  | positions[1].y()); | 
|  | case 3: | 
|  | return MockMotionEvent(action, | 
|  | event_time, | 
|  | positions[0].x(), | 
|  | positions[0].y(), | 
|  | positions[1].x(), | 
|  | positions[1].y(), | 
|  | positions[2].x(), | 
|  | positions[2].y()); | 
|  | default: | 
|  | CHECK(false) << "MockMotionEvent only supports 1-3 pointers"; | 
|  | return MockMotionEvent(); | 
|  | } | 
|  | } | 
|  |  | 
|  | static MockMotionEvent ObtainMotionEvent(base::TimeTicks event_time, | 
|  | MotionEvent::Action action) { | 
|  | return ObtainMotionEvent(event_time, action, kFakeCoordX, kFakeCoordY); | 
|  | } | 
|  |  | 
|  | // Test | 
|  | void SetUp() override { SetUpWithConfig(GetDefaultConfig()); } | 
|  |  | 
|  | void TearDown() override { | 
|  | gestures_.clear(); | 
|  | gesture_provider_.reset(); | 
|  | } | 
|  |  | 
|  | // GestureProviderClient | 
|  | void OnGestureEvent(const GestureEventData& gesture) override { | 
|  | if (gesture.type() == ET_GESTURE_SCROLL_BEGIN) | 
|  | active_scroll_begin_event_.reset(new GestureEventData(gesture)); | 
|  | gestures_.push_back(gesture); | 
|  | } | 
|  |  | 
|  | void SetUpWithConfig(const GestureProvider::Config& config) { | 
|  | gesture_provider_.reset(new GestureProvider(config, this)); | 
|  | gesture_provider_->SetMultiTouchZoomSupportEnabled(false); | 
|  | } | 
|  |  | 
|  | void ResetGestureDetection() { | 
|  | gesture_provider_->ResetDetection(); | 
|  | gestures_.clear(); | 
|  | } | 
|  |  | 
|  | bool CancelActiveTouchSequence() { | 
|  | if (!gesture_provider_->current_down_event()) | 
|  | return false; | 
|  | return gesture_provider_->OnTouchEvent( | 
|  | *gesture_provider_->current_down_event()->Cancel()); | 
|  | } | 
|  |  | 
|  | bool HasReceivedGesture(EventType type) const { | 
|  | for (size_t i = 0; i < gestures_.size(); ++i) { | 
|  | if (gestures_[i].type() == type) | 
|  | return true; | 
|  | } | 
|  | return false; | 
|  | } | 
|  |  | 
|  | const GestureEventData& GetMostRecentGestureEvent() const { | 
|  | EXPECT_FALSE(gestures_.empty()); | 
|  | return gestures_.back(); | 
|  | } | 
|  |  | 
|  | EventType GetMostRecentGestureEventType() const { | 
|  | EXPECT_FALSE(gestures_.empty()); | 
|  | return gestures_.back().type(); | 
|  | } | 
|  |  | 
|  | size_t GetReceivedGestureCount() const { return gestures_.size(); } | 
|  |  | 
|  | const GestureEventData& GetReceivedGesture(size_t index) const { | 
|  | EXPECT_LT(index, GetReceivedGestureCount()); | 
|  | return gestures_[index]; | 
|  | } | 
|  |  | 
|  | const GestureEventData* GetActiveScrollBeginEvent() const { | 
|  | return active_scroll_begin_event_ ? active_scroll_begin_event_.get() : NULL; | 
|  | } | 
|  |  | 
|  | const GestureProvider::Config& GetDefaultConfig() const { | 
|  | static GestureProvider::Config sConfig = CreateDefaultConfig(); | 
|  | return sConfig; | 
|  | } | 
|  |  | 
|  | float GetTouchSlop() const { | 
|  | return GetDefaultConfig().gesture_detector_config.touch_slop; | 
|  | } | 
|  |  | 
|  | float GetMinScalingSpan() const { | 
|  | return GetDefaultConfig().scale_gesture_detector_config.min_scaling_span; | 
|  | } | 
|  |  | 
|  | float GetMinSwipeVelocity() const { | 
|  | return GetDefaultConfig().gesture_detector_config.minimum_swipe_velocity; | 
|  | } | 
|  |  | 
|  | base::TimeDelta GetLongPressTimeout() const { | 
|  | return GetDefaultConfig().gesture_detector_config.longpress_timeout; | 
|  | } | 
|  |  | 
|  | base::TimeDelta GetShowPressTimeout() const { | 
|  | return GetDefaultConfig().gesture_detector_config.showpress_timeout; | 
|  | } | 
|  |  | 
|  | base::TimeDelta GetDoubleTapTimeout() const { | 
|  | return GetDefaultConfig().gesture_detector_config.double_tap_timeout; | 
|  | } | 
|  |  | 
|  | base::TimeDelta GetDoubleTapMinTime() const { | 
|  | return GetDefaultConfig().gesture_detector_config.double_tap_min_time; | 
|  | } | 
|  |  | 
|  | base::TimeDelta GetValidDoubleTapDelay() const { | 
|  | return (GetDoubleTapTimeout() + GetDoubleTapMinTime()) / 2; | 
|  | } | 
|  |  | 
|  | void EnableBeginEndTypes() { | 
|  | GestureProvider::Config config = GetDefaultConfig(); | 
|  | config.gesture_begin_end_types_enabled = true; | 
|  | SetUpWithConfig(config); | 
|  | } | 
|  |  | 
|  | void EnableSwipe() { | 
|  | GestureProvider::Config config = GetDefaultConfig(); | 
|  | config.gesture_detector_config.swipe_enabled = true; | 
|  | SetUpWithConfig(config); | 
|  | } | 
|  |  | 
|  | void EnableTwoFingerTap(float max_distance_for_two_finger_tap, | 
|  | base::TimeDelta two_finger_tap_timeout) { | 
|  | GestureProvider::Config config = GetDefaultConfig(); | 
|  | config.gesture_detector_config.two_finger_tap_enabled = true; | 
|  | config.gesture_detector_config.two_finger_tap_max_separation = | 
|  | max_distance_for_two_finger_tap; | 
|  | config.gesture_detector_config.two_finger_tap_timeout = | 
|  | two_finger_tap_timeout; | 
|  | SetUpWithConfig(config); | 
|  | } | 
|  |  | 
|  | void SetMinPinchUpdateSpanDelta(float min_pinch_update_span_delta) { | 
|  | GestureProvider::Config config = GetDefaultConfig(); | 
|  | config.scale_gesture_detector_config.min_pinch_update_span_delta = | 
|  | min_pinch_update_span_delta; | 
|  | SetUpWithConfig(config); | 
|  | } | 
|  |  | 
|  | void SetMinMaxGestureBoundsLength(float min_gesture_bound_length, | 
|  | float max_gesture_bound_length) { | 
|  | GestureProvider::Config config = GetDefaultConfig(); | 
|  | config.min_gesture_bounds_length = min_gesture_bound_length; | 
|  | config.max_gesture_bounds_length = max_gesture_bound_length; | 
|  | SetUpWithConfig(config); | 
|  | } | 
|  |  | 
|  | void SetShowPressAndLongPressTimeout(base::TimeDelta showpress_timeout, | 
|  | base::TimeDelta longpress_timeout) { | 
|  | GestureProvider::Config config = GetDefaultConfig(); | 
|  | config.gesture_detector_config.showpress_timeout = showpress_timeout; | 
|  | config.gesture_detector_config.longpress_timeout = longpress_timeout; | 
|  | SetUpWithConfig(config); | 
|  | } | 
|  |  | 
|  | bool HasDownEvent() const { return gesture_provider_->current_down_event(); } | 
|  |  | 
|  | protected: | 
|  | void CheckScrollEventSequenceForEndActionType( | 
|  | MotionEvent::Action end_action_type) { | 
|  | base::TimeTicks event_time = base::TimeTicks::Now(); | 
|  | const float scroll_to_x = kFakeCoordX + 100; | 
|  | const float scroll_to_y = kFakeCoordY + 100; | 
|  | int motion_event_id = 3; | 
|  | int motion_event_flags = EF_SHIFT_DOWN | EF_CAPS_LOCK_DOWN; | 
|  |  | 
|  | MockMotionEvent event = | 
|  | ObtainMotionEvent(event_time, MotionEvent::ACTION_DOWN); | 
|  | event.SetPrimaryPointerId(motion_event_id); | 
|  | event.set_flags(motion_event_flags); | 
|  |  | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  | EXPECT_EQ(motion_event_flags, GetMostRecentGestureEvent().flags); | 
|  |  | 
|  | event = ObtainMotionEvent(event_time + kOneSecond, | 
|  | MotionEvent::ACTION_MOVE, | 
|  | scroll_to_x, | 
|  | scroll_to_y); | 
|  | event.SetToolType(0, MotionEvent::TOOL_TYPE_FINGER); | 
|  | event.SetPrimaryPointerId(motion_event_id); | 
|  | event.set_flags(motion_event_flags); | 
|  |  | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  | EXPECT_TRUE(gesture_provider_->IsScrollInProgress()); | 
|  | EXPECT_TRUE(HasReceivedGesture(ET_GESTURE_SCROLL_BEGIN)); | 
|  | EXPECT_EQ(motion_event_id, GetMostRecentGestureEvent().motion_event_id); | 
|  | EXPECT_EQ(motion_event_flags, GetMostRecentGestureEvent().flags); | 
|  | EXPECT_EQ(event.GetToolType(0), | 
|  | GetMostRecentGestureEvent().primary_tool_type); | 
|  | EXPECT_EQ(ET_GESTURE_SCROLL_UPDATE, GetMostRecentGestureEventType()); | 
|  | EXPECT_EQ(BoundsForSingleMockTouchAtLocation(scroll_to_x, scroll_to_y), | 
|  | GetMostRecentGestureEvent().details.bounding_box()); | 
|  | ASSERT_EQ(3U, GetReceivedGestureCount()) << "Only TapDown, " | 
|  | "ScrollBegin and ScrollBy " | 
|  | "should have been sent"; | 
|  |  | 
|  | EXPECT_EQ(ET_GESTURE_SCROLL_BEGIN, GetReceivedGesture(1).type()); | 
|  | EXPECT_EQ(motion_event_id, GetReceivedGesture(1).motion_event_id); | 
|  | EXPECT_EQ(event_time + kOneSecond, GetReceivedGesture(1).time) | 
|  | << "ScrollBegin should have the time of the ACTION_MOVE"; | 
|  |  | 
|  | event = ObtainMotionEvent( | 
|  | event_time + kOneSecond, end_action_type, scroll_to_x, scroll_to_y); | 
|  | event.SetToolType(0, MotionEvent::TOOL_TYPE_FINGER); | 
|  | event.SetPrimaryPointerId(motion_event_id); | 
|  |  | 
|  | gesture_provider_->OnTouchEvent(event); | 
|  | EXPECT_FALSE(gesture_provider_->IsScrollInProgress()); | 
|  | EXPECT_TRUE(HasReceivedGesture(ET_GESTURE_SCROLL_END)); | 
|  | EXPECT_EQ(ET_GESTURE_SCROLL_END, GetMostRecentGestureEventType()); | 
|  | EXPECT_EQ(motion_event_id, GetMostRecentGestureEvent().motion_event_id); | 
|  | EXPECT_EQ(event.GetToolType(0), | 
|  | GetMostRecentGestureEvent().primary_tool_type); | 
|  | EXPECT_EQ(1, GetMostRecentGestureEvent().details.touch_points()); | 
|  | EXPECT_EQ(BoundsForSingleMockTouchAtLocation(scroll_to_x, scroll_to_y), | 
|  | GetMostRecentGestureEvent().details.bounding_box()); | 
|  | } | 
|  |  | 
|  | void OneFingerSwipe(float vx, float vy) { | 
|  | std::vector<gfx::Vector2dF> velocities; | 
|  | velocities.push_back(gfx::Vector2dF(vx, vy)); | 
|  | MultiFingerSwipe(velocities); | 
|  | } | 
|  |  | 
|  | void TwoFingerSwipe(float vx0, float vy0, float vx1, float vy1) { | 
|  | std::vector<gfx::Vector2dF> velocities; | 
|  | velocities.push_back(gfx::Vector2dF(vx0, vy0)); | 
|  | velocities.push_back(gfx::Vector2dF(vx1, vy1)); | 
|  | MultiFingerSwipe(velocities); | 
|  | } | 
|  |  | 
|  | void ThreeFingerSwipe(float vx0, | 
|  | float vy0, | 
|  | float vx1, | 
|  | float vy1, | 
|  | float vx2, | 
|  | float vy2) { | 
|  | std::vector<gfx::Vector2dF> velocities; | 
|  | velocities.push_back(gfx::Vector2dF(vx0, vy0)); | 
|  | velocities.push_back(gfx::Vector2dF(vx1, vy1)); | 
|  | velocities.push_back(gfx::Vector2dF(vx2, vy2)); | 
|  | MultiFingerSwipe(velocities); | 
|  | } | 
|  |  | 
|  | void MultiFingerSwipe(std::vector<gfx::Vector2dF> velocities) { | 
|  | ASSERT_GT(velocities.size(), 0U); | 
|  |  | 
|  | base::TimeTicks event_time = base::TimeTicks::Now(); | 
|  |  | 
|  | std::vector<gfx::PointF> positions(velocities.size()); | 
|  | for (size_t i = 0; i < positions.size(); ++i) | 
|  | positions[i] = gfx::PointF(kFakeCoordX * (i + 1), kFakeCoordY * (i + 1)); | 
|  |  | 
|  | float dt = kDeltaTimeForFlingSequences.InSecondsF(); | 
|  |  | 
|  | // Each pointer down should be a separate event. | 
|  | for (size_t i = 0; i < positions.size(); ++i) { | 
|  | const size_t pointer_count = i + 1; | 
|  | std::vector<gfx::PointF> event_positions(pointer_count); | 
|  | event_positions.assign(positions.begin(), | 
|  | positions.begin() + pointer_count); | 
|  | MockMotionEvent event = | 
|  | ObtainMotionEvent(event_time, | 
|  | pointer_count > 1 ? MotionEvent::ACTION_POINTER_DOWN | 
|  | : MotionEvent::ACTION_DOWN, | 
|  | event_positions); | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  | } | 
|  |  | 
|  | for (size_t i = 0; i < positions.size(); ++i) | 
|  | positions[i] += gfx::ScaleVector2d(velocities[i], dt); | 
|  | MockMotionEvent event = | 
|  | ObtainMotionEvent(event_time + kDeltaTimeForFlingSequences, | 
|  | MotionEvent::ACTION_MOVE, | 
|  | positions); | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  |  | 
|  | for (size_t i = 0; i < positions.size(); ++i) | 
|  | positions[i] += gfx::ScaleVector2d(velocities[i], dt); | 
|  | event = ObtainMotionEvent(event_time + 2 * kDeltaTimeForFlingSequences, | 
|  | MotionEvent::ACTION_MOVE, | 
|  | positions); | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  |  | 
|  | event = ObtainMotionEvent(event_time + 2 * kDeltaTimeForFlingSequences, | 
|  | MotionEvent::ACTION_POINTER_UP, | 
|  | positions); | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  | } | 
|  |  | 
|  | static void RunTasksAndWait(base::TimeDelta delay) { | 
|  | base::MessageLoop::current()->PostDelayedTask( | 
|  | FROM_HERE, base::MessageLoop::QuitClosure(), delay); | 
|  | base::MessageLoop::current()->Run(); | 
|  | } | 
|  |  | 
|  | std::vector<GestureEventData> gestures_; | 
|  | scoped_ptr<GestureProvider> gesture_provider_; | 
|  | scoped_ptr<GestureEventData> active_scroll_begin_event_; | 
|  | base::MessageLoopForUI message_loop_; | 
|  | }; | 
|  |  | 
|  | // Verify that a DOWN followed shortly by an UP will trigger a single tap. | 
|  | TEST_F(GestureProviderTest, GestureTap) { | 
|  | base::TimeTicks event_time = base::TimeTicks::Now(); | 
|  | int motion_event_id = 6; | 
|  | int motion_event_flags = EF_CONTROL_DOWN | EF_ALT_DOWN; | 
|  |  | 
|  | gesture_provider_->SetDoubleTapSupportForPlatformEnabled(false); | 
|  |  | 
|  | MockMotionEvent event = | 
|  | ObtainMotionEvent(event_time, MotionEvent::ACTION_DOWN); | 
|  | event.SetToolType(0, MotionEvent::TOOL_TYPE_FINGER); | 
|  | event.SetPrimaryPointerId(motion_event_id); | 
|  | event.set_flags(motion_event_flags); | 
|  |  | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  | EXPECT_EQ(ET_GESTURE_TAP_DOWN, GetMostRecentGestureEventType()); | 
|  | EXPECT_EQ(1, GetMostRecentGestureEvent().details.touch_points()); | 
|  | EXPECT_EQ(event.GetToolType(0), | 
|  | GetMostRecentGestureEvent().primary_tool_type); | 
|  | EXPECT_EQ(motion_event_flags, GetMostRecentGestureEvent().flags); | 
|  | EXPECT_EQ(BoundsForSingleMockTouchAtLocation(kFakeCoordX, kFakeCoordY), | 
|  | GetMostRecentGestureEvent().details.bounding_box()); | 
|  |  | 
|  | event = ObtainMotionEvent(event_time + kOneMicrosecond, | 
|  | MotionEvent::ACTION_UP); | 
|  | event.SetToolType(0, MotionEvent::TOOL_TYPE_FINGER); | 
|  | event.SetPrimaryPointerId(motion_event_id); | 
|  | event.set_flags(motion_event_flags); | 
|  |  | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  | EXPECT_EQ(ET_GESTURE_TAP, GetMostRecentGestureEventType()); | 
|  | // Ensure tap details have been set. | 
|  | EXPECT_EQ(1, GetMostRecentGestureEvent().details.tap_count()); | 
|  | EXPECT_EQ(event.GetToolType(0), | 
|  | GetMostRecentGestureEvent().primary_tool_type); | 
|  | EXPECT_EQ(motion_event_id, GetMostRecentGestureEvent().motion_event_id); | 
|  | EXPECT_EQ(motion_event_flags, GetMostRecentGestureEvent().flags); | 
|  | EXPECT_EQ(1, GetMostRecentGestureEvent().details.touch_points()); | 
|  | EXPECT_EQ(BoundsForSingleMockTouchAtLocation(kFakeCoordX, kFakeCoordY), | 
|  | GetMostRecentGestureEvent().details.bounding_box()); | 
|  | } | 
|  |  | 
|  | // Verify that a DOWN followed shortly by an UP will trigger | 
|  | // a ET_GESTURE_TAP_UNCONFIRMED event if double-tap is enabled. | 
|  | TEST_F(GestureProviderTest, GestureTapWithDelay) { | 
|  | base::TimeTicks event_time = base::TimeTicks::Now(); | 
|  | int motion_event_id = 6; | 
|  | int motion_event_flags = EF_CONTROL_DOWN | EF_ALT_DOWN | EF_CAPS_LOCK_DOWN; | 
|  |  | 
|  | gesture_provider_->SetDoubleTapSupportForPlatformEnabled(true); | 
|  |  | 
|  | MockMotionEvent event = | 
|  | ObtainMotionEvent(event_time, MotionEvent::ACTION_DOWN); | 
|  | event.SetPrimaryPointerId(motion_event_id); | 
|  | event.set_flags(motion_event_flags); | 
|  |  | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  | EXPECT_EQ(ET_GESTURE_TAP_DOWN, GetMostRecentGestureEventType()); | 
|  | EXPECT_EQ(motion_event_id, GetMostRecentGestureEvent().motion_event_id); | 
|  | EXPECT_EQ(motion_event_flags, GetMostRecentGestureEvent().flags); | 
|  | EXPECT_EQ(1, GetMostRecentGestureEvent().details.touch_points()); | 
|  | EXPECT_EQ(BoundsForSingleMockTouchAtLocation(kFakeCoordX, kFakeCoordY), | 
|  | GetMostRecentGestureEvent().details.bounding_box()); | 
|  |  | 
|  | event = ObtainMotionEvent(event_time + kOneMicrosecond, | 
|  | MotionEvent::ACTION_UP); | 
|  | event.SetPrimaryPointerId(motion_event_id); | 
|  | event.set_flags(motion_event_flags); | 
|  |  | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  | EXPECT_EQ(ET_GESTURE_TAP_UNCONFIRMED, GetMostRecentGestureEventType()); | 
|  | // Ensure tap details have been set. | 
|  | EXPECT_EQ(1, GetMostRecentGestureEvent().details.tap_count()); | 
|  | EXPECT_EQ(motion_event_id, GetMostRecentGestureEvent().motion_event_id); | 
|  | EXPECT_EQ(motion_event_flags, GetMostRecentGestureEvent().flags); | 
|  | EXPECT_EQ(1, GetMostRecentGestureEvent().details.touch_points()); | 
|  | EXPECT_EQ(BoundsForSingleMockTouchAtLocation(kFakeCoordX, kFakeCoordY), | 
|  | GetMostRecentGestureEvent().details.bounding_box()); | 
|  | EXPECT_EQ(event.GetEventTime(), GetMostRecentGestureEvent().time); | 
|  |  | 
|  | EXPECT_FALSE(HasReceivedGesture(ET_GESTURE_TAP)); | 
|  | RunTasksAndWait(GetDoubleTapTimeout()); | 
|  | EXPECT_TRUE(HasReceivedGesture(ET_GESTURE_TAP)); | 
|  | EXPECT_EQ(motion_event_id, GetMostRecentGestureEvent().motion_event_id); | 
|  | EXPECT_EQ(event.GetEventTime(), GetMostRecentGestureEvent().time); | 
|  | } | 
|  |  | 
|  | // Verify that a DOWN followed by a MOVE will trigger fling (but not LONG). | 
|  | TEST_F(GestureProviderTest, GestureFlingAndCancelLongPress) { | 
|  | base::TimeTicks event_time = TimeTicks::Now(); | 
|  | base::TimeDelta delta_time = kDeltaTimeForFlingSequences; | 
|  | int motion_event_id = 6; | 
|  | int motion_event_flags = EF_ALT_DOWN; | 
|  |  | 
|  | MockMotionEvent event = | 
|  | ObtainMotionEvent(event_time, MotionEvent::ACTION_DOWN); | 
|  | event.SetPrimaryPointerId(motion_event_id); | 
|  | event.set_flags(motion_event_flags); | 
|  |  | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  | EXPECT_EQ(ET_GESTURE_TAP_DOWN, GetMostRecentGestureEventType()); | 
|  | EXPECT_EQ(motion_event_id, GetMostRecentGestureEvent().motion_event_id); | 
|  | EXPECT_EQ(motion_event_flags, GetMostRecentGestureEvent().flags); | 
|  | EXPECT_EQ(1, GetMostRecentGestureEvent().details.touch_points()); | 
|  |  | 
|  | event = ObtainMotionEvent(event_time + delta_time, | 
|  | MotionEvent::ACTION_MOVE, | 
|  | kFakeCoordX * 10, | 
|  | kFakeCoordY * 10); | 
|  | event.SetPrimaryPointerId(motion_event_id); | 
|  | event.set_flags(motion_event_flags); | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  |  | 
|  | event = ObtainMotionEvent(event_time + delta_time * 2, | 
|  | MotionEvent::ACTION_UP, | 
|  | kFakeCoordX * 10, | 
|  | kFakeCoordY * 10); | 
|  | event.SetPrimaryPointerId(motion_event_id); | 
|  | event.set_flags(motion_event_flags); | 
|  |  | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  | EXPECT_EQ(ET_SCROLL_FLING_START, GetMostRecentGestureEventType()); | 
|  | EXPECT_EQ(motion_event_id, GetMostRecentGestureEvent().motion_event_id); | 
|  | EXPECT_EQ(motion_event_flags, GetMostRecentGestureEvent().flags); | 
|  | EXPECT_EQ(1, GetMostRecentGestureEvent().details.touch_points()); | 
|  | EXPECT_FALSE(HasReceivedGesture(ET_GESTURE_LONG_PRESS)); | 
|  | EXPECT_EQ( | 
|  | BoundsForSingleMockTouchAtLocation(kFakeCoordX * 10, kFakeCoordY * 10), | 
|  | GetMostRecentGestureEvent().details.bounding_box()); | 
|  | } | 
|  |  | 
|  | // Verify that for a normal scroll the following events are sent: | 
|  | // - ET_GESTURE_SCROLL_BEGIN | 
|  | // - ET_GESTURE_SCROLL_UPDATE | 
|  | // - ET_GESTURE_SCROLL_END | 
|  | TEST_F(GestureProviderTest, ScrollEventActionUpSequence) { | 
|  | CheckScrollEventSequenceForEndActionType(MotionEvent::ACTION_UP); | 
|  | } | 
|  |  | 
|  | // Verify that for a cancelled scroll the following events are sent: | 
|  | // - ET_GESTURE_SCROLL_BEGIN | 
|  | // - ET_GESTURE_SCROLL_UPDATE | 
|  | // - ET_GESTURE_SCROLL_END | 
|  | TEST_F(GestureProviderTest, ScrollEventActionCancelSequence) { | 
|  | CheckScrollEventSequenceForEndActionType(MotionEvent::ACTION_CANCEL); | 
|  | } | 
|  |  | 
|  | // Verify that for a normal fling (fling after scroll) the following events are | 
|  | // sent: | 
|  | // - ET_GESTURE_SCROLL_BEGIN | 
|  | // - ET_SCROLL_FLING_START | 
|  | TEST_F(GestureProviderTest, FlingEventSequence) { | 
|  | base::TimeTicks event_time = base::TimeTicks::Now(); | 
|  | base::TimeDelta delta_time = kDeltaTimeForFlingSequences; | 
|  | int motion_event_id = 6; | 
|  |  | 
|  | MockMotionEvent event = | 
|  | ObtainMotionEvent(event_time, MotionEvent::ACTION_DOWN); | 
|  | event.SetPrimaryPointerId(motion_event_id); | 
|  |  | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  |  | 
|  | event = ObtainMotionEvent(event_time + delta_time, | 
|  | MotionEvent::ACTION_MOVE, | 
|  | kFakeCoordX * 5, | 
|  | kFakeCoordY * 5); | 
|  | event.SetPrimaryPointerId(motion_event_id); | 
|  |  | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  | EXPECT_TRUE(gesture_provider_->IsScrollInProgress()); | 
|  | EXPECT_TRUE(HasReceivedGesture(ET_GESTURE_SCROLL_BEGIN)); | 
|  | EXPECT_EQ(ET_GESTURE_SCROLL_UPDATE, GetMostRecentGestureEventType()); | 
|  | EXPECT_EQ(motion_event_id, GetMostRecentGestureEvent().motion_event_id); | 
|  | ASSERT_EQ(3U, GetReceivedGestureCount()); | 
|  | ASSERT_EQ(ET_GESTURE_SCROLL_BEGIN, GetReceivedGesture(1).type()); | 
|  | EXPECT_EQ(motion_event_id, GetReceivedGesture(1).motion_event_id); | 
|  |  | 
|  | // We don't want to take a dependency here on exactly how hints are calculated | 
|  | // for a fling (eg. may depend on velocity), so just validate the direction. | 
|  | int hint_x = GetReceivedGesture(1).details.scroll_x_hint(); | 
|  | int hint_y = GetReceivedGesture(1).details.scroll_y_hint(); | 
|  | EXPECT_TRUE(hint_x > 0 && hint_y > 0 && hint_x > hint_y) | 
|  | << "ScrollBegin hint should be in positive X axis"; | 
|  |  | 
|  | event = ObtainMotionEvent(event_time + delta_time * 2, | 
|  | MotionEvent::ACTION_UP, | 
|  | kFakeCoordX * 10, | 
|  | kFakeCoordY * 10); | 
|  | event.SetPrimaryPointerId(motion_event_id); | 
|  |  | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  | EXPECT_FALSE(gesture_provider_->IsScrollInProgress()); | 
|  | EXPECT_EQ(ET_SCROLL_FLING_START, GetMostRecentGestureEventType()); | 
|  | EXPECT_EQ(motion_event_id, GetMostRecentGestureEvent().motion_event_id); | 
|  | EXPECT_EQ(1, GetMostRecentGestureEvent().details.touch_points()); | 
|  | EXPECT_FALSE(HasReceivedGesture(ET_GESTURE_SCROLL_END)); | 
|  | EXPECT_EQ(event_time + delta_time * 2, GetMostRecentGestureEvent().time) | 
|  | << "FlingStart should have the time of the ACTION_UP"; | 
|  | } | 
|  |  | 
|  | TEST_F(GestureProviderTest, GestureCancelledOnCancelEvent) { | 
|  | const base::TimeTicks event_time = TimeTicks::Now(); | 
|  |  | 
|  | MockMotionEvent event = | 
|  | ObtainMotionEvent(event_time, MotionEvent::ACTION_DOWN); | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  | EXPECT_EQ(ET_GESTURE_TAP_DOWN, GetMostRecentGestureEventType()); | 
|  |  | 
|  | RunTasksAndWait(GetLongPressTimeout() + GetShowPressTimeout() + | 
|  | kOneMicrosecond); | 
|  | EXPECT_TRUE(HasReceivedGesture(ET_GESTURE_SHOW_PRESS)); | 
|  | EXPECT_EQ(ET_GESTURE_LONG_PRESS, GetMostRecentGestureEventType()); | 
|  |  | 
|  | // A cancellation event may be triggered for a number of reasons, e.g., | 
|  | // from a context-menu-triggering long press resulting in loss of focus. | 
|  | EXPECT_TRUE(CancelActiveTouchSequence()); | 
|  | EXPECT_FALSE(HasDownEvent()); | 
|  |  | 
|  | // A final ACTION_UP should have no effect. | 
|  | event = ObtainMotionEvent(event_time + kOneMicrosecond * 2, | 
|  | MotionEvent::ACTION_UP); | 
|  | EXPECT_FALSE(gesture_provider_->OnTouchEvent(event)); | 
|  | } | 
|  |  | 
|  | TEST_F(GestureProviderTest, GestureCancelledOnDetectionReset) { | 
|  | const base::TimeTicks event_time = TimeTicks::Now(); | 
|  |  | 
|  | MockMotionEvent event = | 
|  | ObtainMotionEvent(event_time, MotionEvent::ACTION_DOWN); | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  | EXPECT_EQ(ET_GESTURE_TAP_DOWN, GetMostRecentGestureEventType()); | 
|  |  | 
|  | RunTasksAndWait(GetLongPressTimeout() + GetShowPressTimeout() + | 
|  | kOneMicrosecond); | 
|  | EXPECT_TRUE(HasReceivedGesture(ET_GESTURE_SHOW_PRESS)); | 
|  | EXPECT_EQ(ET_GESTURE_LONG_PRESS, GetMostRecentGestureEventType()); | 
|  |  | 
|  | ResetGestureDetection(); | 
|  | EXPECT_FALSE(HasDownEvent()); | 
|  |  | 
|  | // A final ACTION_UP should have no effect. | 
|  | event = ObtainMotionEvent(event_time + kOneMicrosecond * 2, | 
|  | MotionEvent::ACTION_UP); | 
|  | EXPECT_FALSE(gesture_provider_->OnTouchEvent(event)); | 
|  | } | 
|  |  | 
|  | TEST_F(GestureProviderTest, NoTapAfterScrollBegins) { | 
|  | base::TimeTicks event_time = base::TimeTicks::Now(); | 
|  |  | 
|  | MockMotionEvent event = | 
|  | ObtainMotionEvent(event_time, MotionEvent::ACTION_DOWN); | 
|  |  | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  |  | 
|  | EXPECT_EQ(ET_GESTURE_TAP_DOWN, GetMostRecentGestureEventType()); | 
|  | EXPECT_EQ(1, GetMostRecentGestureEvent().details.touch_points()); | 
|  | event = ObtainMotionEvent(event_time + kOneMicrosecond, | 
|  | MotionEvent::ACTION_MOVE, | 
|  | kFakeCoordX + 50, | 
|  | kFakeCoordY + 50); | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  | EXPECT_EQ(ET_GESTURE_SCROLL_UPDATE, GetMostRecentGestureEventType()); | 
|  |  | 
|  | event = ObtainMotionEvent(event_time + kOneSecond, | 
|  | MotionEvent::ACTION_UP, | 
|  | kFakeCoordX + 50, | 
|  | kFakeCoordY + 50); | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  | EXPECT_EQ(ET_GESTURE_SCROLL_END, GetMostRecentGestureEventType()); | 
|  | EXPECT_FALSE(HasReceivedGesture(ET_GESTURE_LONG_TAP)); | 
|  | } | 
|  |  | 
|  | TEST_F(GestureProviderTest, DoubleTap) { | 
|  | base::TimeTicks event_time = base::TimeTicks::Now(); | 
|  |  | 
|  | MockMotionEvent event = | 
|  | ObtainMotionEvent(event_time, MotionEvent::ACTION_DOWN); | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  |  | 
|  | EXPECT_EQ(ET_GESTURE_TAP_DOWN, GetMostRecentGestureEventType()); | 
|  | EXPECT_EQ(1, GetMostRecentGestureEvent().details.touch_points()); | 
|  |  | 
|  | event = ObtainMotionEvent(event_time + kOneMicrosecond, | 
|  | MotionEvent::ACTION_UP, | 
|  | kFakeCoordX, | 
|  | kFakeCoordY); | 
|  | gesture_provider_->OnTouchEvent(event); | 
|  | EXPECT_EQ(ET_GESTURE_TAP_UNCONFIRMED, GetMostRecentGestureEventType()); | 
|  | EXPECT_EQ(1, GetMostRecentGestureEvent().details.touch_points()); | 
|  |  | 
|  | event_time += GetValidDoubleTapDelay(); | 
|  | event = ObtainMotionEvent(event_time, | 
|  | MotionEvent::ACTION_DOWN, | 
|  | kFakeCoordX, | 
|  | kFakeCoordY); | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  | EXPECT_EQ(ET_GESTURE_TAP_DOWN, GetMostRecentGestureEventType()); | 
|  | EXPECT_EQ(1, GetMostRecentGestureEvent().details.touch_points()); | 
|  |  | 
|  | // Moving a very small amount of distance should not trigger the double tap | 
|  | // drag zoom mode. | 
|  | event = ObtainMotionEvent(event_time + kOneMicrosecond, | 
|  | MotionEvent::ACTION_MOVE, | 
|  | kFakeCoordX, | 
|  | kFakeCoordY + 1); | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  | EXPECT_EQ(ET_GESTURE_TAP_DOWN, GetMostRecentGestureEventType()); | 
|  | EXPECT_EQ(1, GetMostRecentGestureEvent().details.touch_points()); | 
|  |  | 
|  | event = ObtainMotionEvent(event_time + kOneMicrosecond * 2, | 
|  | MotionEvent::ACTION_UP, | 
|  | kFakeCoordX, | 
|  | kFakeCoordY + 1); | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  |  | 
|  | const GestureEventData& double_tap = GetMostRecentGestureEvent(); | 
|  | EXPECT_EQ(ET_GESTURE_DOUBLE_TAP, double_tap.type()); | 
|  | // Ensure tap details have been set. | 
|  | EXPECT_EQ(10, double_tap.details.bounding_box().width()); | 
|  | EXPECT_EQ(10, double_tap.details.bounding_box().height()); | 
|  | EXPECT_EQ(1, double_tap.details.tap_count()); | 
|  | } | 
|  |  | 
|  | TEST_F(GestureProviderTest, DoubleTapDragZoomBasic) { | 
|  | const base::TimeTicks down_time_1 = TimeTicks::Now(); | 
|  | const base::TimeTicks down_time_2 = down_time_1 + GetValidDoubleTapDelay(); | 
|  |  | 
|  | MockMotionEvent event = | 
|  | ObtainMotionEvent(down_time_1, MotionEvent::ACTION_DOWN); | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  |  | 
|  | event = ObtainMotionEvent(down_time_1 + kOneMicrosecond, | 
|  | MotionEvent::ACTION_UP, | 
|  | kFakeCoordX, | 
|  | kFakeCoordY); | 
|  | gesture_provider_->OnTouchEvent(event); | 
|  | EXPECT_EQ(ET_GESTURE_TAP_UNCONFIRMED, GetMostRecentGestureEventType()); | 
|  | EXPECT_EQ(1, GetMostRecentGestureEvent().details.touch_points()); | 
|  |  | 
|  | event = ObtainMotionEvent( | 
|  | down_time_2, MotionEvent::ACTION_DOWN, kFakeCoordX, kFakeCoordY); | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  | EXPECT_EQ(ET_GESTURE_TAP_DOWN, GetMostRecentGestureEventType()); | 
|  | EXPECT_EQ(1, GetMostRecentGestureEvent().details.touch_points()); | 
|  |  | 
|  | event = ObtainMotionEvent(down_time_2 + kOneMicrosecond, | 
|  | MotionEvent::ACTION_MOVE, | 
|  | kFakeCoordX, | 
|  | kFakeCoordY + 100); | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  | EXPECT_TRUE(HasReceivedGesture(ET_GESTURE_SCROLL_BEGIN)); | 
|  | ASSERT_EQ(ET_GESTURE_PINCH_BEGIN, GetMostRecentGestureEventType()); | 
|  | EXPECT_EQ(BoundsForSingleMockTouchAtLocation(kFakeCoordX, kFakeCoordY + 100), | 
|  | GetMostRecentGestureEvent().details.bounding_box()); | 
|  |  | 
|  | event = ObtainMotionEvent(down_time_2 + kOneMicrosecond * 2, | 
|  | MotionEvent::ACTION_MOVE, | 
|  | kFakeCoordX, | 
|  | kFakeCoordY + 200); | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  | ASSERT_EQ(ET_GESTURE_PINCH_UPDATE, GetMostRecentGestureEventType()); | 
|  | EXPECT_LT(1.f, GetMostRecentGestureEvent().details.scale()); | 
|  | EXPECT_EQ(BoundsForSingleMockTouchAtLocation(kFakeCoordX, kFakeCoordY + 200), | 
|  | GetMostRecentGestureEvent().details.bounding_box()); | 
|  |  | 
|  | event = ObtainMotionEvent(down_time_2 + kOneMicrosecond * 3, | 
|  | MotionEvent::ACTION_MOVE, | 
|  | kFakeCoordX, | 
|  | kFakeCoordY + 100); | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  | ASSERT_EQ(ET_GESTURE_PINCH_UPDATE, GetMostRecentGestureEventType()); | 
|  | EXPECT_GT(1.f, GetMostRecentGestureEvent().details.scale()); | 
|  | EXPECT_EQ(BoundsForSingleMockTouchAtLocation(kFakeCoordX, kFakeCoordY + 100), | 
|  | GetMostRecentGestureEvent().details.bounding_box()); | 
|  |  | 
|  | event = ObtainMotionEvent(down_time_2 + kOneMicrosecond * 4, | 
|  | MotionEvent::ACTION_UP, | 
|  | kFakeCoordX, | 
|  | kFakeCoordY - 200); | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  | EXPECT_TRUE(HasReceivedGesture(ET_GESTURE_PINCH_END)); | 
|  | EXPECT_EQ(ET_GESTURE_SCROLL_END, GetMostRecentGestureEventType()); | 
|  | EXPECT_EQ(BoundsForSingleMockTouchAtLocation(kFakeCoordX, kFakeCoordY - 200), | 
|  | GetMostRecentGestureEvent().details.bounding_box()); | 
|  | } | 
|  |  | 
|  | // Generate a scroll gesture and verify that the resulting scroll motion event | 
|  | // has both absolute and relative position information. | 
|  | TEST_F(GestureProviderTest, ScrollUpdateValues) { | 
|  | const float delta_x = 16; | 
|  | const float delta_y = 84; | 
|  | const float raw_offset_x = 17.3f; | 
|  | const float raw_offset_y = 13.7f; | 
|  |  | 
|  | const base::TimeTicks event_time = TimeTicks::Now(); | 
|  |  | 
|  | MockMotionEvent event = | 
|  | ObtainMotionEvent(event_time, MotionEvent::ACTION_DOWN); | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  |  | 
|  | // Move twice so that we get two ET_GESTURE_SCROLL_UPDATE events and can | 
|  | // compare the relative and absolute coordinates. | 
|  | event = ObtainMotionEvent(event_time + kOneMicrosecond, | 
|  | MotionEvent::ACTION_MOVE, | 
|  | kFakeCoordX - delta_x / 2, | 
|  | kFakeCoordY - delta_y / 2); | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  |  | 
|  | event = ObtainMotionEvent(event_time + kOneMicrosecond * 2, | 
|  | MotionEvent::ACTION_MOVE, | 
|  | kFakeCoordX - delta_x, | 
|  | kFakeCoordY - delta_y); | 
|  | event.SetRawOffset(raw_offset_x, raw_offset_y); | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  |  | 
|  | // Make sure the reported gesture event has all the expected details. | 
|  | ASSERT_LT(0U, GetReceivedGestureCount()); | 
|  | GestureEventData gesture = GetMostRecentGestureEvent(); | 
|  | EXPECT_EQ(ET_GESTURE_SCROLL_UPDATE, gesture.type()); | 
|  | EXPECT_EQ(event_time + kOneMicrosecond * 2, gesture.time); | 
|  | EXPECT_EQ(kFakeCoordX - delta_x, gesture.x); | 
|  | EXPECT_EQ(kFakeCoordY - delta_y, gesture.y); | 
|  | EXPECT_EQ(kFakeCoordX - delta_x + raw_offset_x, gesture.raw_x); | 
|  | EXPECT_EQ(kFakeCoordY - delta_y + raw_offset_y, gesture.raw_y); | 
|  | EXPECT_EQ(1, gesture.details.touch_points()); | 
|  |  | 
|  | // No horizontal delta because of snapping. | 
|  | EXPECT_EQ(0, gesture.details.scroll_x()); | 
|  | EXPECT_EQ(-delta_y / 2, gesture.details.scroll_y()); | 
|  | } | 
|  |  | 
|  | // Verify that fractional scroll deltas are rounded as expected and that | 
|  | // fractional scrolling doesn't break scroll snapping. | 
|  | TEST_F(GestureProviderTest, FractionalScroll) { | 
|  | const float delta_x = 0.4f; | 
|  | const float delta_y = 5.2f; | 
|  |  | 
|  | const base::TimeTicks event_time = TimeTicks::Now(); | 
|  |  | 
|  | MockMotionEvent event = | 
|  | ObtainMotionEvent(event_time, MotionEvent::ACTION_DOWN); | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  |  | 
|  | // Skip past the touch slop and move back. | 
|  | event = ObtainMotionEvent(event_time, | 
|  | MotionEvent::ACTION_MOVE, | 
|  | kFakeCoordX, | 
|  | kFakeCoordY + 100); | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  | event = ObtainMotionEvent(event_time, | 
|  | MotionEvent::ACTION_MOVE); | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  |  | 
|  | // Now move up slowly, mostly vertically but with a (fractional) bit of | 
|  | // horizontal motion. | 
|  | for (int i = 1; i <= 10; i++) { | 
|  | event = ObtainMotionEvent(event_time + kOneMicrosecond * i, | 
|  | MotionEvent::ACTION_MOVE, | 
|  | kFakeCoordX + delta_x * i, | 
|  | kFakeCoordY + delta_y * i); | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  |  | 
|  | ASSERT_LT(0U, GetReceivedGestureCount()); | 
|  | GestureEventData gesture = GetMostRecentGestureEvent(); | 
|  | EXPECT_EQ(ET_GESTURE_SCROLL_UPDATE, gesture.type()); | 
|  | EXPECT_EQ(event_time + kOneMicrosecond * i, gesture.time); | 
|  | EXPECT_EQ(1, gesture.details.touch_points()); | 
|  |  | 
|  | // Verify that the event co-ordinates are still the precise values we | 
|  | // supplied. | 
|  | EXPECT_EQ(kFakeCoordX + delta_x * i, gesture.x); | 
|  | EXPECT_FLOAT_EQ(kFakeCoordY + delta_y * i, gesture.y); | 
|  |  | 
|  | // Verify that we're scrolling vertically by the expected amount | 
|  | // (modulo rounding). | 
|  | EXPECT_GE(gesture.details.scroll_y(), (int)delta_y); | 
|  | EXPECT_LE(gesture.details.scroll_y(), ((int)delta_y) + 1); | 
|  |  | 
|  | // And that there has been no horizontal motion at all. | 
|  | EXPECT_EQ(0, gesture.details.scroll_x()); | 
|  | } | 
|  | } | 
|  |  | 
|  | // Generate a scroll gesture and verify that the resulting scroll begin event | 
|  | // has the expected hint values. | 
|  | TEST_F(GestureProviderTest, ScrollBeginValues) { | 
|  | const float delta_x = 13; | 
|  | const float delta_y = 89; | 
|  |  | 
|  | const base::TimeTicks event_time = TimeTicks::Now(); | 
|  |  | 
|  | MockMotionEvent event = | 
|  | ObtainMotionEvent(event_time, MotionEvent::ACTION_DOWN); | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  |  | 
|  | // Move twice such that the first event isn't sufficient to start | 
|  | // scrolling on it's own. | 
|  | event = ObtainMotionEvent(event_time + kOneMicrosecond, | 
|  | MotionEvent::ACTION_MOVE, | 
|  | kFakeCoordX + 2, | 
|  | kFakeCoordY + 1); | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  | EXPECT_FALSE(gesture_provider_->IsScrollInProgress()); | 
|  |  | 
|  | event = ObtainMotionEvent(event_time + kOneMicrosecond * 2, | 
|  | MotionEvent::ACTION_MOVE, | 
|  | kFakeCoordX + delta_x, | 
|  | kFakeCoordY + delta_y); | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  | EXPECT_TRUE(gesture_provider_->IsScrollInProgress()); | 
|  |  | 
|  | const GestureEventData* scroll_begin_gesture = GetActiveScrollBeginEvent(); | 
|  | ASSERT_TRUE(scroll_begin_gesture); | 
|  | EXPECT_EQ(delta_x, scroll_begin_gesture->details.scroll_x_hint()); | 
|  | EXPECT_EQ(delta_y, scroll_begin_gesture->details.scroll_y_hint()); | 
|  | } | 
|  |  | 
|  | TEST_F(GestureProviderTest, LongPressAndTapCancelledWhenScrollBegins) { | 
|  | base::TimeTicks event_time = base::TimeTicks::Now(); | 
|  |  | 
|  | MockMotionEvent event = | 
|  | ObtainMotionEvent(event_time, MotionEvent::ACTION_DOWN); | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  | event = ObtainMotionEvent(event_time + kOneMicrosecond, | 
|  | MotionEvent::ACTION_MOVE, | 
|  | kFakeCoordX * 5, | 
|  | kFakeCoordY * 5); | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  | event = ObtainMotionEvent(event_time + kOneMicrosecond * 2, | 
|  | MotionEvent::ACTION_MOVE, | 
|  | kFakeCoordX * 10, | 
|  | kFakeCoordY * 10); | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  |  | 
|  | const base::TimeDelta long_press_timeout = | 
|  | GetLongPressTimeout() + GetShowPressTimeout() + kOneMicrosecond; | 
|  | RunTasksAndWait(long_press_timeout); | 
|  |  | 
|  | // No LONG_TAP as the LONG_PRESS timer is cancelled. | 
|  | EXPECT_FALSE(HasReceivedGesture(ET_GESTURE_LONG_PRESS)); | 
|  | EXPECT_FALSE(HasReceivedGesture(ET_GESTURE_LONG_TAP)); | 
|  | } | 
|  |  | 
|  | // Verify that LONG_TAP is triggered after LONG_PRESS followed by an UP. | 
|  | TEST_F(GestureProviderTest, GestureLongTap) { | 
|  | base::TimeTicks event_time = base::TimeTicks::Now(); | 
|  |  | 
|  | MockMotionEvent event = | 
|  | ObtainMotionEvent(event_time, MotionEvent::ACTION_DOWN); | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  |  | 
|  | const base::TimeDelta long_press_timeout = | 
|  | GetLongPressTimeout() + GetShowPressTimeout() + kOneMicrosecond; | 
|  | RunTasksAndWait(long_press_timeout); | 
|  |  | 
|  | EXPECT_EQ(ET_GESTURE_LONG_PRESS, GetMostRecentGestureEventType()); | 
|  | EXPECT_EQ(1, GetMostRecentGestureEvent().details.touch_points()); | 
|  | EXPECT_EQ(BoundsForSingleMockTouchAtLocation(kFakeCoordX, kFakeCoordY), | 
|  | GetMostRecentGestureEvent().details.bounding_box()); | 
|  |  | 
|  | event = ObtainMotionEvent(event_time + kOneSecond, MotionEvent::ACTION_UP); | 
|  | gesture_provider_->OnTouchEvent(event); | 
|  | EXPECT_EQ(ET_GESTURE_LONG_TAP, GetMostRecentGestureEventType()); | 
|  | EXPECT_EQ(1, GetMostRecentGestureEvent().details.touch_points()); | 
|  | EXPECT_EQ(BoundsForSingleMockTouchAtLocation(kFakeCoordX, kFakeCoordY), | 
|  | GetMostRecentGestureEvent().details.bounding_box()); | 
|  | } | 
|  |  | 
|  | TEST_F(GestureProviderTest, GestureLongPressDoesNotPreventScrolling) { | 
|  | base::TimeTicks event_time = base::TimeTicks::Now(); | 
|  |  | 
|  | MockMotionEvent event = | 
|  | ObtainMotionEvent(event_time, MotionEvent::ACTION_DOWN); | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  |  | 
|  | const base::TimeDelta long_press_timeout = | 
|  | GetLongPressTimeout() + GetShowPressTimeout() + kOneMicrosecond; | 
|  | RunTasksAndWait(long_press_timeout); | 
|  |  | 
|  | EXPECT_EQ(ET_GESTURE_LONG_PRESS, GetMostRecentGestureEventType()); | 
|  | EXPECT_EQ(1, GetMostRecentGestureEvent().details.touch_points()); | 
|  | event = ObtainMotionEvent(event_time + long_press_timeout, | 
|  | MotionEvent::ACTION_MOVE, | 
|  | kFakeCoordX + 100, | 
|  | kFakeCoordY + 100); | 
|  | gesture_provider_->OnTouchEvent(event); | 
|  |  | 
|  | EXPECT_EQ(ET_GESTURE_SCROLL_UPDATE, GetMostRecentGestureEventType()); | 
|  | EXPECT_EQ(1, GetMostRecentGestureEvent().details.touch_points()); | 
|  | EXPECT_TRUE(HasReceivedGesture(ET_GESTURE_SCROLL_BEGIN)); | 
|  |  | 
|  | event = ObtainMotionEvent(event_time + long_press_timeout, | 
|  | MotionEvent::ACTION_UP); | 
|  | gesture_provider_->OnTouchEvent(event); | 
|  | EXPECT_FALSE(HasReceivedGesture(ET_GESTURE_LONG_TAP)); | 
|  | } | 
|  |  | 
|  | TEST_F(GestureProviderTest, NoGestureLongPressDuringDoubleTap) { | 
|  | base::TimeTicks event_time = base::TimeTicks::Now(); | 
|  | int motion_event_id = 6; | 
|  |  | 
|  | MockMotionEvent event = ObtainMotionEvent( | 
|  | event_time, MotionEvent::ACTION_DOWN, kFakeCoordX, kFakeCoordY); | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  |  | 
|  | event = ObtainMotionEvent(event_time + kOneMicrosecond, | 
|  | MotionEvent::ACTION_UP, | 
|  | kFakeCoordX, | 
|  | kFakeCoordY); | 
|  | gesture_provider_->OnTouchEvent(event); | 
|  | EXPECT_EQ(ET_GESTURE_TAP_UNCONFIRMED, GetMostRecentGestureEventType()); | 
|  | EXPECT_EQ(1, GetMostRecentGestureEvent().details.touch_points()); | 
|  |  | 
|  | event_time += GetValidDoubleTapDelay(); | 
|  | event = ObtainMotionEvent(event_time, | 
|  | MotionEvent::ACTION_DOWN, | 
|  | kFakeCoordX, | 
|  | kFakeCoordY); | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  | EXPECT_EQ(ET_GESTURE_TAP_DOWN, GetMostRecentGestureEventType()); | 
|  | EXPECT_EQ(1, GetMostRecentGestureEvent().details.touch_points()); | 
|  | EXPECT_TRUE(gesture_provider_->IsDoubleTapInProgress()); | 
|  |  | 
|  | const base::TimeDelta long_press_timeout = | 
|  | GetLongPressTimeout() + GetShowPressTimeout() + kOneMicrosecond; | 
|  | RunTasksAndWait(long_press_timeout); | 
|  | EXPECT_FALSE(HasReceivedGesture(ET_GESTURE_LONG_PRESS)); | 
|  |  | 
|  | event = ObtainMotionEvent(event_time + long_press_timeout, | 
|  | MotionEvent::ACTION_MOVE, | 
|  | kFakeCoordX + 20, | 
|  | kFakeCoordY + 20); | 
|  | event.SetPrimaryPointerId(motion_event_id); | 
|  |  | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  | EXPECT_EQ(ET_GESTURE_PINCH_BEGIN, GetMostRecentGestureEventType()); | 
|  | EXPECT_EQ(motion_event_id, GetMostRecentGestureEvent().motion_event_id); | 
|  | EXPECT_EQ(1, GetMostRecentGestureEvent().details.touch_points()); | 
|  | EXPECT_TRUE(gesture_provider_->IsDoubleTapInProgress()); | 
|  |  | 
|  | event = ObtainMotionEvent(event_time + long_press_timeout + kOneMicrosecond, | 
|  | MotionEvent::ACTION_UP, | 
|  | kFakeCoordX, | 
|  | kFakeCoordY + 1); | 
|  | event.SetPrimaryPointerId(motion_event_id); | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  | EXPECT_EQ(ET_GESTURE_SCROLL_END, GetMostRecentGestureEventType()); | 
|  | EXPECT_EQ(motion_event_id, GetMostRecentGestureEvent().motion_event_id); | 
|  | EXPECT_EQ(1, GetMostRecentGestureEvent().details.touch_points()); | 
|  | EXPECT_FALSE(gesture_provider_->IsDoubleTapInProgress()); | 
|  | } | 
|  |  | 
|  | // Verify that the touch slop region is removed from the first scroll delta to | 
|  | // avoid a jump when starting to scroll. | 
|  | TEST_F(GestureProviderTest, TouchSlopRemovedFromScroll) { | 
|  | const float touch_slop = GetTouchSlop(); | 
|  | const float scroll_delta = 5; | 
|  |  | 
|  | base::TimeTicks event_time = base::TimeTicks::Now(); | 
|  |  | 
|  | MockMotionEvent event = | 
|  | ObtainMotionEvent(event_time, MotionEvent::ACTION_DOWN); | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  |  | 
|  | event = ObtainMotionEvent(event_time + kOneMicrosecond * 2, | 
|  | MotionEvent::ACTION_MOVE, | 
|  | kFakeCoordX, | 
|  | kFakeCoordY + touch_slop + scroll_delta); | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  |  | 
|  | EXPECT_EQ(ET_GESTURE_SCROLL_UPDATE, GetMostRecentGestureEventType()); | 
|  | GestureEventData gesture = GetMostRecentGestureEvent(); | 
|  | EXPECT_EQ(0, gesture.details.scroll_x()); | 
|  | EXPECT_EQ(scroll_delta, gesture.details.scroll_y()); | 
|  | EXPECT_EQ(1, gesture.details.touch_points()); | 
|  | } | 
|  |  | 
|  | // Verify that movement within the touch slop region does not generate a scroll, | 
|  | // and that the slop region is correct even when using fractional coordinates. | 
|  | TEST_F(GestureProviderTest, NoScrollWithinTouchSlop) { | 
|  | const float touch_slop = GetTouchSlop(); | 
|  | const float scale_factor = 2.5f; | 
|  | const int touch_slop_pixels = static_cast<int>(scale_factor * touch_slop); | 
|  |  | 
|  | base::TimeTicks event_time = base::TimeTicks::Now(); | 
|  |  | 
|  | MockMotionEvent event = | 
|  | ObtainMotionEvent(event_time, MotionEvent::ACTION_DOWN); | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  |  | 
|  | event = ObtainMotionEvent(event_time + kOneMicrosecond * 2, | 
|  | MotionEvent::ACTION_MOVE, | 
|  | kFakeCoordX + touch_slop_pixels / scale_factor, | 
|  | kFakeCoordY); | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  | EXPECT_FALSE(HasReceivedGesture(ET_GESTURE_SCROLL_BEGIN)); | 
|  |  | 
|  | event = ObtainMotionEvent(event_time + kOneMicrosecond * 2, | 
|  | MotionEvent::ACTION_MOVE, | 
|  | kFakeCoordX, | 
|  | kFakeCoordY + touch_slop_pixels / scale_factor); | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  | EXPECT_FALSE(HasReceivedGesture(ET_GESTURE_SCROLL_BEGIN)); | 
|  |  | 
|  | event = ObtainMotionEvent(event_time + kOneMicrosecond * 2, | 
|  | MotionEvent::ACTION_MOVE, | 
|  | kFakeCoordX - touch_slop_pixels / scale_factor, | 
|  | kFakeCoordY); | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  | EXPECT_FALSE(HasReceivedGesture(ET_GESTURE_SCROLL_BEGIN)); | 
|  |  | 
|  | event = ObtainMotionEvent(event_time + kOneMicrosecond * 2, | 
|  | MotionEvent::ACTION_MOVE, | 
|  | kFakeCoordX, | 
|  | kFakeCoordY - touch_slop_pixels / scale_factor); | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  | EXPECT_FALSE(HasReceivedGesture(ET_GESTURE_SCROLL_BEGIN)); | 
|  |  | 
|  | event = | 
|  | ObtainMotionEvent(event_time + kOneMicrosecond * 2, | 
|  | MotionEvent::ACTION_MOVE, | 
|  | kFakeCoordX, | 
|  | kFakeCoordY + (touch_slop_pixels + 1.f) / scale_factor); | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  | EXPECT_TRUE(HasReceivedGesture(ET_GESTURE_SCROLL_BEGIN)); | 
|  | } | 
|  |  | 
|  | TEST_F(GestureProviderTest, NoDoubleTapWhenTooRapid) { | 
|  | base::TimeTicks event_time = base::TimeTicks::Now(); | 
|  |  | 
|  | MockMotionEvent event = | 
|  | ObtainMotionEvent(event_time, MotionEvent::ACTION_DOWN); | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  |  | 
|  | EXPECT_EQ(ET_GESTURE_TAP_DOWN, GetMostRecentGestureEventType()); | 
|  | EXPECT_EQ(1, GetMostRecentGestureEvent().details.touch_points()); | 
|  |  | 
|  | event = ObtainMotionEvent(event_time + kOneMicrosecond, | 
|  | MotionEvent::ACTION_UP, | 
|  | kFakeCoordX, | 
|  | kFakeCoordY); | 
|  | gesture_provider_->OnTouchEvent(event); | 
|  | EXPECT_EQ(ET_GESTURE_TAP_UNCONFIRMED, GetMostRecentGestureEventType()); | 
|  | EXPECT_EQ(1, GetMostRecentGestureEvent().details.touch_points()); | 
|  |  | 
|  | // If the second tap follows the first in too short a time span, no double-tap | 
|  | // will occur. | 
|  | event_time += (GetDoubleTapMinTime() / 2); | 
|  | event = ObtainMotionEvent(event_time, | 
|  | MotionEvent::ACTION_DOWN, | 
|  | kFakeCoordX, | 
|  | kFakeCoordY); | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  | EXPECT_EQ(ET_GESTURE_TAP_DOWN, GetMostRecentGestureEventType()); | 
|  | EXPECT_EQ(1, GetMostRecentGestureEvent().details.touch_points()); | 
|  |  | 
|  | event = ObtainMotionEvent(event_time + kOneMicrosecond, | 
|  | MotionEvent::ACTION_UP, | 
|  | kFakeCoordX, | 
|  | kFakeCoordY); | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  | EXPECT_EQ(ET_GESTURE_TAP_UNCONFIRMED, GetMostRecentGestureEventType()); | 
|  | } | 
|  |  | 
|  | TEST_F(GestureProviderTest, NoDoubleTapWhenExplicitlyDisabled) { | 
|  | // Ensure that double-tap gestures can be disabled. | 
|  | gesture_provider_->SetDoubleTapSupportForPlatformEnabled(false); | 
|  |  | 
|  | base::TimeTicks event_time = base::TimeTicks::Now(); | 
|  | MockMotionEvent event = ObtainMotionEvent( | 
|  | event_time, MotionEvent::ACTION_DOWN, kFakeCoordX, kFakeCoordY); | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  | EXPECT_EQ(ET_GESTURE_TAP_DOWN, GetMostRecentGestureEventType()); | 
|  |  | 
|  | event = ObtainMotionEvent(event_time + kOneMicrosecond, | 
|  | MotionEvent::ACTION_UP, | 
|  | kFakeCoordX, | 
|  | kFakeCoordY); | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  | EXPECT_EQ(ET_GESTURE_TAP, GetMostRecentGestureEventType()); | 
|  |  | 
|  | event_time += GetValidDoubleTapDelay(); | 
|  | event = ObtainMotionEvent(event_time, | 
|  | MotionEvent::ACTION_DOWN, | 
|  | kFakeCoordX, | 
|  | kFakeCoordY); | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  | EXPECT_EQ(ET_GESTURE_TAP_DOWN, GetMostRecentGestureEventType()); | 
|  |  | 
|  | event = ObtainMotionEvent(event_time + kOneMicrosecond, | 
|  | MotionEvent::ACTION_UP, | 
|  | kFakeCoordX, | 
|  | kFakeCoordY); | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  | EXPECT_EQ(ET_GESTURE_TAP, GetMostRecentGestureEventType()); | 
|  |  | 
|  | // Ensure that double-tap gestures can be interrupted. | 
|  | gesture_provider_->SetDoubleTapSupportForPlatformEnabled(true); | 
|  |  | 
|  | event_time = base::TimeTicks::Now(); | 
|  | event = ObtainMotionEvent( | 
|  | event_time, MotionEvent::ACTION_DOWN, kFakeCoordX, kFakeCoordY); | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  | EXPECT_EQ(5U, GetReceivedGestureCount()); | 
|  |  | 
|  | event = ObtainMotionEvent(event_time + kOneMicrosecond, | 
|  | MotionEvent::ACTION_UP, | 
|  | kFakeCoordX, | 
|  | kFakeCoordY); | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  | EXPECT_EQ(ET_GESTURE_TAP_UNCONFIRMED, GetMostRecentGestureEventType()); | 
|  |  | 
|  | gesture_provider_->SetDoubleTapSupportForPlatformEnabled(false); | 
|  | EXPECT_EQ(ET_GESTURE_TAP, GetMostRecentGestureEventType()); | 
|  |  | 
|  | // Ensure that double-tap gestures can be resumed. | 
|  | gesture_provider_->SetDoubleTapSupportForPlatformEnabled(true); | 
|  |  | 
|  | event_time += GetValidDoubleTapDelay(); | 
|  | event = ObtainMotionEvent(event_time, | 
|  | MotionEvent::ACTION_DOWN, | 
|  | kFakeCoordX, | 
|  | kFakeCoordY); | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  | EXPECT_EQ(ET_GESTURE_TAP_DOWN, GetMostRecentGestureEventType()); | 
|  |  | 
|  | event = ObtainMotionEvent(event_time + kOneMicrosecond, | 
|  | MotionEvent::ACTION_UP, | 
|  | kFakeCoordX, | 
|  | kFakeCoordY); | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  | EXPECT_EQ(ET_GESTURE_TAP_UNCONFIRMED, GetMostRecentGestureEventType()); | 
|  |  | 
|  | event_time += GetValidDoubleTapDelay(); | 
|  | event = ObtainMotionEvent(event_time, | 
|  | MotionEvent::ACTION_DOWN, | 
|  | kFakeCoordX, | 
|  | kFakeCoordY); | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  | EXPECT_EQ(ET_GESTURE_TAP_DOWN, GetMostRecentGestureEventType()); | 
|  |  | 
|  | event = ObtainMotionEvent(event_time + kOneMicrosecond, | 
|  | MotionEvent::ACTION_UP, | 
|  | kFakeCoordX, | 
|  | kFakeCoordY); | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  | EXPECT_EQ(ET_GESTURE_DOUBLE_TAP, GetMostRecentGestureEventType()); | 
|  | } | 
|  |  | 
|  | TEST_F(GestureProviderTest, NoDelayedTapWhenDoubleTapSupportToggled) { | 
|  | gesture_provider_->SetDoubleTapSupportForPlatformEnabled(true); | 
|  |  | 
|  | base::TimeTicks event_time = base::TimeTicks::Now(); | 
|  | MockMotionEvent event = ObtainMotionEvent( | 
|  | event_time, MotionEvent::ACTION_DOWN, kFakeCoordX, kFakeCoordY); | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  | EXPECT_EQ(ET_GESTURE_TAP_DOWN, GetMostRecentGestureEventType()); | 
|  | EXPECT_EQ(1U, GetReceivedGestureCount()); | 
|  |  | 
|  | event = ObtainMotionEvent(event_time + kOneMicrosecond, | 
|  | MotionEvent::ACTION_UP, | 
|  | kFakeCoordX, | 
|  | kFakeCoordY); | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  | EXPECT_EQ(ET_GESTURE_TAP_UNCONFIRMED, GetMostRecentGestureEventType()); | 
|  | EXPECT_EQ(2U, GetReceivedGestureCount()); | 
|  |  | 
|  | // Disabling double-tap during the tap timeout should flush the delayed tap. | 
|  | gesture_provider_->SetDoubleTapSupportForPlatformEnabled(false); | 
|  | EXPECT_EQ(ET_GESTURE_TAP, GetMostRecentGestureEventType()); | 
|  | EXPECT_EQ(3U, GetReceivedGestureCount()); | 
|  |  | 
|  | // No further timeout gestures should arrive. | 
|  | const base::TimeDelta long_press_timeout = | 
|  | GetLongPressTimeout() + GetShowPressTimeout() + kOneMicrosecond; | 
|  | RunTasksAndWait(long_press_timeout); | 
|  | EXPECT_EQ(3U, GetReceivedGestureCount()); | 
|  | } | 
|  |  | 
|  | TEST_F(GestureProviderTest, NoDoubleTapDragZoomWhenDisabledOnPlatform) { | 
|  | const base::TimeTicks down_time_1 = TimeTicks::Now(); | 
|  | const base::TimeTicks down_time_2 = down_time_1 + GetValidDoubleTapDelay(); | 
|  |  | 
|  | gesture_provider_->SetDoubleTapSupportForPlatformEnabled(false); | 
|  |  | 
|  | MockMotionEvent event = | 
|  | ObtainMotionEvent(down_time_1, MotionEvent::ACTION_DOWN); | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  |  | 
|  | event = ObtainMotionEvent(down_time_1 + kOneMicrosecond, | 
|  | MotionEvent::ACTION_UP, | 
|  | kFakeCoordX, | 
|  | kFakeCoordY); | 
|  | gesture_provider_->OnTouchEvent(event); | 
|  |  | 
|  | event = ObtainMotionEvent( | 
|  | down_time_2, MotionEvent::ACTION_DOWN, kFakeCoordX, kFakeCoordY); | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  |  | 
|  | event = ObtainMotionEvent(down_time_2 + kOneMicrosecond, | 
|  | MotionEvent::ACTION_MOVE, | 
|  | kFakeCoordX, | 
|  | kFakeCoordY + 100); | 
|  |  | 
|  | // The move should become a scroll, as doubletap drag zoom is disabled. | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  | EXPECT_TRUE(HasReceivedGesture(ET_GESTURE_SCROLL_BEGIN)); | 
|  | EXPECT_FALSE(HasReceivedGesture(ET_GESTURE_PINCH_BEGIN)); | 
|  |  | 
|  | event = ObtainMotionEvent(down_time_2 + kOneMicrosecond * 2, | 
|  | MotionEvent::ACTION_MOVE, | 
|  | kFakeCoordX, | 
|  | kFakeCoordY + 200); | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  | EXPECT_EQ(ET_GESTURE_SCROLL_UPDATE, GetMostRecentGestureEventType()); | 
|  | EXPECT_EQ(1, GetMostRecentGestureEvent().details.touch_points()); | 
|  | EXPECT_EQ(down_time_2 + kOneMicrosecond * 2, | 
|  | GetMostRecentGestureEvent().time); | 
|  | EXPECT_FALSE(HasReceivedGesture(ET_GESTURE_PINCH_UPDATE)); | 
|  |  | 
|  | event = ObtainMotionEvent(down_time_2 + kOneMicrosecond * 3, | 
|  | MotionEvent::ACTION_UP, | 
|  | kFakeCoordX, | 
|  | kFakeCoordY + 200); | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  | EXPECT_FALSE(HasReceivedGesture(ET_GESTURE_PINCH_END)); | 
|  | } | 
|  |  | 
|  | // Verify that double tap drag zoom feature is not invoked when the gesture | 
|  | // handler is told to disable double tap gesture detection. | 
|  | // The second tap sequence should be treated just as the first would be. | 
|  | TEST_F(GestureProviderTest, NoDoubleTapDragZoomWhenDisabledOnPage) { | 
|  | const base::TimeTicks down_time_1 = TimeTicks::Now(); | 
|  | const base::TimeTicks down_time_2 = down_time_1 + GetValidDoubleTapDelay(); | 
|  |  | 
|  | gesture_provider_->SetDoubleTapSupportForPageEnabled(false); | 
|  |  | 
|  | MockMotionEvent event = | 
|  | ObtainMotionEvent(down_time_1, MotionEvent::ACTION_DOWN); | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  |  | 
|  | event = ObtainMotionEvent(down_time_1 + kOneMicrosecond, | 
|  | MotionEvent::ACTION_UP, | 
|  | kFakeCoordX, | 
|  | kFakeCoordY); | 
|  | gesture_provider_->OnTouchEvent(event); | 
|  |  | 
|  | event = ObtainMotionEvent( | 
|  | down_time_2, MotionEvent::ACTION_DOWN, kFakeCoordX, kFakeCoordY); | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  |  | 
|  | event = ObtainMotionEvent(down_time_2 + kOneMicrosecond, | 
|  | MotionEvent::ACTION_MOVE, | 
|  | kFakeCoordX, | 
|  | kFakeCoordY + 100); | 
|  |  | 
|  | // The move should become a scroll, as double tap drag zoom is disabled. | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  | EXPECT_TRUE(HasReceivedGesture(ET_GESTURE_SCROLL_BEGIN)); | 
|  | EXPECT_FALSE(HasReceivedGesture(ET_GESTURE_PINCH_BEGIN)); | 
|  |  | 
|  | event = ObtainMotionEvent(down_time_2 + kOneMicrosecond * 2, | 
|  | MotionEvent::ACTION_MOVE, | 
|  | kFakeCoordX, | 
|  | kFakeCoordY + 200); | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  | EXPECT_EQ(ET_GESTURE_SCROLL_UPDATE, GetMostRecentGestureEventType()); | 
|  | EXPECT_EQ(1, GetMostRecentGestureEvent().details.touch_points()); | 
|  | EXPECT_FALSE(HasReceivedGesture(ET_GESTURE_PINCH_UPDATE)); | 
|  |  | 
|  | event = ObtainMotionEvent(down_time_2 + kOneMicrosecond * 3, | 
|  | MotionEvent::ACTION_UP, | 
|  | kFakeCoordX, | 
|  | kFakeCoordY + 200); | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  | EXPECT_FALSE(HasReceivedGesture(ET_GESTURE_PINCH_END)); | 
|  | } | 
|  |  | 
|  | // Verify that updating double tap support during a double tap drag zoom | 
|  | // disables double tap detection after the gesture has ended. | 
|  | TEST_F(GestureProviderTest, FixedPageScaleDuringDoubleTapDragZoom) { | 
|  | base::TimeTicks down_time_1 = TimeTicks::Now(); | 
|  | base::TimeTicks down_time_2 = down_time_1 + GetValidDoubleTapDelay(); | 
|  |  | 
|  | gesture_provider_->SetDoubleTapSupportForPageEnabled(true); | 
|  | gesture_provider_->SetDoubleTapSupportForPlatformEnabled(true); | 
|  |  | 
|  | // Start a double-tap drag gesture. | 
|  | MockMotionEvent event = | 
|  | ObtainMotionEvent(down_time_1, MotionEvent::ACTION_DOWN); | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  | event = ObtainMotionEvent(down_time_1 + kOneMicrosecond, | 
|  | MotionEvent::ACTION_UP, | 
|  | kFakeCoordX, | 
|  | kFakeCoordY); | 
|  | gesture_provider_->OnTouchEvent(event); | 
|  | event = ObtainMotionEvent( | 
|  | down_time_2, MotionEvent::ACTION_DOWN, kFakeCoordX, kFakeCoordY); | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  | event = ObtainMotionEvent(down_time_2 + kOneMicrosecond, | 
|  | MotionEvent::ACTION_MOVE, | 
|  | kFakeCoordX, | 
|  | kFakeCoordY + 100); | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  | EXPECT_TRUE(HasReceivedGesture(ET_GESTURE_SCROLL_BEGIN)); | 
|  | EXPECT_EQ(ET_GESTURE_PINCH_BEGIN, GetMostRecentGestureEventType()); | 
|  | EXPECT_EQ(1, GetMostRecentGestureEvent().details.touch_points()); | 
|  |  | 
|  | // Simulate setting a fixed page scale (or a mobile viewport); | 
|  | // this should not disrupt the current double-tap gesture. | 
|  | gesture_provider_->SetDoubleTapSupportForPageEnabled(false); | 
|  |  | 
|  | // Double tap zoom updates should continue. | 
|  | event = ObtainMotionEvent(down_time_2 + kOneMicrosecond * 2, | 
|  | MotionEvent::ACTION_MOVE, | 
|  | kFakeCoordX, | 
|  | kFakeCoordY + 200); | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  | EXPECT_EQ(ET_GESTURE_PINCH_UPDATE, GetMostRecentGestureEventType()); | 
|  | EXPECT_EQ(1, GetMostRecentGestureEvent().details.touch_points()); | 
|  | EXPECT_LT(1.f, GetMostRecentGestureEvent().details.scale()); | 
|  | event = ObtainMotionEvent(down_time_2 + kOneMicrosecond * 3, | 
|  | MotionEvent::ACTION_UP, | 
|  | kFakeCoordX, | 
|  | kFakeCoordY + 200); | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  | EXPECT_TRUE(HasReceivedGesture(ET_GESTURE_PINCH_END)); | 
|  | EXPECT_EQ(ET_GESTURE_SCROLL_END, GetMostRecentGestureEventType()); | 
|  | EXPECT_EQ(1, GetMostRecentGestureEvent().details.touch_points()); | 
|  |  | 
|  | // The double-tap gesture has finished, but the page scale is fixed. | 
|  | // The same event sequence should not generate any double tap getsures. | 
|  | gestures_.clear(); | 
|  | down_time_1 += kOneMicrosecond * 40; | 
|  | down_time_2 += kOneMicrosecond * 40; | 
|  |  | 
|  | // Start a double-tap drag gesture. | 
|  | event = ObtainMotionEvent(down_time_1, MotionEvent::ACTION_DOWN); | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  | event = ObtainMotionEvent(down_time_1 + kOneMicrosecond, | 
|  | MotionEvent::ACTION_UP, | 
|  | kFakeCoordX, | 
|  | kFakeCoordY); | 
|  | gesture_provider_->OnTouchEvent(event); | 
|  | event = ObtainMotionEvent( | 
|  | down_time_2, MotionEvent::ACTION_DOWN, kFakeCoordX, kFakeCoordY); | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  | event = ObtainMotionEvent(down_time_2 + kOneMicrosecond, | 
|  | MotionEvent::ACTION_MOVE, | 
|  | kFakeCoordX, | 
|  | kFakeCoordY + 100); | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  | EXPECT_TRUE(HasReceivedGesture(ET_GESTURE_SCROLL_BEGIN)); | 
|  | EXPECT_FALSE(HasReceivedGesture(ET_GESTURE_PINCH_BEGIN)); | 
|  |  | 
|  | // Double tap zoom updates should not be sent. | 
|  | // Instead, the second tap drag becomes a scroll gesture sequence. | 
|  | event = ObtainMotionEvent(down_time_2 + kOneMicrosecond * 2, | 
|  | MotionEvent::ACTION_MOVE, | 
|  | kFakeCoordX, | 
|  | kFakeCoordY + 200); | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  | EXPECT_TRUE(HasReceivedGesture(ET_GESTURE_SCROLL_UPDATE)); | 
|  | EXPECT_FALSE(HasReceivedGesture(ET_GESTURE_PINCH_UPDATE)); | 
|  | event = ObtainMotionEvent(down_time_2 + kOneMicrosecond * 3, | 
|  | MotionEvent::ACTION_UP, | 
|  | kFakeCoordX, | 
|  | kFakeCoordY + 200); | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  | EXPECT_FALSE(HasReceivedGesture(ET_GESTURE_PINCH_END)); | 
|  | } | 
|  |  | 
|  | // Verify that pinch zoom sends the proper event sequence. | 
|  | TEST_F(GestureProviderTest, PinchZoom) { | 
|  | base::TimeTicks event_time = base::TimeTicks::Now(); | 
|  | const float touch_slop = GetTouchSlop(); | 
|  | const float raw_offset_x = 3.2f; | 
|  | const float raw_offset_y = 4.3f; | 
|  | int motion_event_id = 6; | 
|  |  | 
|  | gesture_provider_->SetDoubleTapSupportForPageEnabled(false); | 
|  | gesture_provider_->SetDoubleTapSupportForPlatformEnabled(true); | 
|  | gesture_provider_->SetMultiTouchZoomSupportEnabled(true); | 
|  |  | 
|  | int secondary_coord_x = kFakeCoordX + 20 * touch_slop; | 
|  | int secondary_coord_y = kFakeCoordY + 20 * touch_slop; | 
|  |  | 
|  | MockMotionEvent event = | 
|  | ObtainMotionEvent(event_time, MotionEvent::ACTION_DOWN); | 
|  | event.SetPrimaryPointerId(motion_event_id); | 
|  | event.SetRawOffset(raw_offset_x, raw_offset_y); | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  | EXPECT_EQ(ET_GESTURE_TAP_DOWN, GetMostRecentGestureEventType()); | 
|  | EXPECT_EQ(kFakeCoordX, GetMostRecentGestureEvent().x); | 
|  | EXPECT_EQ(kFakeCoordY, GetMostRecentGestureEvent().y); | 
|  | EXPECT_EQ(kFakeCoordX + raw_offset_x, GetMostRecentGestureEvent().raw_x); | 
|  | EXPECT_EQ(kFakeCoordY + raw_offset_y, GetMostRecentGestureEvent().raw_y); | 
|  | EXPECT_EQ(1, GetMostRecentGestureEvent().details.touch_points()); | 
|  | EXPECT_EQ(BoundsForSingleMockTouchAtLocation(kFakeCoordX, kFakeCoordY), | 
|  | GetMostRecentGestureEvent().details.bounding_box()); | 
|  |  | 
|  | // Toggling double-tap support should not take effect until the next sequence. | 
|  | gesture_provider_->SetDoubleTapSupportForPageEnabled(true); | 
|  |  | 
|  | event = ObtainMotionEvent(event_time, | 
|  | MotionEvent::ACTION_POINTER_DOWN, | 
|  | kFakeCoordX, | 
|  | kFakeCoordY, | 
|  | secondary_coord_x, | 
|  | secondary_coord_y); | 
|  | event.SetPrimaryPointerId(motion_event_id); | 
|  | event.SetRawOffset(raw_offset_x, raw_offset_y); | 
|  |  | 
|  | gesture_provider_->OnTouchEvent(event); | 
|  | EXPECT_EQ(1U, GetReceivedGestureCount()); | 
|  | EXPECT_EQ(1, GetMostRecentGestureEvent().details.touch_points()); | 
|  | EXPECT_EQ(BoundsForSingleMockTouchAtLocation(kFakeCoordX, kFakeCoordY), | 
|  | GetMostRecentGestureEvent().details.bounding_box()); | 
|  |  | 
|  | secondary_coord_x += 5 * touch_slop; | 
|  | secondary_coord_y += 5 * touch_slop; | 
|  | event = ObtainMotionEvent(event_time, | 
|  | MotionEvent::ACTION_MOVE, | 
|  | kFakeCoordX, | 
|  | kFakeCoordY, | 
|  | secondary_coord_x, | 
|  | secondary_coord_y); | 
|  | event.SetPrimaryPointerId(motion_event_id); | 
|  | event.SetRawOffset(raw_offset_x, raw_offset_y); | 
|  |  | 
|  | // Toggling double-tap support should not take effect until the next sequence. | 
|  | gesture_provider_->SetDoubleTapSupportForPageEnabled(false); | 
|  |  | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  | EXPECT_EQ(motion_event_id, GetMostRecentGestureEvent().motion_event_id); | 
|  | EXPECT_EQ(2, GetMostRecentGestureEvent().details.touch_points()); | 
|  | EXPECT_TRUE(HasReceivedGesture(ET_GESTURE_PINCH_BEGIN)); | 
|  | EXPECT_TRUE(HasReceivedGesture(ET_GESTURE_SCROLL_BEGIN)); | 
|  | EXPECT_TRUE(HasReceivedGesture(ET_GESTURE_SCROLL_UPDATE)); | 
|  |  | 
|  | EXPECT_EQ((kFakeCoordX + secondary_coord_x) / 2, GetReceivedGesture(3).x); | 
|  | EXPECT_EQ((kFakeCoordY + secondary_coord_y) / 2, GetReceivedGesture(3).y); | 
|  | EXPECT_EQ((kFakeCoordX + secondary_coord_x) / 2 + raw_offset_x, | 
|  | GetReceivedGesture(3).raw_x); | 
|  | EXPECT_EQ((kFakeCoordY + secondary_coord_y) / 2 + raw_offset_y, | 
|  | GetReceivedGesture(3).raw_y); | 
|  |  | 
|  | EXPECT_EQ( | 
|  | gfx::RectF(kFakeCoordX - kMockTouchRadius, | 
|  | kFakeCoordY - kMockTouchRadius, | 
|  | secondary_coord_x - kFakeCoordX + kMockTouchRadius * 2, | 
|  | secondary_coord_y - kFakeCoordY + kMockTouchRadius * 2), | 
|  | GetMostRecentGestureEvent().details.bounding_box()); | 
|  |  | 
|  | secondary_coord_x += 2 * touch_slop; | 
|  | secondary_coord_y += 2 * touch_slop; | 
|  | event = ObtainMotionEvent(event_time, | 
|  | MotionEvent::ACTION_MOVE, | 
|  | kFakeCoordX, | 
|  | kFakeCoordY, | 
|  | secondary_coord_x, | 
|  | secondary_coord_y); | 
|  | event.SetPrimaryPointerId(motion_event_id); | 
|  |  | 
|  | // Toggling double-tap support should not take effect until the next sequence. | 
|  | gesture_provider_->SetDoubleTapSupportForPageEnabled(true); | 
|  |  | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  | EXPECT_EQ(motion_event_id, GetMostRecentGestureEvent().motion_event_id); | 
|  | EXPECT_TRUE(HasReceivedGesture(ET_GESTURE_SCROLL_UPDATE)); | 
|  | EXPECT_EQ(ET_GESTURE_PINCH_UPDATE, GetMostRecentGestureEventType()); | 
|  | EXPECT_EQ(2, GetMostRecentGestureEvent().details.touch_points()); | 
|  | EXPECT_LT(1.f, GetMostRecentGestureEvent().details.scale()); | 
|  | EXPECT_EQ( | 
|  | gfx::RectF(kFakeCoordX - kMockTouchRadius, | 
|  | kFakeCoordY - kMockTouchRadius, | 
|  | secondary_coord_x - kFakeCoordX + kMockTouchRadius * 2, | 
|  | secondary_coord_y - kFakeCoordY + kMockTouchRadius * 2), | 
|  | GetMostRecentGestureEvent().details.bounding_box()); | 
|  |  | 
|  | event = ObtainMotionEvent(event_time, | 
|  | MotionEvent::ACTION_POINTER_UP, | 
|  | kFakeCoordX, | 
|  | kFakeCoordY, | 
|  | secondary_coord_x, | 
|  | secondary_coord_y); | 
|  | event.SetPrimaryPointerId(motion_event_id); | 
|  |  | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  | EXPECT_EQ(motion_event_id, GetMostRecentGestureEvent().motion_event_id); | 
|  | EXPECT_EQ(ET_GESTURE_PINCH_END, GetMostRecentGestureEventType()); | 
|  | EXPECT_EQ(2, GetMostRecentGestureEvent().details.touch_points()); | 
|  | EXPECT_FALSE(HasReceivedGesture(ET_GESTURE_SCROLL_END)); | 
|  | EXPECT_EQ( | 
|  | gfx::RectF(kFakeCoordX - kMockTouchRadius, | 
|  | kFakeCoordY - kMockTouchRadius, | 
|  | secondary_coord_x - kFakeCoordX + kMockTouchRadius * 2, | 
|  | secondary_coord_y - kFakeCoordY + kMockTouchRadius * 2), | 
|  | GetMostRecentGestureEvent().details.bounding_box()); | 
|  |  | 
|  | event = ObtainMotionEvent(event_time, MotionEvent::ACTION_UP); | 
|  | gesture_provider_->OnTouchEvent(event); | 
|  | EXPECT_EQ(ET_GESTURE_SCROLL_END, GetMostRecentGestureEventType()); | 
|  | EXPECT_EQ(1, GetMostRecentGestureEvent().details.touch_points()); | 
|  | EXPECT_EQ(gfx::RectF(kFakeCoordX - kMockTouchRadius, | 
|  | kFakeCoordY - kMockTouchRadius, | 
|  | kMockTouchRadius * 2, | 
|  | kMockTouchRadius * 2), | 
|  | GetMostRecentGestureEvent().details.bounding_box()); | 
|  | } | 
|  |  | 
|  | // Verify that no accidental pinching occurs if the touch size is large relative | 
|  | // to the min scaling span when the touch major value is used in scaling. | 
|  | TEST_F(GestureProviderTest, NoPinchZoomWithFatFinger) { | 
|  | base::TimeTicks event_time = base::TimeTicks::Now(); | 
|  | const float kFatFingerSize = GetMinScalingSpan() * 3.f; | 
|  |  | 
|  | gesture_provider_->SetDoubleTapSupportForPlatformEnabled(false); | 
|  | gesture_provider_->SetMultiTouchZoomSupportEnabled(true); | 
|  |  | 
|  | MockMotionEvent event = | 
|  | ObtainMotionEvent(event_time, MotionEvent::ACTION_DOWN); | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  | EXPECT_EQ(ET_GESTURE_TAP_DOWN, GetMostRecentGestureEventType()); | 
|  | EXPECT_EQ(1U, GetReceivedGestureCount()); | 
|  |  | 
|  | event = ObtainMotionEvent(event_time + kOneSecond, | 
|  | MotionEvent::ACTION_MOVE); | 
|  | event.SetTouchMajor(0.1f); | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  | EXPECT_EQ(1U, GetReceivedGestureCount()); | 
|  |  | 
|  | event = ObtainMotionEvent(event_time + kOneSecond * 2, | 
|  | MotionEvent::ACTION_MOVE, | 
|  | kFakeCoordX + 1.f, | 
|  | kFakeCoordY); | 
|  | event.SetTouchMajor(1.f); | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  | EXPECT_EQ(1U, GetReceivedGestureCount()); | 
|  |  | 
|  | event = ObtainMotionEvent(event_time + kOneSecond * 3, | 
|  | MotionEvent::ACTION_MOVE); | 
|  | event.SetTouchMajor(kFatFingerSize * 3.5f); | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  | EXPECT_EQ(1U, GetReceivedGestureCount()); | 
|  |  | 
|  | event = ObtainMotionEvent(event_time + kOneSecond * 4, | 
|  | MotionEvent::ACTION_MOVE); | 
|  | event.SetTouchMajor(kFatFingerSize * 5.f); | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  | EXPECT_EQ(1U, GetReceivedGestureCount()); | 
|  |  | 
|  | event = ObtainMotionEvent(event_time + kOneSecond * 4, | 
|  | MotionEvent::ACTION_MOVE, | 
|  | kFakeCoordX + 50.f, | 
|  | kFakeCoordY - 25.f); | 
|  | event.SetTouchMajor(kFatFingerSize * 10.f); | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  | EXPECT_FALSE(HasReceivedGesture(ET_GESTURE_PINCH_BEGIN)); | 
|  |  | 
|  | event = ObtainMotionEvent(event_time + kOneSecond * 4, | 
|  | MotionEvent::ACTION_MOVE, | 
|  | kFakeCoordX + 100.f, | 
|  | kFakeCoordY - 50.f); | 
|  | event.SetTouchMajor(kFatFingerSize * 5.f); | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  | EXPECT_FALSE(HasReceivedGesture(ET_GESTURE_PINCH_BEGIN)); | 
|  | } | 
|  |  | 
|  | // Verify that multi-finger swipe sends the proper event sequence. | 
|  | TEST_F(GestureProviderTest, MultiFingerSwipe) { | 
|  | EnableSwipe(); | 
|  | gesture_provider_->SetMultiTouchZoomSupportEnabled(false); | 
|  | const float min_swipe_velocity = GetMinSwipeVelocity(); | 
|  |  | 
|  | // One finger - swipe right | 
|  | OneFingerSwipe(2 * min_swipe_velocity, 0); | 
|  | EXPECT_TRUE(HasReceivedGesture(ET_GESTURE_SWIPE)); | 
|  | EXPECT_TRUE(GetMostRecentGestureEvent().details.swipe_right()); | 
|  | EXPECT_EQ(1, GetMostRecentGestureEvent().details.touch_points()); | 
|  | ResetGestureDetection(); | 
|  |  | 
|  | // One finger - swipe left | 
|  | OneFingerSwipe(-2 * min_swipe_velocity, 0); | 
|  | EXPECT_TRUE(HasReceivedGesture(ET_GESTURE_SWIPE)); | 
|  | EXPECT_TRUE(GetMostRecentGestureEvent().details.swipe_left()); | 
|  | EXPECT_EQ(1, GetMostRecentGestureEvent().details.touch_points()); | 
|  | ResetGestureDetection(); | 
|  |  | 
|  | // One finger - swipe down | 
|  | OneFingerSwipe(0, 2 * min_swipe_velocity); | 
|  | EXPECT_TRUE(HasReceivedGesture(ET_GESTURE_SWIPE)); | 
|  | EXPECT_TRUE(GetMostRecentGestureEvent().details.swipe_down()); | 
|  | EXPECT_EQ(1, GetMostRecentGestureEvent().details.touch_points()); | 
|  | ResetGestureDetection(); | 
|  |  | 
|  | // One finger - swipe up | 
|  | OneFingerSwipe(0, -2 * min_swipe_velocity); | 
|  | EXPECT_TRUE(HasReceivedGesture(ET_GESTURE_SWIPE)); | 
|  | EXPECT_TRUE(GetMostRecentGestureEvent().details.swipe_up()); | 
|  | EXPECT_EQ(1, GetMostRecentGestureEvent().details.touch_points()); | 
|  | ResetGestureDetection(); | 
|  |  | 
|  | // Two fingers | 
|  | // Swipe right. | 
|  | TwoFingerSwipe(min_swipe_velocity * 2, 0, min_swipe_velocity * 2, 0); | 
|  | EXPECT_TRUE(HasReceivedGesture(ET_GESTURE_SWIPE)); | 
|  | EXPECT_TRUE(GetMostRecentGestureEvent().details.swipe_right()); | 
|  | EXPECT_EQ(2, GetMostRecentGestureEvent().details.touch_points()); | 
|  | ResetGestureDetection(); | 
|  |  | 
|  | // Swipe left. | 
|  | TwoFingerSwipe(-min_swipe_velocity * 2, 0, -min_swipe_velocity * 2, 0); | 
|  | EXPECT_TRUE(HasReceivedGesture(ET_GESTURE_SWIPE)); | 
|  | EXPECT_TRUE(GetMostRecentGestureEvent().details.swipe_left()); | 
|  | EXPECT_EQ(2, GetMostRecentGestureEvent().details.touch_points()); | 
|  | ResetGestureDetection(); | 
|  |  | 
|  | // No swipe with different touch directions. | 
|  | TwoFingerSwipe(min_swipe_velocity * 2, 0, -min_swipe_velocity * 2, 0); | 
|  | EXPECT_FALSE(HasReceivedGesture(ET_GESTURE_SWIPE)); | 
|  | ResetGestureDetection(); | 
|  |  | 
|  | // No swipe without a dominant direction. | 
|  | TwoFingerSwipe(min_swipe_velocity * 2, | 
|  | min_swipe_velocity * 2, | 
|  | min_swipe_velocity * 2, | 
|  | min_swipe_velocity * 2); | 
|  | EXPECT_FALSE(HasReceivedGesture(ET_GESTURE_SWIPE)); | 
|  | ResetGestureDetection(); | 
|  |  | 
|  | // Swipe down with non-zero velocities on both axes and dominant direction. | 
|  | TwoFingerSwipe(-min_swipe_velocity, | 
|  | min_swipe_velocity * 4, | 
|  | -min_swipe_velocity, | 
|  | min_swipe_velocity * 4); | 
|  | EXPECT_TRUE(HasReceivedGesture(ET_GESTURE_SWIPE)); | 
|  | EXPECT_TRUE(GetMostRecentGestureEvent().details.swipe_down()); | 
|  | EXPECT_FALSE(GetMostRecentGestureEvent().details.swipe_left()); | 
|  | EXPECT_EQ(2, GetMostRecentGestureEvent().details.touch_points()); | 
|  | ResetGestureDetection(); | 
|  |  | 
|  | // Swipe up with non-zero velocities on both axes. | 
|  | TwoFingerSwipe(min_swipe_velocity, | 
|  | -min_swipe_velocity * 4, | 
|  | min_swipe_velocity, | 
|  | -min_swipe_velocity * 4); | 
|  | EXPECT_TRUE(HasReceivedGesture(ET_GESTURE_SWIPE)); | 
|  | EXPECT_TRUE(GetMostRecentGestureEvent().details.swipe_up()); | 
|  | EXPECT_FALSE(GetMostRecentGestureEvent().details.swipe_right()); | 
|  | EXPECT_EQ(2, GetMostRecentGestureEvent().details.touch_points()); | 
|  | ResetGestureDetection(); | 
|  |  | 
|  | // No swipe without sufficient velocity. | 
|  | TwoFingerSwipe(min_swipe_velocity / 2, 0, 0, 0); | 
|  | EXPECT_FALSE(HasReceivedGesture(ET_GESTURE_SWIPE)); | 
|  | ResetGestureDetection(); | 
|  |  | 
|  | // Swipe up with one small and one medium velocity in slightly different but | 
|  | // not opposing directions. | 
|  | TwoFingerSwipe(min_swipe_velocity / 2, | 
|  | min_swipe_velocity / 2, | 
|  | 0, | 
|  | min_swipe_velocity * 2); | 
|  | EXPECT_TRUE(HasReceivedGesture(ET_GESTURE_SWIPE)); | 
|  | EXPECT_TRUE(GetMostRecentGestureEvent().details.swipe_down()); | 
|  | EXPECT_FALSE(GetMostRecentGestureEvent().details.swipe_right()); | 
|  | EXPECT_EQ(2, GetMostRecentGestureEvent().details.touch_points()); | 
|  | ResetGestureDetection(); | 
|  |  | 
|  | // No swipe in orthogonal directions. | 
|  | TwoFingerSwipe(min_swipe_velocity * 2, 0, 0, min_swipe_velocity * 7); | 
|  | EXPECT_FALSE(HasReceivedGesture(ET_GESTURE_SWIPE)); | 
|  | ResetGestureDetection(); | 
|  |  | 
|  | // Three finger swipe in same directions. | 
|  | ThreeFingerSwipe(min_swipe_velocity * 2, | 
|  | 0, | 
|  | min_swipe_velocity * 3, | 
|  | 0, | 
|  | min_swipe_velocity * 4, | 
|  | 0); | 
|  | EXPECT_TRUE(HasReceivedGesture(ET_GESTURE_SWIPE)); | 
|  | EXPECT_TRUE(GetMostRecentGestureEvent().details.swipe_right()); | 
|  | EXPECT_EQ(3, GetMostRecentGestureEvent().details.touch_points()); | 
|  | ResetGestureDetection(); | 
|  |  | 
|  | // No three finger swipe in different directions. | 
|  | ThreeFingerSwipe(min_swipe_velocity * 2, | 
|  | 0, | 
|  | 0, | 
|  | min_swipe_velocity * 3, | 
|  | min_swipe_velocity * 4, | 
|  | 0); | 
|  | EXPECT_FALSE(HasReceivedGesture(ET_GESTURE_SWIPE)); | 
|  | } | 
|  |  | 
|  | // Verify that the timer of LONG_PRESS will be cancelled when scrolling begins | 
|  | // so LONG_PRESS and LONG_TAP won't be triggered. | 
|  | TEST_F(GestureProviderTest, GesturesCancelledAfterLongPressCausesLostFocus) { | 
|  | base::TimeTicks event_time = base::TimeTicks::Now(); | 
|  |  | 
|  | MockMotionEvent event = | 
|  | ObtainMotionEvent(event_time, MotionEvent::ACTION_DOWN); | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  |  | 
|  | const base::TimeDelta long_press_timeout = | 
|  | GetLongPressTimeout() + GetShowPressTimeout() + kOneMicrosecond; | 
|  | RunTasksAndWait(long_press_timeout); | 
|  | EXPECT_EQ(ET_GESTURE_LONG_PRESS, GetMostRecentGestureEventType()); | 
|  | EXPECT_EQ(1, GetMostRecentGestureEvent().details.touch_points()); | 
|  |  | 
|  | EXPECT_TRUE(CancelActiveTouchSequence()); | 
|  | EXPECT_FALSE(HasDownEvent()); | 
|  |  | 
|  | event = ObtainMotionEvent(event_time + long_press_timeout, | 
|  | MotionEvent::ACTION_UP); | 
|  | gesture_provider_->OnTouchEvent(event); | 
|  | EXPECT_FALSE(HasReceivedGesture(ET_GESTURE_LONG_TAP)); | 
|  | } | 
|  |  | 
|  | // Verify that inserting a touch cancel event will trigger proper touch and | 
|  | // gesture sequence cancellation. | 
|  | TEST_F(GestureProviderTest, CancelActiveTouchSequence) { | 
|  | base::TimeTicks event_time = base::TimeTicks::Now(); | 
|  | int motion_event_id = 6; | 
|  |  | 
|  | EXPECT_FALSE(CancelActiveTouchSequence()); | 
|  | EXPECT_EQ(0U, GetReceivedGestureCount()); | 
|  |  | 
|  | MockMotionEvent event = | 
|  | ObtainMotionEvent(event_time, MotionEvent::ACTION_DOWN); | 
|  | event.SetPrimaryPointerId(motion_event_id); | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  | EXPECT_EQ(ET_GESTURE_TAP_DOWN, GetMostRecentGestureEventType()); | 
|  | EXPECT_EQ(motion_event_id, GetMostRecentGestureEvent().motion_event_id); | 
|  | EXPECT_EQ(1, GetMostRecentGestureEvent().details.touch_points()); | 
|  |  | 
|  | ASSERT_TRUE(CancelActiveTouchSequence()); | 
|  | EXPECT_FALSE(HasDownEvent()); | 
|  |  | 
|  | // Subsequent MotionEvent's are dropped until ACTION_DOWN. | 
|  | event = ObtainMotionEvent(event_time + kOneMicrosecond, | 
|  | MotionEvent::ACTION_MOVE); | 
|  | EXPECT_FALSE(gesture_provider_->OnTouchEvent(event)); | 
|  |  | 
|  | event = ObtainMotionEvent(event_time + kOneMicrosecond * 2, | 
|  | MotionEvent::ACTION_UP); | 
|  | EXPECT_FALSE(gesture_provider_->OnTouchEvent(event)); | 
|  |  | 
|  | event = ObtainMotionEvent(event_time + kOneMicrosecond * 3, | 
|  | MotionEvent::ACTION_DOWN); | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  | EXPECT_EQ(ET_GESTURE_TAP_DOWN, GetMostRecentGestureEventType()); | 
|  | EXPECT_EQ(1, GetMostRecentGestureEvent().details.touch_points()); | 
|  | } | 
|  |  | 
|  | TEST_F(GestureProviderTest, DoubleTapDragZoomCancelledOnSecondaryPointerDown) { | 
|  | const base::TimeTicks down_time_1 = TimeTicks::Now(); | 
|  | const base::TimeTicks down_time_2 = down_time_1 + GetValidDoubleTapDelay(); | 
|  |  | 
|  | gesture_provider_->SetDoubleTapSupportForPlatformEnabled(true); | 
|  |  | 
|  | MockMotionEvent event = | 
|  | ObtainMotionEvent(down_time_1, MotionEvent::ACTION_DOWN); | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  | EXPECT_EQ(ET_GESTURE_TAP_DOWN, GetMostRecentGestureEventType()); | 
|  | EXPECT_EQ(1, GetMostRecentGestureEvent().details.touch_points()); | 
|  |  | 
|  | event = | 
|  | ObtainMotionEvent(down_time_1 + kOneMicrosecond, MotionEvent::ACTION_UP); | 
|  | gesture_provider_->OnTouchEvent(event); | 
|  | EXPECT_EQ(ET_GESTURE_TAP_UNCONFIRMED, GetMostRecentGestureEventType()); | 
|  | EXPECT_EQ(1, GetMostRecentGestureEvent().details.touch_points()); | 
|  |  | 
|  | event = ObtainMotionEvent(down_time_2, MotionEvent::ACTION_DOWN); | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  | EXPECT_EQ(ET_GESTURE_TAP_DOWN, GetMostRecentGestureEventType()); | 
|  | EXPECT_EQ(1, GetMostRecentGestureEvent().details.touch_points()); | 
|  |  | 
|  | event = ObtainMotionEvent(down_time_2 + kOneMicrosecond, | 
|  | MotionEvent::ACTION_MOVE, | 
|  | kFakeCoordX, | 
|  | kFakeCoordY - 30); | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  | EXPECT_TRUE(HasReceivedGesture(ET_GESTURE_SCROLL_BEGIN)); | 
|  | EXPECT_EQ(ET_GESTURE_PINCH_BEGIN, GetMostRecentGestureEventType()); | 
|  | EXPECT_EQ(1, GetMostRecentGestureEvent().details.touch_points()); | 
|  |  | 
|  | event = ObtainMotionEvent(down_time_2 + kOneMicrosecond * 2, | 
|  | MotionEvent::ACTION_POINTER_DOWN, | 
|  | kFakeCoordX, | 
|  | kFakeCoordY - 30, | 
|  | kFakeCoordX + 50, | 
|  | kFakeCoordY + 50); | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  | EXPECT_EQ(ET_GESTURE_PINCH_END, GetMostRecentGestureEventType()); | 
|  | EXPECT_EQ(2, GetMostRecentGestureEvent().details.touch_points()); | 
|  |  | 
|  | const size_t gesture_count = GetReceivedGestureCount(); | 
|  | event = ObtainMotionEvent(down_time_2 + kOneMicrosecond * 3, | 
|  | MotionEvent::ACTION_POINTER_UP, | 
|  | kFakeCoordX, | 
|  | kFakeCoordY - 30, | 
|  | kFakeCoordX + 50, | 
|  | kFakeCoordY + 50); | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  | EXPECT_EQ(gesture_count, GetReceivedGestureCount()); | 
|  |  | 
|  | event = ObtainMotionEvent(down_time_2 + kOneSecond, | 
|  | MotionEvent::ACTION_UP); | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  | EXPECT_EQ(gesture_count + 1, GetReceivedGestureCount()); | 
|  | EXPECT_EQ(ET_GESTURE_SCROLL_END, GetMostRecentGestureEventType()); | 
|  | EXPECT_EQ(1, GetMostRecentGestureEvent().details.touch_points()); | 
|  | } | 
|  |  | 
|  | // Verify that gesture begin and gesture end events are dispatched correctly. | 
|  | TEST_F(GestureProviderTest, GestureBeginAndEnd) { | 
|  | EnableBeginEndTypes(); | 
|  | base::TimeTicks event_time = base::TimeTicks::Now(); | 
|  | const float raw_offset_x = 7.5f; | 
|  | const float raw_offset_y = 5.7f; | 
|  |  | 
|  | EXPECT_EQ(0U, GetReceivedGestureCount()); | 
|  | MockMotionEvent event = | 
|  | ObtainMotionEvent(event_time, MotionEvent::ACTION_DOWN, 1, 1); | 
|  | event.SetRawOffset(raw_offset_x, raw_offset_y); | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  | EXPECT_EQ(ET_GESTURE_BEGIN, GetReceivedGesture(0).type()); | 
|  | EXPECT_EQ(ET_GESTURE_TAP_DOWN, GetMostRecentGestureEventType()); | 
|  | EXPECT_EQ(2U, GetReceivedGestureCount()); | 
|  | EXPECT_EQ(1, GetMostRecentGestureEvent().details.touch_points()); | 
|  | EXPECT_EQ(1, GetMostRecentGestureEvent().x); | 
|  | EXPECT_EQ(1, GetMostRecentGestureEvent().y); | 
|  | EXPECT_EQ(1 + raw_offset_x, GetMostRecentGestureEvent().raw_x); | 
|  | EXPECT_EQ(1 + raw_offset_y, GetMostRecentGestureEvent().raw_y); | 
|  | EXPECT_EQ(gfx::RectF(1 - kMockTouchRadius, | 
|  | 1 - kMockTouchRadius, | 
|  | kMockTouchRadius * 2, | 
|  | kMockTouchRadius * 2), | 
|  | GetMostRecentGestureEvent().details.bounding_box()); | 
|  |  | 
|  | event = ObtainMotionEvent( | 
|  | event_time, MotionEvent::ACTION_POINTER_DOWN, 1, 1, 2, 2); | 
|  | event.SetRawOffset(raw_offset_x, raw_offset_y); | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  | EXPECT_EQ(ET_GESTURE_BEGIN, GetMostRecentGestureEventType()); | 
|  | EXPECT_EQ(3U, GetReceivedGestureCount()); | 
|  | EXPECT_EQ(2, GetMostRecentGestureEvent().details.touch_points()); | 
|  | EXPECT_EQ(2, GetMostRecentGestureEvent().x); | 
|  | EXPECT_EQ(2, GetMostRecentGestureEvent().y); | 
|  | EXPECT_EQ(2 + raw_offset_x, GetMostRecentGestureEvent().raw_x); | 
|  | EXPECT_EQ(2 + raw_offset_y, GetMostRecentGestureEvent().raw_y); | 
|  |  | 
|  | event = ObtainMotionEvent( | 
|  | event_time, MotionEvent::ACTION_POINTER_DOWN, 1, 1, 2, 2, 3, 3); | 
|  | event.SetRawOffset(raw_offset_x, raw_offset_y); | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  | EXPECT_EQ(ET_GESTURE_BEGIN, GetMostRecentGestureEventType()); | 
|  | EXPECT_EQ(4U, GetReceivedGestureCount()); | 
|  | EXPECT_EQ(3, GetMostRecentGestureEvent().details.touch_points()); | 
|  | EXPECT_EQ(3, GetMostRecentGestureEvent().x); | 
|  | EXPECT_EQ(3, GetMostRecentGestureEvent().y); | 
|  | EXPECT_EQ(3 + raw_offset_x, GetMostRecentGestureEvent().raw_x); | 
|  | EXPECT_EQ(3 + raw_offset_y, GetMostRecentGestureEvent().raw_y); | 
|  |  | 
|  | event = ObtainMotionEvent( | 
|  | event_time, MotionEvent::ACTION_POINTER_UP, 1, 1, 2, 2, 3, 3); | 
|  | event.SetRawOffset(raw_offset_x, raw_offset_y); | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  | EXPECT_EQ(ET_GESTURE_END, GetMostRecentGestureEventType()); | 
|  | EXPECT_EQ(5U, GetReceivedGestureCount()); | 
|  | EXPECT_EQ(3, GetMostRecentGestureEvent().details.touch_points()); | 
|  | EXPECT_EQ(1, GetMostRecentGestureEvent().x); | 
|  | EXPECT_EQ(1, GetMostRecentGestureEvent().y); | 
|  | EXPECT_EQ(1 + raw_offset_x, GetMostRecentGestureEvent().raw_x); | 
|  | EXPECT_EQ(1 + raw_offset_y, GetMostRecentGestureEvent().raw_y); | 
|  |  | 
|  | event = ObtainMotionEvent( | 
|  | event_time, MotionEvent::ACTION_POINTER_DOWN, 2, 2, 3, 3, 4, 4); | 
|  | event.SetRawOffset(raw_offset_x, raw_offset_y); | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  | EXPECT_EQ(ET_GESTURE_BEGIN, GetMostRecentGestureEventType()); | 
|  | EXPECT_EQ(6U, GetReceivedGestureCount()); | 
|  | EXPECT_EQ(3, GetMostRecentGestureEvent().details.touch_points()); | 
|  | EXPECT_EQ(4, GetMostRecentGestureEvent().x); | 
|  | EXPECT_EQ(4, GetMostRecentGestureEvent().y); | 
|  | EXPECT_EQ(4 + raw_offset_x, GetMostRecentGestureEvent().raw_x); | 
|  | EXPECT_EQ(4 + raw_offset_y, GetMostRecentGestureEvent().raw_y); | 
|  |  | 
|  | event = ObtainMotionEvent( | 
|  | event_time, MotionEvent::ACTION_POINTER_UP, 2, 2, 3, 3, 4, 4); | 
|  | event.SetRawOffset(raw_offset_x, raw_offset_y); | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  | EXPECT_EQ(ET_GESTURE_END, GetMostRecentGestureEventType()); | 
|  | EXPECT_EQ(7U, GetReceivedGestureCount()); | 
|  | EXPECT_EQ(3, GetMostRecentGestureEvent().details.touch_points()); | 
|  | EXPECT_EQ(2, GetMostRecentGestureEvent().x); | 
|  | EXPECT_EQ(2, GetMostRecentGestureEvent().y); | 
|  | EXPECT_EQ(2 + raw_offset_x, GetMostRecentGestureEvent().raw_x); | 
|  | EXPECT_EQ(2 + raw_offset_y, GetMostRecentGestureEvent().raw_y); | 
|  |  | 
|  | event = | 
|  | ObtainMotionEvent(event_time, MotionEvent::ACTION_POINTER_UP, 3, 3, 4, 4); | 
|  | event.SetRawOffset(raw_offset_x, raw_offset_y); | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  | EXPECT_EQ(ET_GESTURE_END, GetMostRecentGestureEventType()); | 
|  | EXPECT_EQ(8U, GetReceivedGestureCount()); | 
|  | EXPECT_EQ(2, GetMostRecentGestureEvent().details.touch_points()); | 
|  | EXPECT_EQ(3, GetMostRecentGestureEvent().x); | 
|  | EXPECT_EQ(3, GetMostRecentGestureEvent().y); | 
|  | EXPECT_EQ(3 + raw_offset_x, GetMostRecentGestureEvent().raw_x); | 
|  | EXPECT_EQ(3 + raw_offset_y, GetMostRecentGestureEvent().raw_y); | 
|  |  | 
|  |  | 
|  | event = ObtainMotionEvent(event_time, MotionEvent::ACTION_UP, 4, 4); | 
|  | event.SetRawOffset(raw_offset_x, raw_offset_y); | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  | EXPECT_EQ(ET_GESTURE_END, GetMostRecentGestureEventType()); | 
|  | EXPECT_EQ(9U, GetReceivedGestureCount()); | 
|  | EXPECT_EQ(1, GetMostRecentGestureEvent().details.touch_points()); | 
|  | EXPECT_EQ(4, GetMostRecentGestureEvent().x); | 
|  | EXPECT_EQ(4, GetMostRecentGestureEvent().y); | 
|  | EXPECT_EQ(4 + raw_offset_x, GetMostRecentGestureEvent().raw_x); | 
|  | EXPECT_EQ(4 + raw_offset_y, GetMostRecentGestureEvent().raw_y); | 
|  | } | 
|  |  | 
|  | // Verify that gesture begin and gesture end events are dispatched correctly | 
|  | // when an ACTION_CANCEL is received. | 
|  | TEST_F(GestureProviderTest, GestureBeginAndEndOnCancel) { | 
|  | EnableBeginEndTypes(); | 
|  | base::TimeTicks event_time = base::TimeTicks::Now(); | 
|  |  | 
|  | EXPECT_EQ(0U, GetReceivedGestureCount()); | 
|  | MockMotionEvent event = | 
|  | ObtainMotionEvent(event_time, MotionEvent::ACTION_DOWN, 1, 1); | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  | EXPECT_EQ(ET_GESTURE_BEGIN, GetReceivedGesture(0).type()); | 
|  | EXPECT_EQ(ET_GESTURE_TAP_DOWN, GetMostRecentGestureEventType()); | 
|  | EXPECT_EQ(2U, GetReceivedGestureCount()); | 
|  | EXPECT_EQ(1, GetMostRecentGestureEvent().details.touch_points()); | 
|  | EXPECT_EQ(gfx::RectF(1 - kMockTouchRadius, | 
|  | 1 - kMockTouchRadius, | 
|  | kMockTouchRadius * 2, | 
|  | kMockTouchRadius * 2), | 
|  | GetMostRecentGestureEvent().details.bounding_box()); | 
|  | EXPECT_EQ(1, GetMostRecentGestureEvent().x); | 
|  | EXPECT_EQ(1, GetMostRecentGestureEvent().y); | 
|  |  | 
|  | event = ObtainMotionEvent( | 
|  | event_time, MotionEvent::ACTION_POINTER_DOWN, 1, 1, 2, 2); | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  | EXPECT_EQ(ET_GESTURE_BEGIN, GetMostRecentGestureEventType()); | 
|  | EXPECT_EQ(3U, GetReceivedGestureCount()); | 
|  | EXPECT_EQ(2, GetMostRecentGestureEvent().details.touch_points()); | 
|  | EXPECT_EQ(2, GetMostRecentGestureEvent().x); | 
|  | EXPECT_EQ(2, GetMostRecentGestureEvent().y); | 
|  |  | 
|  | event = ObtainMotionEvent( | 
|  | event_time, MotionEvent::ACTION_POINTER_DOWN, 1, 1, 2, 2, 3, 3); | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  | EXPECT_EQ(ET_GESTURE_BEGIN, GetMostRecentGestureEventType()); | 
|  | EXPECT_EQ(4U, GetReceivedGestureCount()); | 
|  | EXPECT_EQ(3, GetMostRecentGestureEvent().details.touch_points()); | 
|  | EXPECT_EQ(3, GetMostRecentGestureEvent().x); | 
|  | EXPECT_EQ(3, GetMostRecentGestureEvent().y); | 
|  |  | 
|  | event = ObtainMotionEvent( | 
|  | event_time, MotionEvent::ACTION_CANCEL, 1, 1, 2, 2, 3, 3); | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  | EXPECT_EQ(5U, GetReceivedGestureCount()); | 
|  | EXPECT_EQ(3, GetReceivedGesture(4).details.touch_points()); | 
|  | EXPECT_EQ(ET_GESTURE_END, GetReceivedGesture(4).type()); | 
|  | EXPECT_EQ(1, GetMostRecentGestureEvent().x); | 
|  | EXPECT_EQ(1, GetMostRecentGestureEvent().y); | 
|  |  | 
|  | event = ObtainMotionEvent( | 
|  | event_time, MotionEvent::ACTION_CANCEL, 1, 1, 3, 3); | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  | EXPECT_EQ(6U, GetReceivedGestureCount()); | 
|  | EXPECT_EQ(2, GetMostRecentGestureEvent().details.touch_points()); | 
|  | EXPECT_EQ(ET_GESTURE_END, GetMostRecentGestureEvent().type()); | 
|  | EXPECT_EQ(1, GetMostRecentGestureEvent().x); | 
|  | EXPECT_EQ(1, GetMostRecentGestureEvent().y); | 
|  |  | 
|  | event = ObtainMotionEvent( | 
|  | event_time, MotionEvent::ACTION_CANCEL, 3, 3); | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  | EXPECT_EQ(1, GetMostRecentGestureEvent().details.touch_points()); | 
|  | EXPECT_EQ(ET_GESTURE_END, GetMostRecentGestureEvent().type()); | 
|  | EXPECT_EQ(3, GetMostRecentGestureEvent().x); | 
|  | EXPECT_EQ(3, GetMostRecentGestureEvent().y); | 
|  | } | 
|  |  | 
|  | // Test a simple two finger tap | 
|  | TEST_F(GestureProviderTest, TwoFingerTap) { | 
|  | // The time between ACTION_POINTER_DOWN and ACTION_POINTER_UP must be <= the | 
|  | // two finger tap delay. | 
|  | EnableTwoFingerTap(kMaxTwoFingerTapSeparation, base::TimeDelta()); | 
|  | const float scaled_touch_slop = GetTouchSlop(); | 
|  |  | 
|  | base::TimeTicks event_time = base::TimeTicks::Now(); | 
|  |  | 
|  | MockMotionEvent event = | 
|  | ObtainMotionEvent(event_time, MotionEvent::ACTION_DOWN, 0, 0); | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  |  | 
|  | event = ObtainMotionEvent(event_time, | 
|  | MotionEvent::ACTION_MOVE, | 
|  | 0, | 
|  | scaled_touch_slop / 2); | 
|  |  | 
|  | event = ObtainMotionEvent(event_time, | 
|  | MotionEvent::ACTION_POINTER_DOWN, | 
|  | 0, | 
|  | 0, | 
|  | kMaxTwoFingerTapSeparation / 2, | 
|  | 0); | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  |  | 
|  | event = | 
|  | ObtainMotionEvent(event_time, | 
|  | MotionEvent::ACTION_MOVE, | 
|  | 0, | 
|  | -scaled_touch_slop / 2, | 
|  | kMaxTwoFingerTapSeparation / 2 + scaled_touch_slop / 2, | 
|  | 0); | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  |  | 
|  | event = ObtainMotionEvent(event_time, | 
|  | MotionEvent::ACTION_POINTER_UP, | 
|  | 0, | 
|  | 0, | 
|  | kMaxTwoFingerTapSeparation, | 
|  | 0); | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  |  | 
|  | EXPECT_EQ(ET_GESTURE_TAP_DOWN, GetReceivedGesture(0).type()); | 
|  | EXPECT_EQ(ET_GESTURE_SCROLL_BEGIN, GetReceivedGesture(1).type()); | 
|  | EXPECT_EQ(ET_GESTURE_SCROLL_UPDATE, GetReceivedGesture(2).type()); | 
|  | EXPECT_EQ(ET_GESTURE_TWO_FINGER_TAP, GetReceivedGesture(3).type()); | 
|  | EXPECT_EQ(4U, GetReceivedGestureCount()); | 
|  |  | 
|  | EXPECT_EQ(kMockTouchRadius * 2, | 
|  | GetReceivedGesture(3).details.first_finger_width()); | 
|  | EXPECT_EQ(kMockTouchRadius * 2, | 
|  | GetReceivedGesture(3).details.first_finger_height()); | 
|  | } | 
|  |  | 
|  | // Test preventing a two finger tap via finger movement. | 
|  | TEST_F(GestureProviderTest, TwoFingerTapCancelledByFingerMovement) { | 
|  | EnableTwoFingerTap(kMaxTwoFingerTapSeparation, base::TimeDelta()); | 
|  | const float scaled_touch_slop = GetTouchSlop(); | 
|  | base::TimeTicks event_time = base::TimeTicks::Now(); | 
|  |  | 
|  | MockMotionEvent event = ObtainMotionEvent( | 
|  | event_time, MotionEvent::ACTION_DOWN, kFakeCoordX, kFakeCoordY); | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  |  | 
|  | event = ObtainMotionEvent(event_time, | 
|  | MotionEvent::ACTION_POINTER_DOWN, | 
|  | kFakeCoordX, | 
|  | kFakeCoordY, | 
|  | kFakeCoordX, | 
|  | kFakeCoordY); | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  |  | 
|  | event = ObtainMotionEvent(event_time, | 
|  | MotionEvent::ACTION_MOVE, | 
|  | kFakeCoordX, | 
|  | kFakeCoordY, | 
|  | kFakeCoordX + scaled_touch_slop + 0.1, | 
|  | kFakeCoordY); | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  |  | 
|  | event = ObtainMotionEvent(event_time, | 
|  | MotionEvent::ACTION_POINTER_UP, | 
|  | kFakeCoordX, | 
|  | kFakeCoordY, | 
|  | kFakeCoordX, | 
|  | kFakeCoordY); | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  |  | 
|  | EXPECT_EQ(ET_GESTURE_TAP_DOWN, GetReceivedGesture(0).type()); | 
|  | EXPECT_EQ(ET_GESTURE_SCROLL_BEGIN, GetReceivedGesture(1).type()); | 
|  | EXPECT_EQ(ET_GESTURE_SCROLL_UPDATE, GetReceivedGesture(2).type()); | 
|  | EXPECT_FLOAT_EQ((scaled_touch_slop + 0.1) / 2, | 
|  | GetReceivedGesture(2).details.scroll_x()); | 
|  | EXPECT_EQ(0, GetReceivedGesture(2).details.scroll_y()); | 
|  | EXPECT_EQ(3U, GetReceivedGestureCount()); | 
|  | } | 
|  |  | 
|  | // Test preventing a two finger tap by waiting too long before releasing the | 
|  | // secondary pointer. | 
|  | TEST_F(GestureProviderTest, TwoFingerTapCancelledByDelay) { | 
|  | base::TimeDelta two_finger_tap_timeout = kOneSecond; | 
|  | EnableTwoFingerTap(kMaxTwoFingerTapSeparation, two_finger_tap_timeout); | 
|  | base::TimeTicks event_time = base::TimeTicks::Now(); | 
|  |  | 
|  | MockMotionEvent event = ObtainMotionEvent( | 
|  | event_time, MotionEvent::ACTION_DOWN, kFakeCoordX, kFakeCoordY); | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  |  | 
|  | event = ObtainMotionEvent(event_time, | 
|  | MotionEvent::ACTION_MOVE, | 
|  | kFakeCoordX, | 
|  | kFakeCoordY); | 
|  |  | 
|  | event = ObtainMotionEvent(event_time, | 
|  | MotionEvent::ACTION_POINTER_DOWN, | 
|  | kFakeCoordX, | 
|  | kFakeCoordY, | 
|  | kFakeCoordX + kMaxTwoFingerTapSeparation / 2, | 
|  | kFakeCoordY); | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  |  | 
|  | event = ObtainMotionEvent(event_time + kOneSecond + kOneMicrosecond, | 
|  | MotionEvent::ACTION_POINTER_UP, | 
|  | kFakeCoordX, | 
|  | kFakeCoordY, | 
|  | kFakeCoordX + kMaxTwoFingerTapSeparation / 2, | 
|  | kFakeCoordY); | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  |  | 
|  | EXPECT_EQ(ET_GESTURE_TAP_DOWN, GetReceivedGesture(0).type()); | 
|  | EXPECT_EQ(1U, GetReceivedGestureCount()); | 
|  | } | 
|  |  | 
|  | // Test preventing a two finger tap by pressing the secondary pointer too far | 
|  | // from the first | 
|  | TEST_F(GestureProviderTest, TwoFingerTapCancelledByDistanceBetweenPointers) { | 
|  | EnableTwoFingerTap(kMaxTwoFingerTapSeparation, base::TimeDelta()); | 
|  | base::TimeTicks event_time = base::TimeTicks::Now(); | 
|  |  | 
|  | MockMotionEvent event = ObtainMotionEvent( | 
|  | event_time, MotionEvent::ACTION_DOWN, kFakeCoordX, kFakeCoordY); | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  |  | 
|  | event = ObtainMotionEvent(event_time, | 
|  | MotionEvent::ACTION_POINTER_DOWN, | 
|  | kFakeCoordX, | 
|  | kFakeCoordY, | 
|  | kFakeCoordX + kMaxTwoFingerTapSeparation, | 
|  | kFakeCoordY); | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  |  | 
|  | event = ObtainMotionEvent(event_time, | 
|  | MotionEvent::ACTION_POINTER_UP, | 
|  | kFakeCoordX, | 
|  | kFakeCoordY, | 
|  | kFakeCoordX + kMaxTwoFingerTapSeparation, | 
|  | kFakeCoordY); | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  |  | 
|  | EXPECT_EQ(ET_GESTURE_TAP_DOWN, GetReceivedGesture(0).type()); | 
|  | EXPECT_EQ(1U, GetReceivedGestureCount()); | 
|  | } | 
|  |  | 
|  | // Verify that pinch zoom only sends updates which exceed the | 
|  | // min_pinch_update_span_delta. | 
|  | TEST_F(GestureProviderTest, PinchZoomWithThreshold) { | 
|  | const float kMinPinchUpdateDistance = 5; | 
|  |  | 
|  | base::TimeTicks event_time = base::TimeTicks::Now(); | 
|  | const float touch_slop = GetTouchSlop(); | 
|  |  | 
|  | SetMinPinchUpdateSpanDelta(kMinPinchUpdateDistance); | 
|  | gesture_provider_->SetDoubleTapSupportForPageEnabled(false); | 
|  | gesture_provider_->SetDoubleTapSupportForPlatformEnabled(true); | 
|  | gesture_provider_->SetMultiTouchZoomSupportEnabled(true); | 
|  |  | 
|  | int secondary_coord_x = kFakeCoordX + 20 * touch_slop; | 
|  | int secondary_coord_y = kFakeCoordY + 20 * touch_slop; | 
|  |  | 
|  | // First finger down. | 
|  | MockMotionEvent event = | 
|  | ObtainMotionEvent(event_time, MotionEvent::ACTION_DOWN); | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  | EXPECT_EQ(ET_GESTURE_TAP_DOWN, GetMostRecentGestureEventType()); | 
|  | EXPECT_EQ(1, GetMostRecentGestureEvent().details.touch_points()); | 
|  |  | 
|  | // Second finger down. | 
|  | event = ObtainMotionEvent(event_time, | 
|  | MotionEvent::ACTION_POINTER_DOWN, | 
|  | kFakeCoordX, | 
|  | kFakeCoordY, | 
|  | secondary_coord_x, | 
|  | secondary_coord_y); | 
|  |  | 
|  | gesture_provider_->OnTouchEvent(event); | 
|  | EXPECT_EQ(1U, GetReceivedGestureCount()); | 
|  | EXPECT_EQ(1, GetMostRecentGestureEvent().details.touch_points()); | 
|  |  | 
|  | // Move second finger. | 
|  | secondary_coord_x += 5 * touch_slop; | 
|  | secondary_coord_y += 5 * touch_slop; | 
|  | event = ObtainMotionEvent(event_time, | 
|  | MotionEvent::ACTION_MOVE, | 
|  | kFakeCoordX, | 
|  | kFakeCoordY, | 
|  | secondary_coord_x, | 
|  | secondary_coord_y); | 
|  |  | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  | EXPECT_EQ(2, GetMostRecentGestureEvent().details.touch_points()); | 
|  | EXPECT_TRUE(HasReceivedGesture(ET_GESTURE_PINCH_BEGIN)); | 
|  | EXPECT_FALSE(HasReceivedGesture(ET_GESTURE_PINCH_UPDATE)); | 
|  | EXPECT_TRUE(HasReceivedGesture(ET_GESTURE_SCROLL_BEGIN)); | 
|  | EXPECT_TRUE(HasReceivedGesture(ET_GESTURE_SCROLL_UPDATE)); | 
|  |  | 
|  | // Small move, shouldn't trigger pinch. | 
|  | event = ObtainMotionEvent(event_time, | 
|  | MotionEvent::ACTION_MOVE, | 
|  | kFakeCoordX, | 
|  | kFakeCoordY, | 
|  | secondary_coord_x + kMinPinchUpdateDistance, | 
|  | secondary_coord_y); | 
|  |  | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  | EXPECT_FALSE(HasReceivedGesture(ET_GESTURE_PINCH_UPDATE)); | 
|  | EXPECT_EQ(2, GetMostRecentGestureEvent().details.touch_points()); | 
|  |  | 
|  | // Small move, but combined with the previous move, should trigger pinch. We | 
|  | // need to overshoot kMinPinchUpdateDistance by a fair bit, as the span | 
|  | // calculation factors in touch radius. | 
|  | const float kOvershootMinPinchUpdateDistance = 3; | 
|  | event = ObtainMotionEvent(event_time, | 
|  | MotionEvent::ACTION_MOVE, | 
|  | kFakeCoordX, | 
|  | kFakeCoordY, | 
|  | secondary_coord_x + kMinPinchUpdateDistance + | 
|  | kOvershootMinPinchUpdateDistance, | 
|  | secondary_coord_y); | 
|  |  | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  | EXPECT_TRUE(HasReceivedGesture(ET_GESTURE_PINCH_UPDATE)); | 
|  | EXPECT_EQ(2, GetMostRecentGestureEvent().details.touch_points()); | 
|  | } | 
|  |  | 
|  | // Verify that the min gesture bound setting is honored. | 
|  | TEST_F(GestureProviderTest, MinGestureBoundsLength) { | 
|  | const float kMinGestureBoundsLength = 10.f * kMockTouchRadius; | 
|  | SetMinMaxGestureBoundsLength(kMinGestureBoundsLength, 0.f); | 
|  | gesture_provider_->SetDoubleTapSupportForPlatformEnabled(false); | 
|  |  | 
|  | base::TimeTicks event_time = base::TimeTicks::Now(); | 
|  | MockMotionEvent event = | 
|  | ObtainMotionEvent(event_time, MotionEvent::ACTION_DOWN); | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  |  | 
|  | EXPECT_EQ(ET_GESTURE_TAP_DOWN, GetMostRecentGestureEventType()); | 
|  | EXPECT_EQ(kMinGestureBoundsLength, | 
|  | GetMostRecentGestureEvent().details.bounding_box_f().width()); | 
|  | EXPECT_EQ(kMinGestureBoundsLength, | 
|  | GetMostRecentGestureEvent().details.bounding_box_f().height()); | 
|  |  | 
|  | event = | 
|  | ObtainMotionEvent(event_time + kOneMicrosecond, MotionEvent::ACTION_UP); | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  | EXPECT_EQ(ET_GESTURE_TAP, GetMostRecentGestureEventType()); | 
|  | EXPECT_EQ(kMinGestureBoundsLength, | 
|  | GetMostRecentGestureEvent().details.bounding_box_f().width()); | 
|  | EXPECT_EQ(kMinGestureBoundsLength, | 
|  | GetMostRecentGestureEvent().details.bounding_box_f().height()); | 
|  | } | 
|  |  | 
|  | TEST_F(GestureProviderTest, MaxGestureBoundsLength) { | 
|  | const float kMaxGestureBoundsLength = kMockTouchRadius / 10.f; | 
|  | SetMinMaxGestureBoundsLength(0.f, kMaxGestureBoundsLength); | 
|  | gesture_provider_->SetDoubleTapSupportForPlatformEnabled(false); | 
|  |  | 
|  | base::TimeTicks event_time = base::TimeTicks::Now(); | 
|  | MockMotionEvent event = | 
|  | ObtainMotionEvent(event_time, MotionEvent::ACTION_DOWN); | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  |  | 
|  | EXPECT_EQ(ET_GESTURE_TAP_DOWN, GetMostRecentGestureEventType()); | 
|  | EXPECT_EQ(kMaxGestureBoundsLength, | 
|  | GetMostRecentGestureEvent().details.bounding_box_f().width()); | 
|  | EXPECT_EQ(kMaxGestureBoundsLength, | 
|  | GetMostRecentGestureEvent().details.bounding_box_f().height()); | 
|  |  | 
|  | event = | 
|  | ObtainMotionEvent(event_time + kOneMicrosecond, MotionEvent::ACTION_UP); | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  | EXPECT_EQ(ET_GESTURE_TAP, GetMostRecentGestureEventType()); | 
|  | EXPECT_EQ(kMaxGestureBoundsLength, | 
|  | GetMostRecentGestureEvent().details.bounding_box_f().width()); | 
|  | EXPECT_EQ(kMaxGestureBoundsLength, | 
|  | GetMostRecentGestureEvent().details.bounding_box_f().height()); | 
|  | } | 
|  |  | 
|  | TEST_F(GestureProviderTest, ZeroRadiusBoundingBox) { | 
|  | base::TimeTicks event_time = base::TimeTicks::Now(); | 
|  | MockMotionEvent event = | 
|  | ObtainMotionEvent(event_time, MotionEvent::ACTION_DOWN, 10, 20); | 
|  | event.SetTouchMajor(0); | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  | EXPECT_EQ(gfx::RectF(10, 20, 0, 0), | 
|  | GetMostRecentGestureEvent().details.bounding_box()); | 
|  |  | 
|  | event = ObtainMotionEvent( | 
|  | event_time, MotionEvent::ACTION_POINTER_DOWN, 10, 20, 110, 120); | 
|  | event.SetTouchMajor(0); | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  |  | 
|  | event = ObtainMotionEvent( | 
|  | event_time, MotionEvent::ACTION_MOVE, 10, 20, 110, 150); | 
|  | event.SetTouchMajor(0); | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  |  | 
|  | EXPECT_EQ(gfx::RectF(10, 20, 100, 130), | 
|  | GetMostRecentGestureEvent().details.bounding_box()); | 
|  | } | 
|  |  | 
|  | // Verify that the min/max gesture bound settings are not applied to stylus | 
|  | // or mouse-derived MotionEvents. | 
|  | TEST_F(GestureProviderTest, NoMinOrMaxGestureBoundsLengthWithStylusOrMouse) { | 
|  | const float kMinGestureBoundsLength = 5.f * kMockTouchRadius; | 
|  | const float kMaxGestureBoundsLength = 10.f * kMockTouchRadius; | 
|  | SetMinMaxGestureBoundsLength(kMinGestureBoundsLength, | 
|  | kMaxGestureBoundsLength); | 
|  | gesture_provider_->SetDoubleTapSupportForPlatformEnabled(false); | 
|  |  | 
|  | base::TimeTicks event_time = base::TimeTicks::Now(); | 
|  | MockMotionEvent event = | 
|  | ObtainMotionEvent(event_time, MotionEvent::ACTION_DOWN); | 
|  | event.SetTouchMajor(0); | 
|  | event.SetToolType(0, MotionEvent::TOOL_TYPE_MOUSE); | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  |  | 
|  | EXPECT_EQ(ET_GESTURE_TAP_DOWN, GetMostRecentGestureEventType()); | 
|  | EXPECT_EQ(MotionEvent::TOOL_TYPE_MOUSE, | 
|  | GetMostRecentGestureEvent().primary_tool_type); | 
|  | EXPECT_EQ(0.f, GetMostRecentGestureEvent().details.bounding_box_f().width()); | 
|  | EXPECT_EQ(0.f, GetMostRecentGestureEvent().details.bounding_box_f().height()); | 
|  |  | 
|  | event = | 
|  | ObtainMotionEvent(event_time + kOneMicrosecond, MotionEvent::ACTION_UP); | 
|  | event.SetTouchMajor(1); | 
|  | event.SetToolType(0, MotionEvent::TOOL_TYPE_STYLUS); | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  | EXPECT_EQ(ET_GESTURE_TAP, GetMostRecentGestureEventType()); | 
|  | EXPECT_EQ(MotionEvent::TOOL_TYPE_STYLUS, | 
|  | GetMostRecentGestureEvent().primary_tool_type); | 
|  | EXPECT_EQ(0, GetMostRecentGestureEvent().details.bounding_box_f().width()); | 
|  | EXPECT_EQ(0, GetMostRecentGestureEvent().details.bounding_box_f().height()); | 
|  |  | 
|  | event = ObtainMotionEvent(event_time, MotionEvent::ACTION_DOWN); | 
|  | event.SetTouchMajor(2.f * kMaxGestureBoundsLength); | 
|  | event.SetToolType(0, MotionEvent::TOOL_TYPE_MOUSE); | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  | EXPECT_EQ(MotionEvent::TOOL_TYPE_MOUSE, | 
|  | GetMostRecentGestureEvent().primary_tool_type); | 
|  | EXPECT_EQ(ET_GESTURE_TAP_DOWN, GetMostRecentGestureEventType()); | 
|  | EXPECT_EQ(2.f * kMaxGestureBoundsLength, | 
|  | GetMostRecentGestureEvent().details.bounding_box_f().width()); | 
|  | EXPECT_EQ(2.f * kMaxGestureBoundsLength, | 
|  | GetMostRecentGestureEvent().details.bounding_box_f().height()); | 
|  |  | 
|  | event = | 
|  | ObtainMotionEvent(event_time + kOneMicrosecond, MotionEvent::ACTION_UP); | 
|  | event.SetTouchMajor(2.f * kMaxGestureBoundsLength); | 
|  | event.SetToolType(0, MotionEvent::TOOL_TYPE_ERASER); | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  | EXPECT_EQ(ET_GESTURE_TAP, GetMostRecentGestureEventType()); | 
|  | EXPECT_EQ(MotionEvent::TOOL_TYPE_ERASER, | 
|  | GetMostRecentGestureEvent().primary_tool_type); | 
|  | EXPECT_EQ(2.f * kMaxGestureBoundsLength, | 
|  | GetMostRecentGestureEvent().details.bounding_box_f().width()); | 
|  | EXPECT_EQ(2.f * kMaxGestureBoundsLength, | 
|  | GetMostRecentGestureEvent().details.bounding_box_f().height()); | 
|  | } | 
|  |  | 
|  | // Test the bounding box for show press and tap gestures. | 
|  | TEST_F(GestureProviderTest, BoundingBoxForShowPressAndTapGesture) { | 
|  | base::TimeTicks event_time = base::TimeTicks::Now(); | 
|  | gesture_provider_->SetDoubleTapSupportForPlatformEnabled(false); | 
|  | base::TimeDelta showpress_timeout = kOneMicrosecond; | 
|  | base::TimeDelta longpress_timeout = kOneSecond; | 
|  | SetShowPressAndLongPressTimeout(showpress_timeout, longpress_timeout); | 
|  |  | 
|  | MockMotionEvent event = | 
|  | ObtainMotionEvent(event_time, MotionEvent::ACTION_DOWN, 10, 10); | 
|  | event.SetTouchMajor(10); | 
|  |  | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  | EXPECT_EQ(ET_GESTURE_TAP_DOWN, GetMostRecentGestureEventType()); | 
|  | EXPECT_EQ(1, GetMostRecentGestureEvent().details.touch_points()); | 
|  | EXPECT_EQ(gfx::RectF(5, 5, 10, 10), | 
|  | GetMostRecentGestureEvent().details.bounding_box()); | 
|  |  | 
|  | event = ObtainMotionEvent( | 
|  | event_time + kOneMicrosecond, MotionEvent::ACTION_MOVE, 11, 9); | 
|  | event.SetTouchMajor(20); | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  | event = ObtainMotionEvent( | 
|  | event_time + kOneMicrosecond, MotionEvent::ACTION_MOVE, 8, 11); | 
|  | event.SetTouchMajor(10); | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  | RunTasksAndWait(showpress_timeout + kOneMicrosecond); | 
|  | EXPECT_EQ(ET_GESTURE_SHOW_PRESS, GetMostRecentGestureEventType()); | 
|  | EXPECT_EQ(gfx::RectF(0, 0, 20, 20), | 
|  | GetMostRecentGestureEvent().details.bounding_box()); | 
|  |  | 
|  | event = | 
|  | ObtainMotionEvent(event_time + kOneMicrosecond, MotionEvent::ACTION_UP); | 
|  | event.SetTouchMajor(30); | 
|  | EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); | 
|  | EXPECT_EQ(ET_GESTURE_TAP, GetMostRecentGestureEventType()); | 
|  |  | 
|  | EXPECT_EQ(1, GetMostRecentGestureEvent().details.tap_count()); | 
|  | EXPECT_EQ(1, GetMostRecentGestureEvent().details.touch_points()); | 
|  | EXPECT_EQ(gfx::RectF(0, 0, 20, 20), | 
|  | GetMostRecentGestureEvent().details.bounding_box()); | 
|  | } | 
|  |  | 
|  | }  // namespace ui |