OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
| 5 // MSVC++ requires this to be set before any other includes to get M_PI. |
| 6 #define _USE_MATH_DEFINES |
| 7 |
5 #include "ui/events/gesture_detection/gesture_detector.h" | 8 #include "ui/events/gesture_detection/gesture_detector.h" |
6 | 9 |
7 #include <cmath> | 10 #include <cmath> |
8 | 11 |
9 #include "base/timer/timer.h" | 12 #include "base/timer/timer.h" |
10 #include "ui/events/gesture_detection/motion_event.h" | 13 #include "ui/events/gesture_detection/motion_event.h" |
11 | 14 |
12 namespace ui { | 15 namespace ui { |
13 namespace { | 16 namespace { |
14 | 17 |
15 // Using a small epsilon when comparing slop distances allows pixel perfect | 18 // Using a small epsilon when comparing slop distances allows pixel perfect |
16 // slop determination when using fractional DIP coordinates (assuming the slop | 19 // slop determination when using fractional DIP coordinates (assuming the slop |
17 // region and DPI scale are reasonably proportioned). | 20 // region and DPI scale are reasonably proportioned). |
18 const float kSlopEpsilon = .05f; | 21 const float kSlopEpsilon = .05f; |
19 | 22 |
20 // Minimum distance a scroll must have traveled from the last scroll/focal point | 23 // Minimum distance a scroll must have traveled from the last scroll/focal point |
21 // to trigger an |OnScroll| callback. | 24 // to trigger an |OnScroll| callback. |
22 const float kScrollEpsilon = .1f; | 25 const float kScrollEpsilon = .1f; |
23 | 26 |
| 27 const float kDegreesToRadians = static_cast<float>(M_PI) / 180.0f; |
| 28 |
24 // Constants used by TimeoutGestureHandler. | 29 // Constants used by TimeoutGestureHandler. |
25 enum TimeoutEvent { | 30 enum TimeoutEvent { |
26 SHOW_PRESS = 0, | 31 SHOW_PRESS = 0, |
27 LONG_PRESS, | 32 LONG_PRESS, |
28 TAP, | 33 TAP, |
29 TIMEOUT_EVENT_COUNT | 34 TIMEOUT_EVENT_COUNT |
30 }; | 35 }; |
31 | 36 |
32 } // namespace | 37 } // namespace |
33 | 38 |
34 // Note: These constants were taken directly from the default (unscaled) | 39 // Note: These constants were taken directly from the default (unscaled) |
35 // versions found in Android's ViewConfiguration. | 40 // versions found in Android's ViewConfiguration. |
36 GestureDetector::Config::Config() | 41 GestureDetector::Config::Config() |
37 : longpress_timeout(base::TimeDelta::FromMilliseconds(500)), | 42 : longpress_timeout(base::TimeDelta::FromMilliseconds(500)), |
38 showpress_timeout(base::TimeDelta::FromMilliseconds(180)), | 43 showpress_timeout(base::TimeDelta::FromMilliseconds(180)), |
39 double_tap_timeout(base::TimeDelta::FromMilliseconds(300)), | 44 double_tap_timeout(base::TimeDelta::FromMilliseconds(300)), |
40 touch_slop(8), | 45 touch_slop(8), |
41 double_tap_slop(100), | 46 double_tap_slop(100), |
42 minimum_fling_velocity(50), | 47 minimum_fling_velocity(50), |
43 maximum_fling_velocity(8000) {} | 48 maximum_fling_velocity(8000), |
| 49 swipe_enabled(false), |
| 50 minimum_swipe_velocity(20), |
| 51 maximum_swipe_deviation_angle(20.f) { |
| 52 } |
44 | 53 |
45 GestureDetector::Config::~Config() {} | 54 GestureDetector::Config::~Config() {} |
46 | 55 |
47 bool GestureDetector::SimpleGestureListener::OnDown(const MotionEvent& e) { | 56 bool GestureDetector::SimpleGestureListener::OnDown(const MotionEvent& e) { |
48 return false; | 57 return false; |
49 } | 58 } |
50 | 59 |
51 void GestureDetector::SimpleGestureListener::OnShowPress(const MotionEvent& e) { | 60 void GestureDetector::SimpleGestureListener::OnShowPress(const MotionEvent& e) { |
52 } | 61 } |
53 | 62 |
(...skipping 13 matching lines...) Expand all Loading... |
67 return false; | 76 return false; |
68 } | 77 } |
69 | 78 |
70 bool GestureDetector::SimpleGestureListener::OnFling(const MotionEvent& e1, | 79 bool GestureDetector::SimpleGestureListener::OnFling(const MotionEvent& e1, |
71 const MotionEvent& e2, | 80 const MotionEvent& e2, |
72 float velocity_x, | 81 float velocity_x, |
73 float velocity_y) { | 82 float velocity_y) { |
74 return false; | 83 return false; |
75 } | 84 } |
76 | 85 |
| 86 bool GestureDetector::SimpleGestureListener::OnSwipe(const MotionEvent& e1, |
| 87 const MotionEvent& e2, |
| 88 float velocity_x, |
| 89 float velocity_y) { |
| 90 return false; |
| 91 } |
| 92 |
77 bool GestureDetector::SimpleGestureListener::OnSingleTapConfirmed( | 93 bool GestureDetector::SimpleGestureListener::OnSingleTapConfirmed( |
78 const MotionEvent& e) { | 94 const MotionEvent& e) { |
79 return false; | 95 return false; |
80 } | 96 } |
81 | 97 |
82 bool GestureDetector::SimpleGestureListener::OnDoubleTap(const MotionEvent& e) { | 98 bool GestureDetector::SimpleGestureListener::OnDoubleTap(const MotionEvent& e) { |
83 return false; | 99 return false; |
84 } | 100 } |
85 | 101 |
86 bool GestureDetector::SimpleGestureListener::OnDoubleTapEvent( | 102 bool GestureDetector::SimpleGestureListener::OnDoubleTapEvent( |
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
151 still_down_(false), | 167 still_down_(false), |
152 defer_confirm_single_tap_(false), | 168 defer_confirm_single_tap_(false), |
153 in_longpress_(false), | 169 in_longpress_(false), |
154 always_in_tap_region_(false), | 170 always_in_tap_region_(false), |
155 always_in_bigger_tap_region_(false), | 171 always_in_bigger_tap_region_(false), |
156 is_double_tapping_(false), | 172 is_double_tapping_(false), |
157 last_focus_x_(0), | 173 last_focus_x_(0), |
158 last_focus_y_(0), | 174 last_focus_y_(0), |
159 down_focus_x_(0), | 175 down_focus_x_(0), |
160 down_focus_y_(0), | 176 down_focus_y_(0), |
161 is_longpress_enabled_(true) { | 177 longpress_enabled_(true) { |
162 DCHECK(listener_); | 178 DCHECK(listener_); |
163 Init(config); | 179 Init(config); |
164 } | 180 } |
165 | 181 |
166 GestureDetector::~GestureDetector() {} | 182 GestureDetector::~GestureDetector() {} |
167 | 183 |
168 bool GestureDetector::OnTouchEvent(const MotionEvent& ev) { | 184 bool GestureDetector::OnTouchEvent(const MotionEvent& ev) { |
169 const MotionEvent::Action action = ev.GetAction(); | 185 const MotionEvent::Action action = ev.GetAction(); |
170 | 186 |
171 velocity_tracker_.AddMovement(ev); | 187 velocity_tracker_.AddMovement(ev); |
(...skipping 27 matching lines...) Expand all Loading... |
199 case MotionEvent::ACTION_POINTER_UP: | 215 case MotionEvent::ACTION_POINTER_UP: |
200 down_focus_x_ = last_focus_x_ = focus_x; | 216 down_focus_x_ = last_focus_x_ = focus_x; |
201 down_focus_y_ = last_focus_y_ = focus_y; | 217 down_focus_y_ = last_focus_y_ = focus_y; |
202 | 218 |
203 // Check the dot product of current velocities. | 219 // Check the dot product of current velocities. |
204 // If the pointer that left was opposing another velocity vector, clear. | 220 // If the pointer that left was opposing another velocity vector, clear. |
205 velocity_tracker_.ComputeCurrentVelocity(1000, max_fling_velocity_); | 221 velocity_tracker_.ComputeCurrentVelocity(1000, max_fling_velocity_); |
206 { | 222 { |
207 const int up_index = ev.GetActionIndex(); | 223 const int up_index = ev.GetActionIndex(); |
208 const int id1 = ev.GetPointerId(up_index); | 224 const int id1 = ev.GetPointerId(up_index); |
209 const float x1 = velocity_tracker_.GetXVelocity(id1); | 225 const float vx1 = velocity_tracker_.GetXVelocity(id1); |
210 const float y1 = velocity_tracker_.GetYVelocity(id1); | 226 const float vy1 = velocity_tracker_.GetYVelocity(id1); |
| 227 float vx_total = vx1; |
| 228 float vy_total = vy1; |
211 for (int i = 0; i < count; i++) { | 229 for (int i = 0; i < count; i++) { |
212 if (i == up_index) | 230 if (i == up_index) |
213 continue; | 231 continue; |
214 | 232 |
215 const int id2 = ev.GetPointerId(i); | 233 const int id2 = ev.GetPointerId(i); |
216 const float x = x1 * velocity_tracker_.GetXVelocity(id2); | 234 const float vx2 = velocity_tracker_.GetXVelocity(id2); |
217 const float y = y1 * velocity_tracker_.GetYVelocity(id2); | 235 const float vy2 = velocity_tracker_.GetYVelocity(id2); |
218 | 236 const float dot = vx1 * vx2 + vy1 * vy2; |
219 const float dot = x + y; | |
220 if (dot < 0) { | 237 if (dot < 0) { |
| 238 vx_total = 0; |
| 239 vy_total = 0; |
221 velocity_tracker_.Clear(); | 240 velocity_tracker_.Clear(); |
222 break; | 241 break; |
223 } | 242 } |
| 243 vx_total += vx2; |
| 244 vy_total += vy2; |
| 245 } |
| 246 |
| 247 if (swipe_enabled_ && (vx_total || vy_total)) { |
| 248 float vx = vx_total / count; |
| 249 float vy = vy_total / count; |
| 250 float vx_abs = std::abs(vx); |
| 251 float vy_abs = std::abs(vy); |
| 252 |
| 253 if (vx_abs < min_swipe_velocity_) |
| 254 vx_abs = vx = 0; |
| 255 if (vy_abs < min_swipe_velocity_) |
| 256 vy_abs = vy = 0; |
| 257 |
| 258 // Note that the ratio will be 0 if both velocites are below the min. |
| 259 float ratio = vx_abs > vy_abs ? vx_abs / std::max(vy_abs, 0.001f) |
| 260 : vy_abs / std::max(vx_abs, 0.001f); |
| 261 if (ratio > min_swipe_direction_component_ratio_) { |
| 262 if (vx_abs > vy_abs) |
| 263 vy = 0; |
| 264 else |
| 265 vx = 0; |
| 266 |
| 267 handled = listener_->OnSwipe(*current_down_event_, ev, vx, vy); |
| 268 } |
224 } | 269 } |
225 } | 270 } |
226 break; | 271 break; |
227 | 272 |
228 case MotionEvent::ACTION_DOWN: | 273 case MotionEvent::ACTION_DOWN: |
229 if (double_tap_listener_) { | 274 if (double_tap_listener_) { |
230 bool had_tap_message = timeout_handler_->HasTimeout(TAP); | 275 bool had_tap_message = timeout_handler_->HasTimeout(TAP); |
231 if (had_tap_message) | 276 if (had_tap_message) |
232 timeout_handler_->StopTimeout(TAP); | 277 timeout_handler_->StopTimeout(TAP); |
233 if (current_down_event_ && previous_up_event_ && had_tap_message && | 278 if (current_down_event_ && previous_up_event_ && had_tap_message && |
(...skipping 18 matching lines...) Expand all Loading... |
252 | 297 |
253 always_in_tap_region_ = true; | 298 always_in_tap_region_ = true; |
254 always_in_bigger_tap_region_ = true; | 299 always_in_bigger_tap_region_ = true; |
255 still_down_ = true; | 300 still_down_ = true; |
256 in_longpress_ = false; | 301 in_longpress_ = false; |
257 defer_confirm_single_tap_ = false; | 302 defer_confirm_single_tap_ = false; |
258 | 303 |
259 // Always start the SHOW_PRESS timer before the LONG_PRESS timer to ensure | 304 // Always start the SHOW_PRESS timer before the LONG_PRESS timer to ensure |
260 // proper timeout ordering. | 305 // proper timeout ordering. |
261 timeout_handler_->StartTimeout(SHOW_PRESS); | 306 timeout_handler_->StartTimeout(SHOW_PRESS); |
262 if (is_longpress_enabled_) | 307 if (longpress_enabled_) |
263 timeout_handler_->StartTimeout(LONG_PRESS); | 308 timeout_handler_->StartTimeout(LONG_PRESS); |
264 handled |= listener_->OnDown(ev); | 309 handled |= listener_->OnDown(ev); |
265 break; | 310 break; |
266 | 311 |
267 case MotionEvent::ACTION_MOVE: | 312 case MotionEvent::ACTION_MOVE: |
268 if (in_longpress_) | 313 if (in_longpress_) |
269 break; | 314 break; |
270 | 315 |
271 { | 316 { |
272 const float scroll_x = last_focus_x_ - focus_x; | 317 const float scroll_x = last_focus_x_ - focus_x; |
(...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
370 | 415 |
371 const float touch_slop = config.touch_slop + kSlopEpsilon; | 416 const float touch_slop = config.touch_slop + kSlopEpsilon; |
372 const float double_tap_touch_slop = touch_slop; | 417 const float double_tap_touch_slop = touch_slop; |
373 const float double_tap_slop = config.double_tap_slop + kSlopEpsilon; | 418 const float double_tap_slop = config.double_tap_slop + kSlopEpsilon; |
374 touch_slop_square_ = touch_slop * touch_slop; | 419 touch_slop_square_ = touch_slop * touch_slop; |
375 double_tap_touch_slop_square_ = double_tap_touch_slop * double_tap_touch_slop; | 420 double_tap_touch_slop_square_ = double_tap_touch_slop * double_tap_touch_slop; |
376 double_tap_slop_square_ = double_tap_slop * double_tap_slop; | 421 double_tap_slop_square_ = double_tap_slop * double_tap_slop; |
377 double_tap_timeout_ = config.double_tap_timeout; | 422 double_tap_timeout_ = config.double_tap_timeout; |
378 min_fling_velocity_ = config.minimum_fling_velocity; | 423 min_fling_velocity_ = config.minimum_fling_velocity; |
379 max_fling_velocity_ = config.maximum_fling_velocity; | 424 max_fling_velocity_ = config.maximum_fling_velocity; |
| 425 |
| 426 swipe_enabled_ = config.swipe_enabled; |
| 427 min_swipe_velocity_ = config.minimum_swipe_velocity; |
| 428 DCHECK_GT(config.maximum_swipe_deviation_angle, 0); |
| 429 DCHECK_LE(config.maximum_swipe_deviation_angle, 45); |
| 430 const float maximum_swipe_deviation_angle = |
| 431 std::min(45.f, std::max(0.001f, config.maximum_swipe_deviation_angle)); |
| 432 min_swipe_direction_component_ratio_ = |
| 433 1.f / tan(maximum_swipe_deviation_angle * kDegreesToRadians); |
380 } | 434 } |
381 | 435 |
382 void GestureDetector::OnShowPressTimeout() { | 436 void GestureDetector::OnShowPressTimeout() { |
383 listener_->OnShowPress(*current_down_event_); | 437 listener_->OnShowPress(*current_down_event_); |
384 } | 438 } |
385 | 439 |
386 void GestureDetector::OnLongPressTimeout() { | 440 void GestureDetector::OnLongPressTimeout() { |
387 timeout_handler_->StopTimeout(TAP); | 441 timeout_handler_->StopTimeout(TAP); |
388 defer_confirm_single_tap_ = false; | 442 defer_confirm_single_tap_ = false; |
389 in_longpress_ = listener_->OnLongPress(*current_down_event_); | 443 in_longpress_ = listener_->OnLongPress(*current_down_event_); |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
428 if (second_down.GetEventTime() - first_up.GetEventTime() > | 482 if (second_down.GetEventTime() - first_up.GetEventTime() > |
429 double_tap_timeout_) | 483 double_tap_timeout_) |
430 return false; | 484 return false; |
431 | 485 |
432 const float delta_x = first_down.GetX() - second_down.GetX(); | 486 const float delta_x = first_down.GetX() - second_down.GetX(); |
433 const float delta_y = first_down.GetY() - second_down.GetY(); | 487 const float delta_y = first_down.GetY() - second_down.GetY(); |
434 return (delta_x * delta_x + delta_y * delta_y < double_tap_slop_square_); | 488 return (delta_x * delta_x + delta_y * delta_y < double_tap_slop_square_); |
435 } | 489 } |
436 | 490 |
437 } // namespace ui | 491 } // namespace ui |
OLD | NEW |