1a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved.
2a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
3a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// found in the LICENSE file.
4a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
55c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu// MSVC++ requires this to be set before any other includes to get M_PI.
65c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#define _USE_MATH_DEFINES
75c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
8a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "ui/events/gesture_detection/gesture_detector.h"
9a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
10a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include <cmath>
11a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
12a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "base/timer/timer.h"
13a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "ui/events/gesture_detection/motion_event.h"
14a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
15a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)namespace ui {
16a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)namespace {
17a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
18a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch// Using a small epsilon when comparing slop distances allows pixel perfect
19a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch// slop determination when using fractional DIP coordinates (assuming the slop
20a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch// region and DPI scale are reasonably proportioned).
21a02191e04bc25c4935f804f2c080ae28663d096dBen Murdochconst float kSlopEpsilon = .05f;
22a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch
23a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch// Minimum distance a scroll must have traveled from the last scroll/focal point
24a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch// to trigger an |OnScroll| callback.
25a02191e04bc25c4935f804f2c080ae28663d096dBen Murdochconst float kScrollEpsilon = .1f;
26a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch
275c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liuconst float kDegreesToRadians = static_cast<float>(M_PI) / 180.0f;
285c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
29a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// Constants used by TimeoutGestureHandler.
30a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)enum TimeoutEvent {
31a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  SHOW_PRESS = 0,
32a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  LONG_PRESS,
33a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  TAP,
34a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  TIMEOUT_EVENT_COUNT
35a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)};
36a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
37a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}  // namespace
38a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
39a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// Note: These constants were taken directly from the default (unscaled)
40a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// versions found in Android's ViewConfiguration.
41a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)GestureDetector::Config::Config()
42a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    : longpress_timeout(base::TimeDelta::FromMilliseconds(500)),
43a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      showpress_timeout(base::TimeDelta::FromMilliseconds(180)),
44a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      double_tap_timeout(base::TimeDelta::FromMilliseconds(300)),
45f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      double_tap_min_time(base::TimeDelta::FromMilliseconds(40)),
46a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch      touch_slop(8),
47a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch      double_tap_slop(100),
48a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch      minimum_fling_velocity(50),
495c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      maximum_fling_velocity(8000),
505c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      swipe_enabled(false),
515c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      minimum_swipe_velocity(20),
52cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      maximum_swipe_deviation_angle(20.f),
53cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      two_finger_tap_enabled(false),
54cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      two_finger_tap_max_separation(300),
55cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      two_finger_tap_timeout(base::TimeDelta::FromMilliseconds(700)) {
565c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}
57a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
58a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)GestureDetector::Config::~Config() {}
59a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
60a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)bool GestureDetector::SimpleGestureListener::OnDown(const MotionEvent& e) {
61a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return false;
62a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
63a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
64a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void GestureDetector::SimpleGestureListener::OnShowPress(const MotionEvent& e) {
65a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
66a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
67a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)bool GestureDetector::SimpleGestureListener::OnSingleTapUp(
68a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    const MotionEvent& e) {
69a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return false;
70a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
71a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
72116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid GestureDetector::SimpleGestureListener::OnLongPress(const MotionEvent& e) {
73a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
74a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
75a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)bool GestureDetector::SimpleGestureListener::OnScroll(const MotionEvent& e1,
76a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                                      const MotionEvent& e2,
77a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                                      float distance_x,
78a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                                      float distance_y) {
79a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return false;
80a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
81a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
82a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)bool GestureDetector::SimpleGestureListener::OnFling(const MotionEvent& e1,
83a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                                     const MotionEvent& e2,
84a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                                     float velocity_x,
85a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                                     float velocity_y) {
86a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return false;
87a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
88a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
895c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liubool GestureDetector::SimpleGestureListener::OnSwipe(const MotionEvent& e1,
905c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu                                                     const MotionEvent& e2,
915c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu                                                     float velocity_x,
925c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu                                                     float velocity_y) {
935c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  return false;
945c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}
955c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
96cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)bool GestureDetector::SimpleGestureListener::OnTwoFingerTap(
97cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    const MotionEvent& e1,
98cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    const MotionEvent& e2) {
99cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  return false;
100cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
101cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
102a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)bool GestureDetector::SimpleGestureListener::OnSingleTapConfirmed(
103a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    const MotionEvent& e) {
104a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return false;
105a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
106a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
107a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)bool GestureDetector::SimpleGestureListener::OnDoubleTap(const MotionEvent& e) {
108a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return false;
109a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
110a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
111a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)bool GestureDetector::SimpleGestureListener::OnDoubleTapEvent(
112a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    const MotionEvent& e) {
113a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return false;
114a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
115a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
116a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)class GestureDetector::TimeoutGestureHandler {
117a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) public:
118a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  TimeoutGestureHandler(const Config& config, GestureDetector* gesture_detector)
119a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      : gesture_detector_(gesture_detector) {
120a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    DCHECK(config.showpress_timeout <= config.longpress_timeout);
121a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
122a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    timeout_callbacks_[SHOW_PRESS] = &GestureDetector::OnShowPressTimeout;
123a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    timeout_delays_[SHOW_PRESS] = config.showpress_timeout;
124a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
125a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    timeout_callbacks_[LONG_PRESS] = &GestureDetector::OnLongPressTimeout;
126a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    timeout_delays_[LONG_PRESS] =
127a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        config.longpress_timeout + config.showpress_timeout;
128a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
129a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    timeout_callbacks_[TAP] = &GestureDetector::OnTapTimeout;
130a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    timeout_delays_[TAP] = config.double_tap_timeout;
131a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
132a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
133a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  ~TimeoutGestureHandler() {
134a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    Stop();
135a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
136a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
137a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  void StartTimeout(TimeoutEvent event) {
138a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    timeout_timers_[event].Start(FROM_HERE,
139a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                 timeout_delays_[event],
140a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                 gesture_detector_,
141a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                 timeout_callbacks_[event]);
142a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
143a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
144a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  void StopTimeout(TimeoutEvent event) { timeout_timers_[event].Stop(); }
145a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
146a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  void Stop() {
147a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    for (size_t i = SHOW_PRESS; i < TIMEOUT_EVENT_COUNT; ++i)
148a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      timeout_timers_[i].Stop();
149a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
150a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
151a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  bool HasTimeout(TimeoutEvent event) const {
152a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return timeout_timers_[event].IsRunning();
153a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
154a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
155a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) private:
156a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  typedef void (GestureDetector::*ReceiverMethod)();
157a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
158a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  GestureDetector* const gesture_detector_;
159a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  base::OneShotTimer<GestureDetector> timeout_timers_[TIMEOUT_EVENT_COUNT];
160a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  ReceiverMethod timeout_callbacks_[TIMEOUT_EVENT_COUNT];
161a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  base::TimeDelta timeout_delays_[TIMEOUT_EVENT_COUNT];
162a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)};
163a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
164a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)GestureDetector::GestureDetector(
165a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    const Config& config,
166a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    GestureListener* listener,
167a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    DoubleTapListener* optional_double_tap_listener)
168a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    : timeout_handler_(new TimeoutGestureHandler(config, this)),
169a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      listener_(listener),
170a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      double_tap_listener_(optional_double_tap_listener),
171a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      touch_slop_square_(0),
172a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      double_tap_touch_slop_square_(0),
173a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      double_tap_slop_square_(0),
174cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      two_finger_tap_distance_square_(0),
175a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      min_fling_velocity_(1),
176a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      max_fling_velocity_(1),
177cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      min_swipe_velocity_(0),
178cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      min_swipe_direction_component_ratio_(0),
179a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      still_down_(false),
180a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      defer_confirm_single_tap_(false),
181a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      always_in_tap_region_(false),
182a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      always_in_bigger_tap_region_(false),
183cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      two_finger_tap_allowed_for_gesture_(false),
184a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      is_double_tapping_(false),
185a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      last_focus_x_(0),
186a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      last_focus_y_(0),
187a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      down_focus_x_(0),
188a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      down_focus_y_(0),
189cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      longpress_enabled_(true),
190cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      swipe_enabled_(false),
191cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      two_finger_tap_enabled_(false) {
192a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  DCHECK(listener_);
193a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  Init(config);
194a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
195a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
196a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)GestureDetector::~GestureDetector() {}
197a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
198a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)bool GestureDetector::OnTouchEvent(const MotionEvent& ev) {
199a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  const MotionEvent::Action action = ev.GetAction();
200a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
201a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  velocity_tracker_.AddMovement(ev);
202a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
203a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  const bool pointer_up = action == MotionEvent::ACTION_POINTER_UP;
204a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  const int skip_index = pointer_up ? ev.GetActionIndex() : -1;
205a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
206a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // Determine focal point.
207a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  float sum_x = 0, sum_y = 0;
208a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  const int count = static_cast<int>(ev.GetPointerCount());
209a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  for (int i = 0; i < count; i++) {
210a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    if (skip_index == i)
211a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      continue;
212a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    sum_x += ev.GetX(i);
213a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    sum_y += ev.GetY(i);
214a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
215a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  const int div = pointer_up ? count - 1 : count;
216a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  const float focus_x = sum_x / div;
217a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  const float focus_y = sum_y / div;
218a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
219a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  bool handled = false;
220a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
221a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  switch (action) {
222cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    case MotionEvent::ACTION_POINTER_DOWN: {
223a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      down_focus_x_ = last_focus_x_ = focus_x;
224a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      down_focus_y_ = last_focus_y_ = focus_y;
225a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      // Cancel long press and taps.
226a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      CancelTaps();
227a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
228cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      if (!two_finger_tap_allowed_for_gesture_)
229cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        break;
230cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
231cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      const int action_index = ev.GetActionIndex();
232cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      const float dx = ev.GetX(action_index) - current_down_event_->GetX();
233cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      const float dy = ev.GetY(action_index) - current_down_event_->GetY();
234cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
235cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      if (ev.GetPointerCount() == 2 &&
236cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          dx * dx + dy * dy < two_finger_tap_distance_square_) {
237cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        secondary_pointer_down_event_ = ev.Clone();
238cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      } else {
239cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        two_finger_tap_allowed_for_gesture_ = false;
240cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      }
241cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    } break;
242cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
243cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    case MotionEvent::ACTION_POINTER_UP: {
244a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      down_focus_x_ = last_focus_x_ = focus_x;
245a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      down_focus_y_ = last_focus_y_ = focus_y;
246a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
247a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      // Check the dot product of current velocities.
248a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      // If the pointer that left was opposing another velocity vector, clear.
249a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      velocity_tracker_.ComputeCurrentVelocity(1000, max_fling_velocity_);
250cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      const int up_index = ev.GetActionIndex();
251cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      const int id1 = ev.GetPointerId(up_index);
252cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      const float vx1 = velocity_tracker_.GetXVelocity(id1);
253cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      const float vy1 = velocity_tracker_.GetYVelocity(id1);
254cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      float vx_total = vx1;
255cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      float vy_total = vy1;
256cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      for (int i = 0; i < count; i++) {
257cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        if (i == up_index)
258cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          continue;
259cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
260cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        const int id2 = ev.GetPointerId(i);
261cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        const float vx2 = velocity_tracker_.GetXVelocity(id2);
262cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        const float vy2 = velocity_tracker_.GetYVelocity(id2);
263cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        const float dot = vx1 * vx2 + vy1 * vy2;
264cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        if (dot < 0) {
265cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          vx_total = 0;
266cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          vy_total = 0;
267cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          velocity_tracker_.Clear();
268cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          break;
2695c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu        }
270cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        vx_total += vx2;
271cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        vy_total += vy2;
272cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      }
2735c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
274cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      handled = HandleSwipeIfNeeded(ev, vx_total / count, vy_total / count);
275cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
276cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      if (two_finger_tap_allowed_for_gesture_ && ev.GetPointerCount() == 2 &&
277cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          (ev.GetEventTime() - secondary_pointer_down_event_->GetEventTime() <=
278cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)           two_finger_tap_timeout_)) {
279cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        handled = listener_->OnTwoFingerTap(*current_down_event_, ev);
280a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      }
281cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      two_finger_tap_allowed_for_gesture_ = false;
282cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    } break;
283a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
284a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    case MotionEvent::ACTION_DOWN:
285a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      if (double_tap_listener_) {
286a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        bool had_tap_message = timeout_handler_->HasTimeout(TAP);
287a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        if (had_tap_message)
288a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)          timeout_handler_->StopTimeout(TAP);
289a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        if (current_down_event_ && previous_up_event_ && had_tap_message &&
290a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)            IsConsideredDoubleTap(
291a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                *current_down_event_, *previous_up_event_, ev)) {
292a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)          // This is a second tap.
293a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)          is_double_tapping_ = true;
294a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)          // Give a callback with the first tap of the double-tap.
295a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)          handled |= double_tap_listener_->OnDoubleTap(*current_down_event_);
296a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)          // Give a callback with down event of the double-tap.
297a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)          handled |= double_tap_listener_->OnDoubleTapEvent(ev);
298a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        } else {
299a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)          // This is a first tap.
300a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)          DCHECK(double_tap_timeout_ > base::TimeDelta());
301a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)          timeout_handler_->StartTimeout(TAP);
302a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        }
303a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      }
304a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
305a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      down_focus_x_ = last_focus_x_ = focus_x;
306a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      down_focus_y_ = last_focus_y_ = focus_y;
307a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      current_down_event_ = ev.Clone();
308a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
309cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      secondary_pointer_down_event_.reset();
310a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      always_in_tap_region_ = true;
311a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      always_in_bigger_tap_region_ = true;
312a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      still_down_ = true;
313a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      defer_confirm_single_tap_ = false;
314cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      two_finger_tap_allowed_for_gesture_ = two_finger_tap_enabled_;
315a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
316a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      // Always start the SHOW_PRESS timer before the LONG_PRESS timer to ensure
317a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      // proper timeout ordering.
318a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      timeout_handler_->StartTimeout(SHOW_PRESS);
3195c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      if (longpress_enabled_)
320a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        timeout_handler_->StartTimeout(LONG_PRESS);
321a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      handled |= listener_->OnDown(ev);
322a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      break;
323a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
324a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    case MotionEvent::ACTION_MOVE:
325a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      {
326a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        const float scroll_x = last_focus_x_ - focus_x;
327a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        const float scroll_y = last_focus_y_ - focus_y;
328a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        if (is_double_tapping_) {
329a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)          // Give the move events of the double-tap.
33023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)          DCHECK(double_tap_listener_);
331a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)          handled |= double_tap_listener_->OnDoubleTapEvent(ev);
332a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        } else if (always_in_tap_region_) {
333a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch          const float delta_x = focus_x - down_focus_x_;
334a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch          const float delta_y = focus_y - down_focus_y_;
335a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch          const float distance_square = delta_x * delta_x + delta_y * delta_y;
336a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch          if (distance_square > touch_slop_square_) {
337a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)            handled = listener_->OnScroll(
338a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                *current_down_event_, ev, scroll_x, scroll_y);
339a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)            last_focus_x_ = focus_x;
340a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)            last_focus_y_ = focus_y;
341a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)            always_in_tap_region_ = false;
342a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)            timeout_handler_->Stop();
343a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)          }
344a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch          if (distance_square > double_tap_touch_slop_square_)
345a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)            always_in_bigger_tap_region_ = false;
346a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch        } else if (std::abs(scroll_x) > kScrollEpsilon ||
347a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch                   std::abs(scroll_y) > kScrollEpsilon) {
348a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)          handled =
349a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)              listener_->OnScroll(*current_down_event_, ev, scroll_x, scroll_y);
350a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)          last_focus_x_ = focus_x;
351a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)          last_focus_y_ = focus_y;
352a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        }
353cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
354cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        if (!two_finger_tap_allowed_for_gesture_)
355cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          break;
356cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
357cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        // Two-finger tap should be prevented if either pointer exceeds its
358cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        // (independent) slop region.
359cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        const int id0 = current_down_event_->GetPointerId(0);
360cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        const int ev_idx0 = ev.GetPointerId(0) == id0 ? 0 : 1;
361cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
362cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        // Check if the primary pointer exceeded the slop region.
363cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        float dx = current_down_event_->GetX() - ev.GetX(ev_idx0);
364cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        float dy = current_down_event_->GetY() - ev.GetY(ev_idx0);
365cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        if (dx * dx + dy * dy > touch_slop_square_) {
366cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          two_finger_tap_allowed_for_gesture_ = false;
367cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          break;
368cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        }
369cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        if (ev.GetPointerCount() == 2) {
370cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          // Check if the secondary pointer exceeded the slop region.
371cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          const int ev_idx1 = ev_idx0 == 0 ? 1 : 0;
372cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          const int idx1 = secondary_pointer_down_event_->GetActionIndex();
373cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          dx = secondary_pointer_down_event_->GetX(idx1) - ev.GetX(ev_idx1);
374cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          dy = secondary_pointer_down_event_->GetY(idx1) - ev.GetY(ev_idx1);
375cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          if (dx * dx + dy * dy > touch_slop_square_)
376cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)            two_finger_tap_allowed_for_gesture_ = false;
377cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        }
378a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      }
379a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      break;
380a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
381a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    case MotionEvent::ACTION_UP:
382a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      still_down_ = false;
383a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      {
384a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        if (is_double_tapping_) {
385a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)          // Finally, give the up event of the double-tap.
38623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)          DCHECK(double_tap_listener_);
387a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)          handled |= double_tap_listener_->OnDoubleTapEvent(ev);
388a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        } else if (always_in_tap_region_) {
389a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)          handled = listener_->OnSingleTapUp(ev);
390a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)          if (defer_confirm_single_tap_ && double_tap_listener_ != NULL) {
391a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)            double_tap_listener_->OnSingleTapConfirmed(ev);
392a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)          }
393a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        } else {
394a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
395a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)          // A fling must travel the minimum tap distance.
396a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)          const int pointer_id = ev.GetPointerId(0);
397a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)          velocity_tracker_.ComputeCurrentVelocity(1000, max_fling_velocity_);
398a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)          const float velocity_y = velocity_tracker_.GetYVelocity(pointer_id);
399a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)          const float velocity_x = velocity_tracker_.GetXVelocity(pointer_id);
400a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
401a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)          if ((std::abs(velocity_y) > min_fling_velocity_) ||
402a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)              (std::abs(velocity_x) > min_fling_velocity_)) {
403a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)            handled = listener_->OnFling(
404a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                *current_down_event_, ev, velocity_x, velocity_y);
405a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)          }
406cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
407cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          handled |= HandleSwipeIfNeeded(ev, velocity_x, velocity_y);
408a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        }
409a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
410a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        previous_up_event_ = ev.Clone();
411a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
412a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        velocity_tracker_.Clear();
413a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        is_double_tapping_ = false;
414a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        defer_confirm_single_tap_ = false;
415a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        timeout_handler_->StopTimeout(SHOW_PRESS);
416a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        timeout_handler_->StopTimeout(LONG_PRESS);
417a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      }
418a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      break;
419a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
420a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    case MotionEvent::ACTION_CANCEL:
421a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      Cancel();
422a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      break;
423a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
424a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
425a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return handled;
426a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
427a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
4280529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochvoid GestureDetector::SetDoubleTapListener(
4290529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    DoubleTapListener* double_tap_listener) {
4300529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  if (double_tap_listener == double_tap_listener_)
4310529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    return;
4320529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
4330529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  DCHECK(!is_double_tapping_);
4340529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
4350529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  // Null'ing the double-tap listener should flush an active tap timeout.
4360529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  if (!double_tap_listener) {
4370529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    if (timeout_handler_->HasTimeout(TAP)) {
4380529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      timeout_handler_->StopTimeout(TAP);
4390529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      OnTapTimeout();
4400529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    }
4410529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  }
4420529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
4430529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  double_tap_listener_ = double_tap_listener;
4440529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch}
4450529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
446a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void GestureDetector::Init(const Config& config) {
447a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  DCHECK(listener_);
448a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
449a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  const float touch_slop = config.touch_slop + kSlopEpsilon;
450a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  const float double_tap_touch_slop = touch_slop;
451a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  const float double_tap_slop = config.double_tap_slop + kSlopEpsilon;
452a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  touch_slop_square_ = touch_slop * touch_slop;
453a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  double_tap_touch_slop_square_ = double_tap_touch_slop * double_tap_touch_slop;
454a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  double_tap_slop_square_ = double_tap_slop * double_tap_slop;
455a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  double_tap_timeout_ = config.double_tap_timeout;
456f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  double_tap_min_time_ = config.double_tap_min_time;
457f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  DCHECK(double_tap_min_time_ < double_tap_timeout_);
458a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  min_fling_velocity_ = config.minimum_fling_velocity;
459a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  max_fling_velocity_ = config.maximum_fling_velocity;
4605c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
4615c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  swipe_enabled_ = config.swipe_enabled;
4625c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  min_swipe_velocity_ = config.minimum_swipe_velocity;
4635c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  DCHECK_GT(config.maximum_swipe_deviation_angle, 0);
4645c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  DCHECK_LE(config.maximum_swipe_deviation_angle, 45);
4655c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  const float maximum_swipe_deviation_angle =
4665c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      std::min(45.f, std::max(0.001f, config.maximum_swipe_deviation_angle));
4675c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  min_swipe_direction_component_ratio_ =
4685c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      1.f / tan(maximum_swipe_deviation_angle * kDegreesToRadians);
469cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
470cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  two_finger_tap_enabled_ = config.two_finger_tap_enabled;
471cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  two_finger_tap_distance_square_ = config.two_finger_tap_max_separation *
472cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                                    config.two_finger_tap_max_separation;
473cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  two_finger_tap_timeout_ = config.two_finger_tap_timeout;
474a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
475a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
476a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void GestureDetector::OnShowPressTimeout() {
477a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  listener_->OnShowPress(*current_down_event_);
478a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
479a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
480a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void GestureDetector::OnLongPressTimeout() {
481a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  timeout_handler_->StopTimeout(TAP);
482a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  defer_confirm_single_tap_ = false;
483116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  listener_->OnLongPress(*current_down_event_);
484a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
485a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
486a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void GestureDetector::OnTapTimeout() {
487a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (!double_tap_listener_)
488a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return;
489a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (!still_down_)
490a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    double_tap_listener_->OnSingleTapConfirmed(*current_down_event_);
491a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  else
492a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    defer_confirm_single_tap_ = true;
493a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
494a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
495a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void GestureDetector::Cancel() {
496cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  CancelTaps();
497a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  velocity_tracker_.Clear();
498a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  still_down_ = false;
499a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
500a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
501a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void GestureDetector::CancelTaps() {
502a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  timeout_handler_->Stop();
503a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  is_double_tapping_ = false;
504a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  always_in_tap_region_ = false;
505a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  always_in_bigger_tap_region_ = false;
506a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  defer_confirm_single_tap_ = false;
507a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
508a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
509a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)bool GestureDetector::IsConsideredDoubleTap(
510a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    const MotionEvent& first_down,
511a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    const MotionEvent& first_up,
512a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    const MotionEvent& second_down) const {
513a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (!always_in_bigger_tap_region_)
514a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return false;
515a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
516f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  const base::TimeDelta delta_time =
517f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      second_down.GetEventTime() - first_up.GetEventTime();
518f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if (delta_time < double_tap_min_time_ || delta_time > double_tap_timeout_)
519a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return false;
520a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
521a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  const float delta_x = first_down.GetX() - second_down.GetX();
522a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  const float delta_y = first_down.GetY() - second_down.GetY();
523a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return (delta_x * delta_x + delta_y * delta_y < double_tap_slop_square_);
524a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
525a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
526cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)bool GestureDetector::HandleSwipeIfNeeded(const MotionEvent& up,
527cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                                          float vx,
528cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                                          float vy) {
529cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (!swipe_enabled_ || (!vx && !vy))
530cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return false;
531cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  float vx_abs = std::abs(vx);
532cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  float vy_abs = std::abs(vy);
533cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
534cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (vx_abs < min_swipe_velocity_)
535cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    vx_abs = vx = 0;
536cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (vy_abs < min_swipe_velocity_)
537cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    vy_abs = vy = 0;
538cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
539cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // Note that the ratio will be 0 if both velocites are below the min.
540cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  float ratio = vx_abs > vy_abs ? vx_abs / std::max(vy_abs, 0.001f)
541cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                                : vy_abs / std::max(vx_abs, 0.001f);
542cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
543cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (ratio < min_swipe_direction_component_ratio_)
544cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return false;
545cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
546cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (vx_abs > vy_abs)
547cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    vy = 0;
548cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  else
549cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    vx = 0;
550cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  return listener_->OnSwipe(*current_down_event_, up, vx, vy);
551cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
552cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
553a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}  // namespace ui
554