Implementing the dispatch of the swipe gesture for one-finger touch swipes.
[chromium-blink-merge.git] / ui / events / gesture_detection / gesture_provider.cc
blob8b9000ddad1e27d906fb1759a3a392c85ab0e372
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "ui/events/gesture_detection/gesture_provider.h"
7 #include <cmath>
9 #include "base/auto_reset.h"
10 #include "base/debug/trace_event.h"
11 #include "ui/events/event_constants.h"
12 #include "ui/events/gesture_detection/gesture_event_data.h"
13 #include "ui/events/gesture_detection/motion_event.h"
15 namespace ui {
16 namespace {
18 // Double-tap drag zoom sensitivity (speed).
19 const float kDoubleTapDragZoomSpeed = 0.005f;
21 const char* GetMotionEventActionName(MotionEvent::Action action) {
22 switch(action) {
23 case MotionEvent::ACTION_POINTER_DOWN: return "ACTION_POINTER_DOWN";
24 case MotionEvent::ACTION_POINTER_UP: return "ACTION_POINTER_UP";
25 case MotionEvent::ACTION_DOWN: return "ACTION_DOWN";
26 case MotionEvent::ACTION_UP: return "ACTION_UP";
27 case MotionEvent::ACTION_CANCEL: return "ACTION_CANCEL";
28 case MotionEvent::ACTION_MOVE: return "ACTION_MOVE";
30 return "";
33 gfx::RectF GetBoundingBox(const MotionEvent& event) {
34 gfx::RectF bounds;
35 for (size_t i = 0; i < event.GetPointerCount(); ++i) {
36 float diameter = event.GetTouchMajor(i);
37 bounds.Union(gfx::RectF(event.GetX(i) - diameter / 2,
38 event.GetY(i) - diameter / 2,
39 diameter,
40 diameter));
42 return bounds;
45 GestureEventData CreateGesture(EventType type,
46 int motion_event_id,
47 base::TimeTicks time,
48 float x,
49 float y,
50 size_t touch_point_count,
51 const gfx::RectF& bounding_box,
52 const GestureEventDetails& details) {
53 return GestureEventData(type,
54 motion_event_id,
55 time,
58 static_cast<int>(touch_point_count),
59 bounding_box,
60 details);
63 GestureEventData CreateGesture(EventType type,
64 int motion_event_id,
65 base::TimeTicks time,
66 float x,
67 float y,
68 size_t touch_point_count,
69 const gfx::RectF& bounding_box) {
70 return GestureEventData(type,
71 motion_event_id,
72 time,
75 static_cast<int>(touch_point_count),
76 bounding_box);
79 GestureEventData CreateGesture(EventType type,
80 const MotionEvent& event,
81 const GestureEventDetails& details) {
82 return CreateGesture(type,
83 event.GetId(),
84 event.GetEventTime(),
85 event.GetX(),
86 event.GetY(),
87 event.GetPointerCount(),
88 GetBoundingBox(event),
89 details);
92 GestureEventData CreateGesture(EventType type,
93 const MotionEvent& event) {
94 return CreateGesture(type,
95 event.GetId(),
96 event.GetEventTime(),
97 event.GetX(),
98 event.GetY(),
99 event.GetPointerCount(),
100 GetBoundingBox(event));
103 GestureEventDetails CreateTapGestureDetails(EventType type,
104 const MotionEvent& event) {
105 // Set the tap count to 1 even for ET_GESTURE_DOUBLE_TAP, in order to be
106 // consistent with double tap behavior on a mobile viewport. See
107 // crbug.com/234986 for context.
108 GestureEventDetails tap_details(type, 1, 0);
109 return tap_details;
112 } // namespace
114 // GestureProvider:::Config
116 GestureProvider::Config::Config()
117 : display(gfx::Display::kInvalidDisplayID, gfx::Rect(1, 1)),
118 disable_click_delay(false),
119 gesture_begin_end_types_enabled(false) {}
121 GestureProvider::Config::~Config() {}
123 // GestureProvider::ScaleGestureListener
125 class GestureProvider::ScaleGestureListenerImpl
126 : public ScaleGestureDetector::ScaleGestureListener {
127 public:
128 ScaleGestureListenerImpl(const ScaleGestureDetector::Config& config,
129 GestureProvider* provider)
130 : scale_gesture_detector_(config, this),
131 provider_(provider),
132 ignore_multitouch_events_(false),
133 pinch_event_sent_(false),
134 min_pinch_update_span_delta_(config.min_pinch_update_span_delta) {}
136 bool OnTouchEvent(const MotionEvent& event) {
137 // TODO: Need to deal with multi-touch transition.
138 const bool in_scale_gesture = IsScaleGestureDetectionInProgress();
139 bool handled = scale_gesture_detector_.OnTouchEvent(event);
140 if (!in_scale_gesture &&
141 (event.GetAction() == MotionEvent::ACTION_UP ||
142 event.GetAction() == MotionEvent::ACTION_CANCEL)) {
143 return false;
145 return handled;
148 // ScaleGestureDetector::ScaleGestureListener implementation.
149 virtual bool OnScaleBegin(const ScaleGestureDetector& detector,
150 const MotionEvent& e) OVERRIDE {
151 if (ignore_multitouch_events_ && !detector.InDoubleTapMode())
152 return false;
153 pinch_event_sent_ = false;
154 return true;
157 virtual void OnScaleEnd(const ScaleGestureDetector& detector,
158 const MotionEvent& e) OVERRIDE {
159 if (!pinch_event_sent_)
160 return;
161 provider_->Send(CreateGesture(ET_GESTURE_PINCH_END,
162 e.GetId(),
163 detector.GetEventTime(),
166 e.GetPointerCount(),
167 GetBoundingBox(e)));
168 pinch_event_sent_ = false;
171 virtual bool OnScale(const ScaleGestureDetector& detector,
172 const MotionEvent& e) OVERRIDE {
173 if (ignore_multitouch_events_ && !detector.InDoubleTapMode())
174 return false;
175 if (!pinch_event_sent_) {
176 pinch_event_sent_ = true;
177 provider_->Send(CreateGesture(ET_GESTURE_PINCH_BEGIN,
178 e.GetId(),
179 detector.GetEventTime(),
180 detector.GetFocusX(),
181 detector.GetFocusY(),
182 e.GetPointerCount(),
183 GetBoundingBox(e)));
186 if (std::abs(detector.GetCurrentSpan() - detector.GetPreviousSpan()) <
187 min_pinch_update_span_delta_) {
188 return false;
191 float scale = detector.GetScaleFactor();
192 if (scale == 1)
193 return true;
195 if (detector.InDoubleTapMode()) {
196 // Relative changes in the double-tap scale factor computed by |detector|
197 // diminish as the touch moves away from the original double-tap focus.
198 // For historical reasons, Chrome has instead adopted a scale factor
199 // computation that is invariant to the focal distance, where
200 // the scale delta remains constant if the touch velocity is constant.
201 float dy =
202 (detector.GetCurrentSpanY() - detector.GetPreviousSpanY()) * 0.5f;
203 scale = std::pow(scale > 1 ? 1.0f + kDoubleTapDragZoomSpeed
204 : 1.0f - kDoubleTapDragZoomSpeed,
205 std::abs(dy));
207 GestureEventDetails pinch_details(ET_GESTURE_PINCH_UPDATE, scale, 0);
208 provider_->Send(CreateGesture(ET_GESTURE_PINCH_UPDATE,
209 e.GetId(),
210 detector.GetEventTime(),
211 detector.GetFocusX(),
212 detector.GetFocusY(),
213 e.GetPointerCount(),
214 GetBoundingBox(e),
215 pinch_details));
216 return true;
219 void SetDoubleTapEnabled(bool enabled) {
220 DCHECK(!IsDoubleTapInProgress());
221 scale_gesture_detector_.SetQuickScaleEnabled(enabled);
224 void SetMultiTouchEnabled(bool enabled) {
225 // Note that returning false from OnScaleBegin / OnScale makes the
226 // gesture detector not to emit further scaling notifications
227 // related to this gesture. Thus, if detector events are enabled in
228 // the middle of the gesture, we don't need to do anything.
229 ignore_multitouch_events_ = !enabled;
232 bool IsDoubleTapInProgress() const {
233 return IsScaleGestureDetectionInProgress() && InDoubleTapMode();
236 bool IsScaleGestureDetectionInProgress() const {
237 return scale_gesture_detector_.IsInProgress();
240 private:
241 bool InDoubleTapMode() const {
242 return scale_gesture_detector_.InDoubleTapMode();
245 ScaleGestureDetector scale_gesture_detector_;
247 GestureProvider* const provider_;
249 // Completely silence multi-touch (pinch) scaling events. Used in WebView when
250 // zoom support is turned off.
251 bool ignore_multitouch_events_;
253 // Whether any pinch zoom event has been sent to native.
254 bool pinch_event_sent_;
256 // The minimum change in span required before this is considered a pinch. See
257 // crbug.com/373318.
258 float min_pinch_update_span_delta_;
260 DISALLOW_COPY_AND_ASSIGN(ScaleGestureListenerImpl);
263 // GestureProvider::GestureListener
265 class GestureProvider::GestureListenerImpl
266 : public GestureDetector::GestureListener,
267 public GestureDetector::DoubleTapListener {
268 public:
269 GestureListenerImpl(
270 const gfx::Display& display,
271 const GestureDetector::Config& gesture_detector_config,
272 bool disable_click_delay,
273 GestureProvider* provider)
274 : gesture_detector_(gesture_detector_config, this, this),
275 snap_scroll_controller_(display),
276 provider_(provider),
277 disable_click_delay_(disable_click_delay),
278 touch_slop_(gesture_detector_config.touch_slop),
279 double_tap_timeout_(gesture_detector_config.double_tap_timeout),
280 ignore_single_tap_(false),
281 seen_first_scroll_event_(false) {}
283 virtual ~GestureListenerImpl() {}
285 bool OnTouchEvent(const MotionEvent& e,
286 bool is_scale_gesture_detection_in_progress) {
287 snap_scroll_controller_.SetSnapScrollingMode(
288 e, is_scale_gesture_detection_in_progress);
290 if (is_scale_gesture_detection_in_progress)
291 SetIgnoreSingleTap(true);
293 if (e.GetAction() == MotionEvent::ACTION_DOWN)
294 gesture_detector_.set_longpress_enabled(true);
296 return gesture_detector_.OnTouchEvent(e);
299 // GestureDetector::GestureListener implementation.
300 virtual bool OnDown(const MotionEvent& e) OVERRIDE {
301 current_down_time_ = e.GetEventTime();
302 ignore_single_tap_ = false;
303 seen_first_scroll_event_ = false;
305 GestureEventDetails tap_details(ET_GESTURE_TAP_DOWN, 0, 0);
306 provider_->Send(CreateGesture(ET_GESTURE_TAP_DOWN, e, tap_details));
308 // Return true to indicate that we want to handle touch.
309 return true;
312 virtual bool OnScroll(const MotionEvent& e1,
313 const MotionEvent& e2,
314 float raw_distance_x,
315 float raw_distance_y) OVERRIDE {
316 float distance_x = raw_distance_x;
317 float distance_y = raw_distance_y;
318 if (!seen_first_scroll_event_) {
319 // Remove the touch slop region from the first scroll event to avoid a
320 // jump.
321 seen_first_scroll_event_ = true;
322 double distance =
323 std::sqrt(distance_x * distance_x + distance_y * distance_y);
324 double epsilon = 1e-3;
325 if (distance > epsilon) {
326 double ratio = std::max(0., distance - touch_slop_) / distance;
327 distance_x *= ratio;
328 distance_y *= ratio;
331 snap_scroll_controller_.UpdateSnapScrollMode(distance_x, distance_y);
332 if (snap_scroll_controller_.IsSnappingScrolls()) {
333 if (snap_scroll_controller_.IsSnapHorizontal()) {
334 distance_y = 0;
335 } else {
336 distance_x = 0;
340 if (!provider_->IsScrollInProgress()) {
341 // Note that scroll start hints are in distance traveled, where
342 // scroll deltas are in the opposite direction.
343 GestureEventDetails scroll_details(
344 ET_GESTURE_SCROLL_BEGIN, -raw_distance_x, -raw_distance_y);
346 // Use the co-ordinates from the touch down, as these co-ordinates are
347 // used to determine which layer the scroll should affect.
348 provider_->Send(CreateGesture(ET_GESTURE_SCROLL_BEGIN,
349 e2.GetId(),
350 e2.GetEventTime(),
351 e1.GetX(),
352 e1.GetY(),
353 e2.GetPointerCount(),
354 GetBoundingBox(e2),
355 scroll_details));
358 if (distance_x || distance_y) {
359 GestureEventDetails scroll_details(
360 ET_GESTURE_SCROLL_UPDATE, -distance_x, -distance_y);
361 provider_->Send(
362 CreateGesture(ET_GESTURE_SCROLL_UPDATE, e2, scroll_details));
365 return true;
368 virtual bool OnFling(const MotionEvent& e1,
369 const MotionEvent& e2,
370 float velocity_x,
371 float velocity_y) OVERRIDE {
372 if (snap_scroll_controller_.IsSnappingScrolls()) {
373 if (snap_scroll_controller_.IsSnapHorizontal()) {
374 velocity_y = 0;
375 } else {
376 velocity_x = 0;
380 provider_->Fling(e2, velocity_x, velocity_y);
381 return true;
384 virtual bool OnSwipe(const MotionEvent& e1,
385 const MotionEvent& e2,
386 float velocity_x,
387 float velocity_y) OVERRIDE {
388 GestureEventDetails swipe_details(ET_GESTURE_SWIPE, velocity_x, velocity_y);
389 provider_->Send(CreateGesture(ET_GESTURE_SWIPE, e2, swipe_details));
390 return true;
393 virtual bool OnTwoFingerTap(const MotionEvent& e1,
394 const MotionEvent& e2) OVERRIDE {
395 // The location of the two finger tap event should be the location of the
396 // primary pointer.
397 GestureEventDetails two_finger_tap_details(ET_GESTURE_TWO_FINGER_TAP,
398 e1.GetTouchMajor(),
399 e1.GetTouchMajor());
400 provider_->Send(CreateGesture(ET_GESTURE_TWO_FINGER_TAP,
401 e2.GetId(),
402 e2.GetEventTime(),
403 e1.GetX(),
404 e1.GetY(),
405 e2.GetPointerCount(),
406 GetBoundingBox(e2),
407 two_finger_tap_details));
408 return true;
411 virtual void OnShowPress(const MotionEvent& e) OVERRIDE {
412 GestureEventDetails show_press_details(ET_GESTURE_SHOW_PRESS, 0, 0);
413 provider_->Send(
414 CreateGesture(ET_GESTURE_SHOW_PRESS, e, show_press_details));
417 virtual bool OnSingleTapUp(const MotionEvent& e) OVERRIDE {
418 // This is a hack to address the issue where user hovers
419 // over a link for longer than double_tap_timeout_, then
420 // OnSingleTapConfirmed() is not triggered. But we still
421 // want to trigger the tap event at UP. So we override
422 // OnSingleTapUp() in this case. This assumes singleTapUp
423 // gets always called before singleTapConfirmed.
424 if (!ignore_single_tap_) {
425 if (e.GetEventTime() - current_down_time_ > double_tap_timeout_) {
426 return OnSingleTapConfirmed(e);
427 } else if (!IsDoubleTapEnabled() || disable_click_delay_) {
428 // If double-tap has been disabled, there is no need to wait
429 // for the double-tap timeout.
430 return OnSingleTapConfirmed(e);
431 } else {
432 // Notify Blink about this tapUp event anyway, when none of the above
433 // conditions applied.
434 provider_->Send(CreateGesture(
435 ET_GESTURE_TAP_UNCONFIRMED,
437 CreateTapGestureDetails(ET_GESTURE_TAP_UNCONFIRMED, e)));
441 return provider_->SendLongTapIfNecessary(e);
444 // GestureDetector::DoubleTapListener implementation.
445 virtual bool OnSingleTapConfirmed(const MotionEvent& e) OVERRIDE {
446 // Long taps in the edges of the screen have their events delayed by
447 // ContentViewHolder for tab swipe operations. As a consequence of the delay
448 // this method might be called after receiving the up event.
449 // These corner cases should be ignored.
450 if (ignore_single_tap_)
451 return true;
453 ignore_single_tap_ = true;
455 provider_->Send(CreateGesture(
456 ET_GESTURE_TAP, e, CreateTapGestureDetails(ET_GESTURE_TAP, e)));
457 return true;
460 virtual bool OnDoubleTap(const MotionEvent& e) OVERRIDE { return false; }
462 virtual bool OnDoubleTapEvent(const MotionEvent& e) OVERRIDE {
463 switch (e.GetAction()) {
464 case MotionEvent::ACTION_DOWN:
465 gesture_detector_.set_longpress_enabled(false);
466 break;
468 case MotionEvent::ACTION_UP:
469 if (!provider_->IsPinchInProgress() &&
470 !provider_->IsScrollInProgress()) {
471 provider_->Send(
472 CreateGesture(ET_GESTURE_DOUBLE_TAP,
474 CreateTapGestureDetails(ET_GESTURE_DOUBLE_TAP, e)));
475 return true;
477 break;
478 default:
479 break;
481 return false;
484 virtual bool OnLongPress(const MotionEvent& e) OVERRIDE {
485 DCHECK(!IsDoubleTapInProgress());
486 SetIgnoreSingleTap(true);
488 GestureEventDetails long_press_details(ET_GESTURE_LONG_PRESS, 0, 0);
489 provider_->Send(
490 CreateGesture(ET_GESTURE_LONG_PRESS, e, long_press_details));
492 // Returning true puts the GestureDetector in "longpress" mode, disabling
493 // further scrolling. This is undesirable, as it is quite common for a
494 // longpress gesture to fire on content that won't trigger a context menu.
495 return false;
498 void SetDoubleTapEnabled(bool enabled) {
499 DCHECK(!IsDoubleTapInProgress());
500 gesture_detector_.SetDoubleTapListener(enabled ? this : NULL);
503 bool IsDoubleTapInProgress() const {
504 return gesture_detector_.is_double_tapping();
507 private:
508 void SetIgnoreSingleTap(bool value) { ignore_single_tap_ = value; }
510 bool IsDoubleTapEnabled() const {
511 return gesture_detector_.has_doubletap_listener();
514 GestureDetector gesture_detector_;
515 SnapScrollController snap_scroll_controller_;
517 GestureProvider* const provider_;
519 // Whether the click delay should always be disabled by sending clicks for
520 // double-tap gestures.
521 const bool disable_click_delay_;
523 const float touch_slop_;
525 const base::TimeDelta double_tap_timeout_;
527 base::TimeTicks current_down_time_;
529 // TODO(klobag): This is to avoid a bug in GestureDetector. With multi-touch,
530 // always_in_tap_region_ is not reset. So when the last finger is up,
531 // OnSingleTapUp() will be mistakenly fired.
532 bool ignore_single_tap_;
534 // Used to remove the touch slop from the initial scroll event in a scroll
535 // gesture.
536 bool seen_first_scroll_event_;
538 DISALLOW_COPY_AND_ASSIGN(GestureListenerImpl);
541 // GestureProvider
543 GestureProvider::GestureProvider(const Config& config,
544 GestureProviderClient* client)
545 : client_(client),
546 touch_scroll_in_progress_(false),
547 pinch_in_progress_(false),
548 double_tap_support_for_page_(true),
549 double_tap_support_for_platform_(true),
550 gesture_begin_end_types_enabled_(config.gesture_begin_end_types_enabled) {
551 DCHECK(client);
552 InitGestureDetectors(config);
555 GestureProvider::~GestureProvider() {}
557 bool GestureProvider::OnTouchEvent(const MotionEvent& event) {
558 TRACE_EVENT1("input", "GestureProvider::OnTouchEvent",
559 "action", GetMotionEventActionName(event.GetAction()));
561 DCHECK_NE(0u, event.GetPointerCount());
563 if (!CanHandle(event))
564 return false;
566 const bool in_scale_gesture =
567 scale_gesture_listener_->IsScaleGestureDetectionInProgress();
569 OnTouchEventHandlingBegin(event);
570 gesture_listener_->OnTouchEvent(event, in_scale_gesture);
571 scale_gesture_listener_->OnTouchEvent(event);
572 OnTouchEventHandlingEnd(event);
573 return true;
576 void GestureProvider::SetMultiTouchZoomSupportEnabled(bool enabled) {
577 scale_gesture_listener_->SetMultiTouchEnabled(enabled);
580 void GestureProvider::SetDoubleTapSupportForPlatformEnabled(bool enabled) {
581 if (double_tap_support_for_platform_ == enabled)
582 return;
583 double_tap_support_for_platform_ = enabled;
584 UpdateDoubleTapDetectionSupport();
587 void GestureProvider::SetDoubleTapSupportForPageEnabled(bool enabled) {
588 if (double_tap_support_for_page_ == enabled)
589 return;
590 double_tap_support_for_page_ = enabled;
591 UpdateDoubleTapDetectionSupport();
594 bool GestureProvider::IsScrollInProgress() const {
595 // TODO(wangxianzhu): Also return true when fling is active once the UI knows
596 // exactly when the fling ends.
597 return touch_scroll_in_progress_;
600 bool GestureProvider::IsPinchInProgress() const { return pinch_in_progress_; }
602 bool GestureProvider::IsDoubleTapInProgress() const {
603 return gesture_listener_->IsDoubleTapInProgress() ||
604 scale_gesture_listener_->IsDoubleTapInProgress();
607 void GestureProvider::InitGestureDetectors(const Config& config) {
608 TRACE_EVENT0("input", "GestureProvider::InitGestureDetectors");
609 gesture_listener_.reset(
610 new GestureListenerImpl(config.display,
611 config.gesture_detector_config,
612 config.disable_click_delay,
613 this));
615 scale_gesture_listener_.reset(
616 new ScaleGestureListenerImpl(config.scale_gesture_detector_config, this));
618 UpdateDoubleTapDetectionSupport();
621 bool GestureProvider::CanHandle(const MotionEvent& event) const {
622 return event.GetAction() == MotionEvent::ACTION_DOWN || current_down_event_;
625 void GestureProvider::Fling(const MotionEvent& event,
626 float velocity_x,
627 float velocity_y) {
628 if (!velocity_x && !velocity_y) {
629 EndTouchScrollIfNecessary(event, true);
630 return;
633 if (!touch_scroll_in_progress_) {
634 // The native side needs a ET_GESTURE_SCROLL_BEGIN before
635 // ET_SCROLL_FLING_START to send the fling to the correct target. Send if it
636 // has not sent. The distance traveled in one second is a reasonable scroll
637 // start hint.
638 GestureEventDetails scroll_details(
639 ET_GESTURE_SCROLL_BEGIN, velocity_x, velocity_y);
640 Send(CreateGesture(ET_GESTURE_SCROLL_BEGIN, event, scroll_details));
642 EndTouchScrollIfNecessary(event, false);
644 GestureEventDetails fling_details(
645 ET_SCROLL_FLING_START, velocity_x, velocity_y);
646 Send(CreateGesture(
647 ET_SCROLL_FLING_START, event, fling_details));
650 void GestureProvider::Send(const GestureEventData& gesture) {
651 DCHECK(!gesture.time.is_null());
652 // The only valid events that should be sent without an active touch sequence
653 // are SHOW_PRESS and TAP, potentially triggered by the double-tap
654 // delay timing out.
655 DCHECK(current_down_event_ || gesture.type == ET_GESTURE_TAP ||
656 gesture.type == ET_GESTURE_SHOW_PRESS);
658 switch (gesture.type) {
659 case ET_GESTURE_LONG_PRESS:
660 DCHECK(!scale_gesture_listener_->IsScaleGestureDetectionInProgress());
661 current_longpress_time_ = gesture.time;
662 break;
663 case ET_GESTURE_LONG_TAP:
664 current_longpress_time_ = base::TimeTicks();
665 break;
666 case ET_GESTURE_SCROLL_BEGIN:
667 DCHECK(!touch_scroll_in_progress_);
668 touch_scroll_in_progress_ = true;
669 break;
670 case ET_GESTURE_SCROLL_END:
671 DCHECK(touch_scroll_in_progress_);
672 if (pinch_in_progress_)
673 Send(CreateGesture(ET_GESTURE_PINCH_END,
674 gesture.motion_event_id,
675 gesture.time,
676 gesture.x,
677 gesture.y,
678 gesture.details.touch_points(),
679 gesture.details.bounding_box()));
680 touch_scroll_in_progress_ = false;
681 break;
682 case ET_GESTURE_PINCH_BEGIN:
683 DCHECK(!pinch_in_progress_);
684 if (!touch_scroll_in_progress_)
685 Send(CreateGesture(ET_GESTURE_SCROLL_BEGIN,
686 gesture.motion_event_id,
687 gesture.time,
688 gesture.x,
689 gesture.y,
690 gesture.details.touch_points(),
691 gesture.details.bounding_box()));
692 pinch_in_progress_ = true;
693 break;
694 case ET_GESTURE_PINCH_END:
695 DCHECK(pinch_in_progress_);
696 pinch_in_progress_ = false;
697 break;
698 case ET_GESTURE_SHOW_PRESS:
699 // It's possible that a double-tap drag zoom (from ScaleGestureDetector)
700 // will start before the press gesture fires (from GestureDetector), in
701 // which case the press should simply be dropped.
702 if (pinch_in_progress_ || touch_scroll_in_progress_)
703 return;
704 default:
705 break;
708 client_->OnGestureEvent(gesture);
711 bool GestureProvider::SendLongTapIfNecessary(const MotionEvent& event) {
712 if (event.GetAction() == MotionEvent::ACTION_UP &&
713 !current_longpress_time_.is_null() &&
714 !scale_gesture_listener_->IsScaleGestureDetectionInProgress()) {
715 GestureEventDetails long_tap_details(ET_GESTURE_LONG_TAP, 0, 0);
716 Send(CreateGesture(ET_GESTURE_LONG_TAP, event, long_tap_details));
717 return true;
719 return false;
722 void GestureProvider::EndTouchScrollIfNecessary(const MotionEvent& event,
723 bool send_scroll_end_event) {
724 if (!touch_scroll_in_progress_)
725 return;
726 if (send_scroll_end_event)
727 Send(CreateGesture(ET_GESTURE_SCROLL_END, event));
728 touch_scroll_in_progress_ = false;
731 void GestureProvider::OnTouchEventHandlingBegin(const MotionEvent& event) {
732 switch (event.GetAction()) {
733 case MotionEvent::ACTION_DOWN:
734 current_down_event_ = event.Clone();
735 touch_scroll_in_progress_ = false;
736 pinch_in_progress_ = false;
737 current_longpress_time_ = base::TimeTicks();
738 if (gesture_begin_end_types_enabled_)
739 Send(CreateGesture(ET_GESTURE_BEGIN, event));
740 break;
741 case MotionEvent::ACTION_POINTER_DOWN:
742 if (gesture_begin_end_types_enabled_)
743 Send(CreateGesture(ET_GESTURE_BEGIN, event));
744 break;
745 case MotionEvent::ACTION_POINTER_UP:
746 case MotionEvent::ACTION_UP:
747 case MotionEvent::ACTION_CANCEL:
748 case MotionEvent::ACTION_MOVE:
749 break;
753 void GestureProvider::OnTouchEventHandlingEnd(const MotionEvent& event) {
754 switch (event.GetAction()) {
755 case MotionEvent::ACTION_UP:
756 case MotionEvent::ACTION_CANCEL:
757 // Note: This call will have no effect if a fling was just generated, as
758 // |Fling()| will have already signalled an end to touch-scrolling.
759 EndTouchScrollIfNecessary(event, true);
761 if (gesture_begin_end_types_enabled_)
762 Send(CreateGesture(ET_GESTURE_END, event));
764 current_down_event_.reset();
766 UpdateDoubleTapDetectionSupport();
767 break;
768 case MotionEvent::ACTION_POINTER_UP:
769 if (gesture_begin_end_types_enabled_)
770 Send(CreateGesture(ET_GESTURE_END, event));
771 break;
772 case MotionEvent::ACTION_DOWN:
773 case MotionEvent::ACTION_POINTER_DOWN:
774 case MotionEvent::ACTION_MOVE:
775 break;
779 void GestureProvider::UpdateDoubleTapDetectionSupport() {
780 // The GestureDetector requires that any provided DoubleTapListener remain
781 // attached to it for the duration of a touch sequence. Defer any potential
782 // null'ing of the listener until the sequence has ended.
783 if (current_down_event_)
784 return;
786 const bool double_tap_enabled = double_tap_support_for_page_ &&
787 double_tap_support_for_platform_;
788 gesture_listener_->SetDoubleTapEnabled(double_tap_enabled);
789 scale_gesture_listener_->SetDoubleTapEnabled(double_tap_enabled);
792 } // namespace ui