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