diff options
Diffstat (limited to 'ui/events')
8 files changed, 243 insertions, 116 deletions
diff --git a/ui/events/gesture_detection/gesture_event_data_packet.h b/ui/events/gesture_detection/gesture_event_data_packet.h index 4d83f21..877f446 100644 --- a/ui/events/gesture_detection/gesture_event_data_packet.h +++ b/ui/events/gesture_detection/gesture_event_data_packet.h @@ -20,7 +20,7 @@ class GESTURE_DETECTION_EXPORT GestureEventDataPacket { UNDEFINED = -1, // Used only for a default-constructed packet. INVALID, // The source of the gesture was invalid. TOUCH_SEQUENCE_START, // The start of a new gesture sequence. - TOUCH_SEQUENCE_END, // The end of gesture sequence. + TOUCH_SEQUENCE_END, // The end of a gesture sequence. TOUCH_START, // A touch down occured during a gesture sequence. TOUCH_MOVE, // A touch move occured during a gesture sequence. TOUCH_END, // A touch up occured during a gesture sequence. diff --git a/ui/events/gesture_detection/gesture_provider.cc b/ui/events/gesture_detection/gesture_provider.cc index 6c581fe..c96a30a 100644 --- a/ui/events/gesture_detection/gesture_provider.cc +++ b/ui/events/gesture_detection/gesture_provider.cc @@ -361,7 +361,6 @@ class GestureProvider::GestureListenerImpl virtual bool OnSingleTapUp(const MotionEvent& e) OVERRIDE { if (IsPointOutsideCurrentSlopRegion(e.GetRawX(), e.GetRawY())) { - provider_->SendTapCancelIfNecessary(e); ignore_single_tap_ = true; return true; } @@ -528,8 +527,6 @@ class GestureProvider::GestureListenerImpl GestureProvider::GestureProvider(const Config& config, GestureProviderClient* client) : client_(client), - needs_show_press_event_(false), - needs_tap_ending_event_(false), touch_scroll_in_progress_(false), pinch_in_progress_(false), double_tap_support_for_page_(true), @@ -654,49 +651,29 @@ void GestureProvider::Send(const GestureEventData& gesture) { gesture.type == ET_GESTURE_SHOW_PRESS); switch (gesture.type) { - case ET_GESTURE_TAP_DOWN: - needs_tap_ending_event_ = true; - needs_show_press_event_ = true; - break; - case ET_GESTURE_TAP_UNCONFIRMED: - needs_show_press_event_ = false; - break; - case ET_GESTURE_TAP: - if (needs_show_press_event_) - Send(CreateGesture(ET_GESTURE_SHOW_PRESS, - gesture.motion_event_id, - gesture.time, - gesture.x, - gesture.y)); - needs_tap_ending_event_ = false; - break; - case ET_GESTURE_DOUBLE_TAP: - needs_tap_ending_event_ = false; - break; - case ET_GESTURE_TAP_CANCEL: - if (!needs_tap_ending_event_) - return; - needs_tap_ending_event_ = false; - break; - case ET_GESTURE_SHOW_PRESS: - needs_show_press_event_ = false; - break; case ET_GESTURE_LONG_PRESS: DCHECK(!scale_gesture_listener_->IsScaleGestureDetectionInProgress()); current_longpress_time_ = gesture.time; break; case ET_GESTURE_LONG_TAP: - needs_tap_ending_event_ = false; current_longpress_time_ = base::TimeTicks(); break; case ET_GESTURE_SCROLL_BEGIN: + DCHECK(!touch_scroll_in_progress_); touch_scroll_in_progress_ = true; - SendTapCancelIfNecessary(gesture); break; case ET_GESTURE_SCROLL_END: + DCHECK(touch_scroll_in_progress_); + if (pinch_in_progress_) + Send(CreateGesture(ET_GESTURE_PINCH_END, + gesture.motion_event_id, + gesture.time, + gesture.x, + gesture.y)); touch_scroll_in_progress_ = false; break; case ET_GESTURE_PINCH_BEGIN: + DCHECK(!pinch_in_progress_); if (!touch_scroll_in_progress_) Send(CreateGesture(ET_GESTURE_SCROLL_BEGIN, gesture.motion_event_id, @@ -706,8 +683,15 @@ void GestureProvider::Send(const GestureEventData& gesture) { pinch_in_progress_ = true; break; case ET_GESTURE_PINCH_END: + DCHECK(pinch_in_progress_); pinch_in_progress_ = false; break; + case ET_GESTURE_SHOW_PRESS: + // It's possible that a double-tap drag zoom (from ScaleGestureDetector) + // will start before the press gesture fires (from GestureDetector), in + // which case the press should simply be dropped. + if (pinch_in_progress_ || touch_scroll_in_progress_) + return; default: break; }; @@ -715,30 +699,10 @@ void GestureProvider::Send(const GestureEventData& gesture) { client_->OnGestureEvent(gesture); } -void GestureProvider::SendTapCancelIfNecessary(const MotionEvent& event) { - if (!needs_tap_ending_event_) - return; - current_longpress_time_ = base::TimeTicks(); - Send(CreateGesture(ET_GESTURE_TAP_CANCEL, event)); -} - -void GestureProvider::SendTapCancelIfNecessary( - const GestureEventData& gesture) { - if (!needs_tap_ending_event_) - return; - current_longpress_time_ = base::TimeTicks(); - Send(CreateGesture(ET_GESTURE_TAP_CANCEL, - gesture.motion_event_id, - gesture.time, - gesture.x, - gesture.y)); -} - bool GestureProvider::SendLongTapIfNecessary(const MotionEvent& event) { if (event.GetAction() == MotionEvent::ACTION_UP && !current_longpress_time_.is_null() && !scale_gesture_listener_->IsScaleGestureDetectionInProgress()) { - SendTapCancelIfNecessary(event); GestureEventDetails long_tap_details(ET_GESTURE_LONG_TAP, 0, 0); long_tap_details.set_bounding_box( gfx::RectF(event.GetTouchMajor(), event.GetTouchMajor())); @@ -752,13 +716,13 @@ void GestureProvider::EndTouchScrollIfNecessary(const MotionEvent& event, bool send_scroll_end_event) { if (!touch_scroll_in_progress_) return; - touch_scroll_in_progress_ = false; if (send_scroll_end_event) Send(CreateGesture(ET_GESTURE_SCROLL_END, event)); + touch_scroll_in_progress_ = false; } void GestureProvider::UpdateDoubleTapDetectionSupport() { - if (IsDoubleTapInProgress()) + if (current_down_event_ || IsDoubleTapInProgress()) return; const bool supports_double_tap = IsDoubleTapSupported(); @@ -771,9 +735,8 @@ void GestureProvider::OnTouchEventHandlingBegin(const MotionEvent& event) { case MotionEvent::ACTION_DOWN: current_down_event_ = event.Clone(); touch_scroll_in_progress_ = false; - needs_show_press_event_ = false; + pinch_in_progress_ = false; current_longpress_time_ = base::TimeTicks(); - SendTapCancelIfNecessary(event); if (gesture_begin_end_types_enabled_) Send(CreateGesture(ET_GESTURE_BEGIN, event)); break; @@ -797,17 +760,12 @@ void GestureProvider::OnTouchEventHandlingEnd(const MotionEvent& event) { // |Fling()| will have already signalled an end to touch-scrolling. EndTouchScrollIfNecessary(event, true); - // We shouldn't necessarily cancel a tap on ACTION_UP, as the double-tap - // timeout may yet trigger a SINGLE_TAP. - if (event.GetAction() == MotionEvent::ACTION_CANCEL) - SendTapCancelIfNecessary(event); - - UpdateDoubleTapDetectionSupport(); - if (gesture_begin_end_types_enabled_) Send(CreateGesture(ET_GESTURE_END, event)); current_down_event_.reset(); + + UpdateDoubleTapDetectionSupport(); break; case MotionEvent::ACTION_POINTER_UP: if (gesture_begin_end_types_enabled_) diff --git a/ui/events/gesture_detection/gesture_provider.h b/ui/events/gesture_detection/gesture_provider.h index 10f2cb1..b8e85b7 100644 --- a/ui/events/gesture_detection/gesture_provider.h +++ b/ui/events/gesture_detection/gesture_provider.h @@ -100,8 +100,6 @@ class GESTURE_DETECTION_EXPORT GestureProvider { void Fling(const MotionEvent& e, float velocity_x, float velocity_y); void Send(const GestureEventData& gesture); - void SendTapCancelIfNecessary(const MotionEvent& event); - void SendTapCancelIfNecessary(const GestureEventData& event); bool SendLongTapIfNecessary(const MotionEvent& event); void EndTouchScrollIfNecessary(const MotionEvent& event, bool send_scroll_end_event); @@ -121,15 +119,6 @@ class GESTURE_DETECTION_EXPORT GestureProvider { scoped_ptr<MotionEvent> current_down_event_; - // Whether a GESTURE_SHOW_PRESS was sent for the current touch sequence. - // Sending a GESTURE_TAP event will forward a GESTURE_SHOW_PRESS if one has - // not yet been sent. - bool needs_show_press_event_; - - // Whether a sent GESTURE_TAP_DOWN event has yet to be accompanied by a - // corresponding GESTURE_TAP, GESTURE_TAP_CANCEL or GESTURE_DOUBLE_TAP. - bool needs_tap_ending_event_; - // Whether the respective {SCROLL,PINCH}_BEGIN gestures have been terminated // with a {SCROLL,PINCH}_END. bool touch_scroll_in_progress_; diff --git a/ui/events/gesture_detection/gesture_provider_unittest.cc b/ui/events/gesture_detection/gesture_provider_unittest.cc index 6ec8a5b..0392acc 100644 --- a/ui/events/gesture_detection/gesture_provider_unittest.cc +++ b/ui/events/gesture_detection/gesture_provider_unittest.cc @@ -150,6 +150,8 @@ class GestureProviderTest : public testing::Test, public GestureProviderClient { gesture_provider_->SetMultiTouchSupportEnabled(false); } + bool HasDownEvent() const { return gesture_provider_->current_down_event(); } + protected: void CheckScrollEventSequenceForEndActionType( MotionEvent::Action end_action_type) { @@ -175,15 +177,13 @@ class GestureProviderTest : public testing::Test, public GestureProviderClient { EXPECT_TRUE(HasReceivedGesture(ET_GESTURE_SCROLL_BEGIN)); EXPECT_EQ(motion_event_id, GetMostRecentGestureEvent().motion_event_id); EXPECT_EQ(ET_GESTURE_SCROLL_UPDATE, GetMostRecentGestureEventType()); - ASSERT_EQ(4U, GetReceivedGestureCount()) << "Only TapDown, TapCancel, " + ASSERT_EQ(3U, GetReceivedGestureCount()) << "Only TapDown, " "ScrollBegin and ScrollBy " "should have been sent"; - EXPECT_EQ(ET_GESTURE_TAP_CANCEL, GetReceivedGesture(1).type); + EXPECT_EQ(ET_GESTURE_SCROLL_BEGIN, GetReceivedGesture(1).type); EXPECT_EQ(motion_event_id, GetReceivedGesture(1).motion_event_id); - EXPECT_EQ(ET_GESTURE_SCROLL_BEGIN, GetReceivedGesture(2).type); - EXPECT_EQ(motion_event_id, GetReceivedGesture(2).motion_event_id); - EXPECT_EQ(event_time + kOneSecond, GetReceivedGesture(2).time) + EXPECT_EQ(event_time + kOneSecond, GetReceivedGesture(1).time) << "ScrollBegin should have the time of the ACTION_MOVE"; event = ObtainMotionEvent( @@ -342,14 +342,14 @@ TEST_F(GestureProviderTest, FlingEventSequence) { 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(4U, GetReceivedGestureCount()); - ASSERT_EQ(ET_GESTURE_SCROLL_BEGIN, GetReceivedGesture(2).type); - EXPECT_EQ(motion_event_id, GetReceivedGesture(2).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(2).details.scroll_x_hint(); - int hint_y = GetReceivedGesture(2).details.scroll_y_hint(); + 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"; @@ -368,7 +368,7 @@ TEST_F(GestureProviderTest, FlingEventSequence) { << "FlingStart should have the time of the ACTION_UP"; } -TEST_F(GestureProviderTest, TapCancelledWhenWindowFocusLost) { +TEST_F(GestureProviderTest, GestureCancelledWhenWindowFocusLost) { const base::TimeTicks event_time = TimeTicks::Now(); MockMotionEvent event = @@ -381,12 +381,17 @@ TEST_F(GestureProviderTest, TapCancelledWhenWindowFocusLost) { EXPECT_TRUE(HasReceivedGesture(ET_GESTURE_SHOW_PRESS)); EXPECT_EQ(ET_GESTURE_LONG_PRESS, GetMostRecentGestureEventType()); - // The long press triggers window focus loss by opening a context menu + // The long press triggers window focus loss by opening a context menu. EXPECT_TRUE(CancelActiveTouchSequence()); - EXPECT_EQ(ET_GESTURE_TAP_CANCEL, GetMostRecentGestureEventType()); + 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, TapCancelledWhenScrollBegins) { +TEST_F(GestureProviderTest, NoTapAfterScrollBegins) { base::TimeTicks event_time = base::TimeTicks::Now(); MockMotionEvent event = @@ -400,9 +405,15 @@ TEST_F(GestureProviderTest, TapCancelledWhenScrollBegins) { kFakeCoordX + 50, kFakeCoordY + 50); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); - EXPECT_EQ(ET_GESTURE_SCROLL_UPDATE, GetMostRecentGestureEventType()); - EXPECT_TRUE(HasReceivedGesture(ET_GESTURE_TAP_CANCEL)); + + 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) { @@ -693,7 +704,6 @@ TEST_F(GestureProviderTest, GestureLongPressDoesNotPreventScrolling) { EXPECT_EQ(ET_GESTURE_SCROLL_UPDATE, GetMostRecentGestureEventType()); EXPECT_TRUE(HasReceivedGesture(ET_GESTURE_SCROLL_BEGIN)); - EXPECT_TRUE(HasReceivedGesture(ET_GESTURE_TAP_CANCEL)); event = ObtainMotionEvent(event_time + long_press_timeout, MotionEvent::ACTION_UP); @@ -910,6 +920,9 @@ TEST_F(GestureProviderTest, FixedPageScaleDuringDoubleTapDragZoom) { base::TimeTicks down_time_1 = TimeTicks::Now(); base::TimeTicks down_time_2 = down_time_1 + kOneMicrosecond * 2; + gesture_provider_->SetDoubleTapSupportForPageEnabled(true); + gesture_provider_->SetDoubleTapSupportForPlatformEnabled(true); + // Start a double-tap drag gesture. MockMotionEvent event = ObtainMotionEvent(down_time_1, MotionEvent::ACTION_DOWN); @@ -998,6 +1011,8 @@ TEST_F(GestureProviderTest, PinchZoom) { const int scaled_touch_slop = GetTouchSlop(); int motion_event_id = 0; + gesture_provider_->SetDoubleTapSupportForPageEnabled(false); + gesture_provider_->SetDoubleTapSupportForPlatformEnabled(true); gesture_provider_->SetMultiTouchSupportEnabled(true); int secondary_coord_x = kFakeCoordX + 20 * scaled_touch_slop; @@ -1009,6 +1024,9 @@ TEST_F(GestureProviderTest, PinchZoom) { EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); EXPECT_EQ(ET_GESTURE_TAP_DOWN, GetMostRecentGestureEventType()); + // 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, @@ -1030,6 +1048,9 @@ TEST_F(GestureProviderTest, PinchZoom) { secondary_coord_y); event.SetId(++motion_event_id); + // 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_TRUE(HasReceivedGesture(ET_GESTURE_PINCH_BEGIN)); @@ -1046,6 +1067,9 @@ TEST_F(GestureProviderTest, PinchZoom) { secondary_coord_y); event.SetId(++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)); @@ -1085,7 +1109,7 @@ TEST_F(GestureProviderTest, GesturesCancelledAfterLongPressCausesLostFocus) { EXPECT_EQ(ET_GESTURE_LONG_PRESS, GetMostRecentGestureEventType()); EXPECT_TRUE(CancelActiveTouchSequence()); - EXPECT_EQ(ET_GESTURE_TAP_CANCEL, GetMostRecentGestureEventType()); + EXPECT_FALSE(HasDownEvent()); event = ObtainMotionEvent(event_time + long_press_timeout, MotionEvent::ACTION_UP); @@ -1110,7 +1134,7 @@ TEST_F(GestureProviderTest, CancelActiveTouchSequence) { EXPECT_EQ(motion_event_id, GetMostRecentGestureEvent().motion_event_id); ASSERT_TRUE(CancelActiveTouchSequence()); - EXPECT_EQ(ET_GESTURE_TAP_CANCEL, GetMostRecentGestureEventType()); + EXPECT_FALSE(HasDownEvent()); EXPECT_EQ(motion_event_id, GetMostRecentGestureEvent().motion_event_id); // Subsequent MotionEvent's are dropped until ACTION_DOWN. @@ -1128,6 +1152,60 @@ TEST_F(GestureProviderTest, CancelActiveTouchSequence) { EXPECT_EQ(ET_GESTURE_TAP_DOWN, GetMostRecentGestureEventType()); } +TEST_F(GestureProviderTest, DoubleTapDragZoomCancelledOnSecondaryPointerDown) { + const base::TimeTicks down_time_1 = TimeTicks::Now(); + const base::TimeTicks down_time_2 = down_time_1 + kOneMicrosecond * 2; + + 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()); + + event = + ObtainMotionEvent(down_time_1 + kOneMicrosecond, MotionEvent::ACTION_UP); + gesture_provider_->OnTouchEvent(event); + EXPECT_EQ(ET_GESTURE_TAP_UNCONFIRMED, GetMostRecentGestureEventType()); + + event = ObtainMotionEvent(down_time_2, MotionEvent::ACTION_DOWN); + EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); + EXPECT_EQ(ET_GESTURE_TAP_DOWN, GetMostRecentGestureEventType()); + + 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()); + + 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()); + + 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()); +} + // Verify that gesture begin and gesture end events are dispatched correctly. TEST_F(GestureProviderTest, GestureBeginAndEnd) { SetBeginEndTypesEnabled(true); @@ -1178,16 +1256,14 @@ TEST_F(GestureProviderTest, GestureBeginAndEnd) { event = ObtainMotionEvent(event_time, MotionEvent::ACTION_DOWN); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); - EXPECT_EQ(ET_GESTURE_TAP_CANCEL, GetReceivedGesture(9).type); - EXPECT_EQ(ET_GESTURE_BEGIN, GetReceivedGesture(10).type); + EXPECT_EQ(ET_GESTURE_BEGIN, GetReceivedGesture(9).type); EXPECT_EQ(ET_GESTURE_TAP_DOWN, GetMostRecentGestureEventType()); - EXPECT_EQ(12U, GetReceivedGestureCount()); + EXPECT_EQ(11U, GetReceivedGestureCount()); event = ObtainMotionEvent(event_time, MotionEvent::ACTION_CANCEL); EXPECT_TRUE(gesture_provider_->OnTouchEvent(event)); - EXPECT_EQ(ET_GESTURE_TAP_CANCEL, GetReceivedGesture(12).type); EXPECT_EQ(ET_GESTURE_END, GetMostRecentGestureEventType()); - EXPECT_EQ(14U, GetReceivedGestureCount()); + EXPECT_EQ(12U, GetReceivedGestureCount()); } diff --git a/ui/events/gesture_detection/scale_gesture_detector.cc b/ui/events/gesture_detection/scale_gesture_detector.cc index e6c35b8..bf8a0d3 100644 --- a/ui/events/gesture_detection/scale_gesture_detector.cc +++ b/ui/events/gesture_detection/scale_gesture_detector.cc @@ -92,7 +92,9 @@ bool ScaleGestureDetector::OnTouchEvent(const MotionEvent& event) { } const bool stream_complete = - action == MotionEvent::ACTION_UP || action == MotionEvent::ACTION_CANCEL; + action == MotionEvent::ACTION_UP || + action == MotionEvent::ACTION_CANCEL || + (action == MotionEvent::ACTION_POINTER_DOWN && InDoubleTapMode()); if (action == MotionEvent::ACTION_DOWN || stream_complete) { // Reset any scale in progress with the listener. @@ -103,8 +105,7 @@ bool ScaleGestureDetector::OnTouchEvent(const MotionEvent& event) { in_progress_ = false; initial_span_ = 0; double_tap_mode_ = DOUBLE_TAP_MODE_NONE; - } else if (double_tap_mode_ == DOUBLE_TAP_MODE_IN_PROGRESS && - stream_complete) { + } else if (InDoubleTapMode() && stream_complete) { in_progress_ = false; initial_span_ = 0; double_tap_mode_ = DOUBLE_TAP_MODE_NONE; @@ -129,7 +130,7 @@ bool ScaleGestureDetector::OnTouchEvent(const MotionEvent& event) { const int div = pointer_up ? count - 1 : count; float focus_x; float focus_y; - if (double_tap_mode_ == DOUBLE_TAP_MODE_IN_PROGRESS) { + if (InDoubleTapMode()) { // In double tap mode, the focal pt is always where the double tap // gesture started. focus_x = double_tap_focus_x_; diff --git a/ui/events/gesture_detection/touch_disposition_gesture_filter.cc b/ui/events/gesture_detection/touch_disposition_gesture_filter.cc index f3e8514b..f637d7f 100644 --- a/ui/events/gesture_detection/touch_disposition_gesture_filter.cc +++ b/ui/events/gesture_detection/touch_disposition_gesture_filter.cc @@ -153,13 +153,8 @@ void TouchDispositionGestureFilter::OnTouchEventAck(bool event_consumed) { if (IsEmpty() || (Head().empty() && sequences_.size() == 1)) return; - if (Head().empty()) { - CancelTapIfNecessary(); - CancelFlingIfNecessary(); - EndScrollIfNecessary(); - state_ = GestureHandlingState(); - sequences_.pop(); - } + if (Head().empty()) + PopGestureSequence(); GestureSequence& sequence = Head(); @@ -171,7 +166,8 @@ void TouchDispositionGestureFilter::OnTouchEventAck(bool event_consumed) { DCHECK_NE(packet.gesture_source(), GestureEventDataPacket::UNDEFINED); DCHECK_NE(packet.gesture_source(), GestureEventDataPacket::INVALID); - if (packet.gesture_source() != GestureEventDataPacket::TOUCH_TIMEOUT) { + GestureEventDataPacket::GestureSource source = packet.gesture_source(); + if (source != GestureEventDataPacket::TOUCH_TIMEOUT) { // We should handle at most one non-timeout based packet. if (touch_packet_for_current_ack_handled) break; @@ -201,6 +197,8 @@ void TouchDispositionGestureFilter::FilterAndSendPacket( } SendGesture(gesture); } + if (packet.gesture_source() == GestureEventDataPacket::TOUCH_SEQUENCE_END) + EndScrollIfNecessary(); } void TouchDispositionGestureFilter::SendGesture(const GestureEventData& event) { @@ -208,18 +206,37 @@ void TouchDispositionGestureFilter::SendGesture(const GestureEventData& event) { // utility class. switch (event.type) { case ET_GESTURE_LONG_TAP: + if (!needs_tap_ending_event_) + return; CancelTapIfNecessary(); CancelFlingIfNecessary(); break; case ET_GESTURE_TAP_DOWN: DCHECK(!needs_tap_ending_event_); ending_event_motion_event_id_ = event.motion_event_id; + needs_show_press_event_ = true; needs_tap_ending_event_ = true; break; + case ET_GESTURE_SHOW_PRESS: + if (!needs_show_press_event_) + return; + needs_show_press_event_ = false; + break; + case ET_GESTURE_DOUBLE_TAP: + CancelTapIfNecessary(); + needs_show_press_event_ = false; + break; case ET_GESTURE_TAP: + if (needs_show_press_event_) { + GestureEventData show_press_event(event); + show_press_event.type = ET_GESTURE_SHOW_PRESS; + SendGesture(show_press_event); + DCHECK(!needs_show_press_event_); + } + needs_tap_ending_event_ = false; + break; case ET_GESTURE_TAP_CANCEL: - case ET_GESTURE_TAP_UNCONFIRMED: - case ET_GESTURE_DOUBLE_TAP: + needs_show_press_event_ = false; needs_tap_ending_event_ = false; break; case ET_GESTURE_SCROLL_BEGIN: @@ -274,6 +291,15 @@ void TouchDispositionGestureFilter::EndScrollIfNecessary() { DCHECK(!needs_scroll_ending_event_); } +void TouchDispositionGestureFilter::PopGestureSequence() { + DCHECK(Head().empty()); + CancelTapIfNecessary(); + CancelFlingIfNecessary(); + EndScrollIfNecessary(); + state_ = GestureHandlingState(); + sequences_.pop(); +} + TouchDispositionGestureFilter::GestureSequence& TouchDispositionGestureFilter::Head() { DCHECK(!sequences_.empty()); diff --git a/ui/events/gesture_detection/touch_disposition_gesture_filter.h b/ui/events/gesture_detection/touch_disposition_gesture_filter.h index cb511ff..6d5e51f 100644 --- a/ui/events/gesture_detection/touch_disposition_gesture_filter.h +++ b/ui/events/gesture_detection/touch_disposition_gesture_filter.h @@ -81,6 +81,7 @@ class GESTURE_DETECTION_EXPORT TouchDispositionGestureFilter { void CancelTapIfNecessary(); void CancelFlingIfNecessary(); void EndScrollIfNecessary(); + void PopGestureSequence(); GestureSequence& Head(); GestureSequence& Tail(); @@ -94,6 +95,7 @@ class GESTURE_DETECTION_EXPORT TouchDispositionGestureFilter { // GestureFlingCancel when a user taps following a GestureFlingStart. int ending_event_motion_event_id_; bool needs_tap_ending_event_; + bool needs_show_press_event_; bool needs_fling_ending_event_; bool needs_scroll_ending_event_; diff --git a/ui/events/gesture_detection/touch_disposition_gesture_filter_unittest.cc b/ui/events/gesture_detection/touch_disposition_gesture_filter_unittest.cc index 562d2dd..4491229 100644 --- a/ui/events/gesture_detection/touch_disposition_gesture_filter_unittest.cc +++ b/ui/events/gesture_detection/touch_disposition_gesture_filter_unittest.cc @@ -664,7 +664,8 @@ TEST_F(TouchDispositionGestureFilterTest, PushGesture(ET_GESTURE_TAP); ReleaseTouchPoint(); SendTouchNotConsumedAck(); - EXPECT_TRUE(GesturesMatch(Gestures(ET_GESTURE_TAP), + EXPECT_TRUE(GesturesMatch(Gestures(ET_GESTURE_SHOW_PRESS, + ET_GESTURE_TAP), GetAndResetSentGestures())); // The tap should not be cancelled as it was terminated by a |ET_GESTURE_TAP|. @@ -676,9 +677,11 @@ TEST_F(TouchDispositionGestureFilterTest, TEST_F(TouchDispositionGestureFilterTest, TimeoutGestures) { // If the sequence is allowed, and there are no preceding gestures, the // timeout gestures should be forwarded immediately. + PushGesture(ET_GESTURE_TAP_DOWN); PressTouchPoint(1, 1); SendTouchNotConsumedAck(); - EXPECT_FALSE(GesturesSent()); + EXPECT_TRUE(GesturesMatch(Gestures(ET_GESTURE_TAP_DOWN), + GetAndResetSentGestures())); SendTimeoutGesture(ET_GESTURE_SHOW_PRESS); EXPECT_TRUE(GesturesMatch(Gestures(ET_GESTURE_SHOW_PRESS), @@ -688,11 +691,16 @@ TEST_F(TouchDispositionGestureFilterTest, TimeoutGestures) { EXPECT_TRUE(GesturesMatch(Gestures(ET_GESTURE_LONG_PRESS), GetAndResetSentGestures())); + PushGesture(ET_GESTURE_LONG_TAP); ReleaseTouchPoint(); SendTouchNotConsumedAck(); + EXPECT_TRUE(GesturesMatch(Gestures(ET_GESTURE_TAP_CANCEL, + ET_GESTURE_LONG_TAP), + GetAndResetSentGestures())); // If the sequence is disallowed, and there are no preceding gestures, the // timeout gestures should be dropped immediately. + PushGesture(ET_GESTURE_TAP_DOWN); PressTouchPoint(1, 1); SendTouchConsumedAck(); EXPECT_FALSE(GesturesSent()); @@ -704,6 +712,7 @@ TEST_F(TouchDispositionGestureFilterTest, TimeoutGestures) { // If the sequence has a pending ack, the timeout gestures should // remain queued until the ack is received. + PushGesture(ET_GESTURE_TAP_DOWN); PressTouchPoint(1, 1); EXPECT_FALSE(GesturesSent()); @@ -711,7 +720,8 @@ TEST_F(TouchDispositionGestureFilterTest, TimeoutGestures) { EXPECT_FALSE(GesturesSent()); SendTouchNotConsumedAck(); - EXPECT_TRUE(GesturesMatch(Gestures(ET_GESTURE_LONG_PRESS), + EXPECT_TRUE(GesturesMatch(Gestures(ET_GESTURE_TAP_DOWN, + ET_GESTURE_LONG_PRESS), GetAndResetSentGestures())); } @@ -786,4 +796,69 @@ TEST_F(TouchDispositionGestureFilterTest, TimeoutEventAfterRelease) { GetAndResetSentGestures())); } +TEST_F(TouchDispositionGestureFilterTest, ShowPressInsertedBeforeTap) { + PushGesture(ET_GESTURE_TAP_DOWN); + PressTouchPoint(1, 1); + SendTouchNotConsumedAck(); + EXPECT_TRUE(GesturesMatch(Gestures(ET_GESTURE_TAP_DOWN), + GetAndResetSentGestures())); + + SendTimeoutGesture(ET_GESTURE_TAP_UNCONFIRMED); + EXPECT_TRUE(GesturesMatch(Gestures(ET_GESTURE_TAP_UNCONFIRMED), + GetAndResetSentGestures())); + + PushGesture(ET_GESTURE_TAP); + ReleaseTouchPoint(); + SendTouchNotConsumedAck(); + EXPECT_TRUE(GesturesMatch(Gestures(ET_GESTURE_SHOW_PRESS, + ET_GESTURE_TAP), + GetAndResetSentGestures())); +} + +TEST_F(TouchDispositionGestureFilterTest, ShowPressNotInsertedIfAlreadySent) { + PushGesture(ET_GESTURE_TAP_DOWN); + PressTouchPoint(1, 1); + SendTouchNotConsumedAck(); + EXPECT_TRUE(GesturesMatch(Gestures(ET_GESTURE_TAP_DOWN), + GetAndResetSentGestures())); + + SendTimeoutGesture(ET_GESTURE_SHOW_PRESS); + EXPECT_TRUE(GesturesMatch(Gestures(ET_GESTURE_SHOW_PRESS), + GetAndResetSentGestures())); + + PushGesture(ET_GESTURE_TAP); + ReleaseTouchPoint(); + SendTouchNotConsumedAck(); + EXPECT_TRUE(GesturesMatch(Gestures(ET_GESTURE_TAP), + GetAndResetSentGestures())); +} + +TEST_F(TouchDispositionGestureFilterTest, TapAndScrollCancelledOnTouchCancel) { + PushGesture(ET_GESTURE_TAP_DOWN); + PressTouchPoint(1, 1); + SendTouchNotConsumedAck(); + EXPECT_TRUE(GesturesMatch(Gestures(ET_GESTURE_TAP_DOWN), + GetAndResetSentGestures())); + + // A cancellation motion event should cancel the tap (though the TAP_CANCEL + // will not be dispatched until the following touch sequence). + CancelTouchPoint(); + SendTouchNotConsumedAck(); + EXPECT_FALSE(GesturesSent()); + + PushGesture(ET_GESTURE_SCROLL_BEGIN); + PressTouchPoint(1, 1); + SendTouchNotConsumedAck(); + EXPECT_TRUE(GesturesMatch(Gestures(ET_GESTURE_TAP_CANCEL, + ET_GESTURE_SCROLL_BEGIN), + GetAndResetSentGestures())); + + // A cancellation motion event should end the scroll, even if the touch was + // consumed. + CancelTouchPoint(); + SendTouchConsumedAck(); + EXPECT_TRUE(GesturesMatch(Gestures(ET_GESTURE_SCROLL_END), + GetAndResetSentGestures())); +} + } // namespace ui |