summaryrefslogtreecommitdiffstats
path: root/ui/events
diff options
context:
space:
mode:
Diffstat (limited to 'ui/events')
-rw-r--r--ui/events/gesture_detection/gesture_event_data_packet.h2
-rw-r--r--ui/events/gesture_detection/gesture_provider.cc84
-rw-r--r--ui/events/gesture_detection/gesture_provider.h11
-rw-r--r--ui/events/gesture_detection/gesture_provider_unittest.cc124
-rw-r--r--ui/events/gesture_detection/scale_gesture_detector.cc9
-rw-r--r--ui/events/gesture_detection/touch_disposition_gesture_filter.cc46
-rw-r--r--ui/events/gesture_detection/touch_disposition_gesture_filter.h2
-rw-r--r--ui/events/gesture_detection/touch_disposition_gesture_filter_unittest.cc81
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