gesture_detector.cc 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674
  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.
  4. #include "ui/events/gesture_detection/gesture_detector.h"
  5. #include <stddef.h>
  6. #include <algorithm>
  7. #include <cmath>
  8. #include "base/cxx17_backports.h"
  9. #include "base/memory/raw_ptr.h"
  10. #include "base/timer/timer.h"
  11. #include "build/build_config.h"
  12. #include "build/chromeos_buildflags.h"
  13. #include "ui/events/event_constants.h"
  14. #include "ui/events/gesture_detection/gesture_listeners.h"
  15. #include "ui/events/gesture_detection/motion_event.h"
  16. #include "ui/gfx/geometry/angle_conversions.h"
  17. namespace ui {
  18. namespace {
  19. // Minimum distance a scroll must have traveled from the last scroll/focal point
  20. // to trigger an |OnScroll| callback.
  21. const float kScrollEpsilon = .1f;
  22. // Constants used by TimeoutGestureHandler.
  23. enum TimeoutEvent {
  24. SHOW_PRESS = 0,
  25. SHORT_PRESS,
  26. LONG_PRESS,
  27. TAP,
  28. TIMEOUT_EVENT_COUNT
  29. };
  30. } // namespace
  31. // Note: These constants were taken directly from the default (unscaled)
  32. // versions found in Android's ViewConfiguration. Do not change these default
  33. // values without explicitly consulting an OWNER.
  34. GestureDetector::Config::Config()
  35. : shortpress_timeout(base::Milliseconds(400)),
  36. longpress_timeout(base::Milliseconds(500)),
  37. showpress_timeout(base::Milliseconds(180)),
  38. double_tap_timeout(base::Milliseconds(300)),
  39. double_tap_min_time(base::Milliseconds(40)),
  40. touch_slop(8),
  41. double_tap_slop(100),
  42. minimum_fling_velocity(50),
  43. maximum_fling_velocity(8000),
  44. swipe_enabled(false),
  45. minimum_swipe_velocity(20),
  46. maximum_swipe_deviation_angle(20.f),
  47. two_finger_tap_enabled(false),
  48. two_finger_tap_max_separation(300),
  49. two_finger_tap_timeout(base::Milliseconds(700)),
  50. single_tap_repeat_interval(1),
  51. #if BUILDFLAG(IS_CHROMEOS_ASH)
  52. stylus_button_accelerated_longpress_enabled(true),
  53. #else
  54. stylus_button_accelerated_longpress_enabled(false),
  55. #endif
  56. #if BUILDFLAG(IS_ANDROID)
  57. deep_press_accelerated_longpress_enabled(true),
  58. #else
  59. deep_press_accelerated_longpress_enabled(false),
  60. #endif
  61. velocity_tracker_strategy(VelocityTracker::Strategy::STRATEGY_DEFAULT) {
  62. }
  63. GestureDetector::Config::Config(const Config& other) = default;
  64. GestureDetector::Config::~Config() {}
  65. class GestureDetector::TimeoutGestureHandler {
  66. public:
  67. TimeoutGestureHandler(const Config& config, GestureDetector* gesture_detector)
  68. : gesture_detector_(gesture_detector) {
  69. DCHECK(config.shortpress_timeout <= config.longpress_timeout);
  70. timeout_callbacks_[SHOW_PRESS] = &GestureDetector::OnShowPressTimeout;
  71. timeout_delays_[SHOW_PRESS] = config.showpress_timeout;
  72. timeout_callbacks_[SHORT_PRESS] = &GestureDetector::OnShortPressTimeout;
  73. timeout_delays_[SHORT_PRESS] =
  74. config.shortpress_timeout + config.showpress_timeout;
  75. timeout_callbacks_[LONG_PRESS] = &GestureDetector::OnLongPressTimeout;
  76. timeout_delays_[LONG_PRESS] =
  77. config.longpress_timeout + config.showpress_timeout;
  78. timeout_callbacks_[TAP] = &GestureDetector::OnTapTimeout;
  79. timeout_delays_[TAP] = config.double_tap_timeout;
  80. if (config.task_runner) {
  81. timeout_timers_[SHOW_PRESS].SetTaskRunner(config.task_runner);
  82. timeout_timers_[LONG_PRESS].SetTaskRunner(config.task_runner);
  83. timeout_timers_[TAP].SetTaskRunner(config.task_runner);
  84. }
  85. }
  86. ~TimeoutGestureHandler() {
  87. Stop();
  88. }
  89. void StartTimeout(TimeoutEvent event) {
  90. timeout_timers_[event].Start(FROM_HERE, timeout_delays_[event],
  91. gesture_detector_.get(),
  92. timeout_callbacks_[event]);
  93. }
  94. void StopTimeout(TimeoutEvent event) { timeout_timers_[event].Stop(); }
  95. void Stop() {
  96. for (size_t i = SHOW_PRESS; i < TIMEOUT_EVENT_COUNT; ++i)
  97. timeout_timers_[i].Stop();
  98. }
  99. bool HasTimeout(TimeoutEvent event) const {
  100. return timeout_timers_[event].IsRunning();
  101. }
  102. private:
  103. typedef void (GestureDetector::*ReceiverMethod)();
  104. const raw_ptr<GestureDetector> gesture_detector_;
  105. base::OneShotTimer timeout_timers_[TIMEOUT_EVENT_COUNT];
  106. ReceiverMethod timeout_callbacks_[TIMEOUT_EVENT_COUNT];
  107. base::TimeDelta timeout_delays_[TIMEOUT_EVENT_COUNT];
  108. };
  109. GestureDetector::GestureDetector(
  110. const Config& config,
  111. GestureListener* listener,
  112. DoubleTapListener* optional_double_tap_listener)
  113. : timeout_handler_(new TimeoutGestureHandler(config, this)),
  114. listener_(listener),
  115. double_tap_listener_(optional_double_tap_listener),
  116. touch_slop_square_(0),
  117. double_tap_touch_slop_square_(0),
  118. double_tap_slop_square_(0),
  119. two_finger_tap_distance_square_(0),
  120. min_fling_velocity_(1),
  121. max_fling_velocity_(1),
  122. min_swipe_velocity_(0),
  123. min_swipe_direction_component_ratio_(0),
  124. still_down_(false),
  125. defer_confirm_single_tap_(false),
  126. all_pointers_within_slop_regions_(false),
  127. always_in_bigger_tap_region_(false),
  128. two_finger_tap_allowed_for_gesture_(false),
  129. is_double_tapping_(false),
  130. is_down_candidate_for_repeated_single_tap_(false),
  131. maximum_pointer_count_(0),
  132. current_single_tap_repeat_count_(0),
  133. single_tap_repeat_interval_(1),
  134. last_focus_x_(0),
  135. last_focus_y_(0),
  136. down_focus_x_(0),
  137. down_focus_y_(0),
  138. velocity_tracker_(config.velocity_tracker_strategy) {
  139. DCHECK(listener_);
  140. Init(config);
  141. }
  142. GestureDetector::~GestureDetector() {}
  143. bool GestureDetector::OnTouchEvent(const MotionEvent& ev,
  144. bool should_process_double_tap) {
  145. const MotionEvent::Action action = ev.GetAction();
  146. velocity_tracker_.AddMovement(ev);
  147. const bool pointer_up = action == MotionEvent::Action::POINTER_UP;
  148. const int skip_index = pointer_up ? ev.GetActionIndex() : -1;
  149. // Determine focal point.
  150. float sum_x = 0, sum_y = 0;
  151. const int count = static_cast<int>(ev.GetPointerCount());
  152. for (int i = 0; i < count; i++) {
  153. if (skip_index == i)
  154. continue;
  155. sum_x += ev.GetX(i);
  156. sum_y += ev.GetY(i);
  157. }
  158. const int div = pointer_up ? count - 1 : count;
  159. const float focus_x = sum_x / div;
  160. const float focus_y = sum_y / div;
  161. bool handled = false;
  162. switch (action) {
  163. case MotionEvent::Action::NONE:
  164. case MotionEvent::Action::HOVER_ENTER:
  165. case MotionEvent::Action::HOVER_EXIT:
  166. case MotionEvent::Action::HOVER_MOVE:
  167. case MotionEvent::Action::BUTTON_PRESS:
  168. case MotionEvent::Action::BUTTON_RELEASE:
  169. NOTREACHED();
  170. return handled;
  171. case MotionEvent::Action::POINTER_DOWN: {
  172. down_focus_x_ = last_focus_x_ = focus_x;
  173. down_focus_y_ = last_focus_y_ = focus_y;
  174. // Cancel long press and taps.
  175. CancelTaps();
  176. maximum_pointer_count_ = std::max(maximum_pointer_count_,
  177. static_cast<int>(ev.GetPointerCount()));
  178. // Even when two_finger_tap_allowed_for_gesture_ is false,
  179. // second pointer down information must be stored to check
  180. // the slop region in multi-finger scrolls.
  181. if (ev.GetPointerCount() == 2)
  182. secondary_pointer_down_event_ = ev.Clone();
  183. if (!two_finger_tap_allowed_for_gesture_)
  184. break;
  185. const int action_index = ev.GetActionIndex();
  186. const float dx = ev.GetX(action_index) - current_down_event_->GetX();
  187. const float dy = ev.GetY(action_index) - current_down_event_->GetY();
  188. if (maximum_pointer_count_ > 2 ||
  189. dx * dx + dy * dy >= two_finger_tap_distance_square_)
  190. two_finger_tap_allowed_for_gesture_ = false;
  191. } break;
  192. case MotionEvent::Action::POINTER_UP: {
  193. down_focus_x_ = last_focus_x_ = focus_x;
  194. down_focus_y_ = last_focus_y_ = focus_y;
  195. // Check the dot product of current velocities.
  196. // If the pointer that left was opposing another velocity vector, clear.
  197. velocity_tracker_.ComputeCurrentVelocity(1000, max_fling_velocity_);
  198. const int up_index = ev.GetActionIndex();
  199. const int id1 = ev.GetPointerId(up_index);
  200. const float vx1 = velocity_tracker_.GetXVelocity(id1);
  201. const float vy1 = velocity_tracker_.GetYVelocity(id1);
  202. float vx_total = vx1;
  203. float vy_total = vy1;
  204. for (int i = 0; i < count; i++) {
  205. if (i == up_index)
  206. continue;
  207. const int id2 = ev.GetPointerId(i);
  208. const float vx2 = velocity_tracker_.GetXVelocity(id2);
  209. const float vy2 = velocity_tracker_.GetYVelocity(id2);
  210. const float dot = vx1 * vx2 + vy1 * vy2;
  211. if (dot < 0) {
  212. vx_total = 0;
  213. vy_total = 0;
  214. velocity_tracker_.Clear();
  215. break;
  216. }
  217. vx_total += vx2;
  218. vy_total += vy2;
  219. }
  220. handled = HandleSwipeIfNeeded(ev, vx_total / count, vy_total / count);
  221. if (two_finger_tap_allowed_for_gesture_ && ev.GetPointerCount() == 2 &&
  222. secondary_pointer_down_event_ &&
  223. (ev.GetEventTime() - secondary_pointer_down_event_->GetEventTime() <=
  224. two_finger_tap_timeout_)) {
  225. handled = listener_->OnTwoFingerTap(*current_down_event_, ev);
  226. }
  227. two_finger_tap_allowed_for_gesture_ = false;
  228. } break;
  229. case MotionEvent::Action::DOWN: {
  230. bool is_repeated_tap =
  231. current_down_event_ && previous_up_event_ &&
  232. IsRepeatedTap(*current_down_event_, *previous_up_event_, ev,
  233. should_process_double_tap);
  234. if (double_tap_listener_ && should_process_double_tap) {
  235. is_down_candidate_for_repeated_single_tap_ = false;
  236. bool had_tap_message = timeout_handler_->HasTimeout(TAP);
  237. if (had_tap_message)
  238. timeout_handler_->StopTimeout(TAP);
  239. if (is_repeated_tap && had_tap_message) {
  240. // This is a second tap.
  241. is_double_tapping_ = true;
  242. // Give a callback with the first tap of the double-tap.
  243. handled |= double_tap_listener_->OnDoubleTap(*current_down_event_);
  244. // Give a callback with down event of the double-tap.
  245. handled |= double_tap_listener_->OnDoubleTapEvent(ev);
  246. } else {
  247. // This is a first tap.
  248. DCHECK(double_tap_timeout_.is_positive());
  249. timeout_handler_->StartTimeout(TAP);
  250. }
  251. } else {
  252. is_down_candidate_for_repeated_single_tap_ = is_repeated_tap;
  253. }
  254. down_focus_x_ = last_focus_x_ = focus_x;
  255. down_focus_y_ = last_focus_y_ = focus_y;
  256. current_down_event_ = ev.Clone();
  257. secondary_pointer_down_event_.reset();
  258. all_pointers_within_slop_regions_ = true;
  259. always_in_bigger_tap_region_ = true;
  260. still_down_ = true;
  261. defer_confirm_single_tap_ = false;
  262. two_finger_tap_allowed_for_gesture_ = two_finger_tap_enabled_;
  263. maximum_pointer_count_ = 1;
  264. // Always start the SHOW_PRESS timer before the LONG_PRESS timer to
  265. // ensure proper timeout ordering.
  266. if (showpress_enabled_)
  267. timeout_handler_->StartTimeout(SHOW_PRESS);
  268. if (press_and_hold_enabled_) {
  269. timeout_handler_->StartTimeout(SHORT_PRESS);
  270. timeout_handler_->StartTimeout(LONG_PRESS);
  271. }
  272. handled |= listener_->OnDown(ev);
  273. } break;
  274. case MotionEvent::Action::MOVE: {
  275. const float scroll_x = last_focus_x_ - focus_x;
  276. const float scroll_y = last_focus_y_ - focus_y;
  277. if (is_double_tapping_) {
  278. // Give the move events of the double-tap.
  279. DCHECK(double_tap_listener_);
  280. handled |= double_tap_listener_->OnDoubleTapEvent(ev);
  281. } else if (all_pointers_within_slop_regions_) {
  282. if (!IsWithinTouchSlop(ev)) {
  283. handled = listener_->OnScroll(
  284. *current_down_event_, ev,
  285. (maximum_pointer_count_ > 1 && secondary_pointer_down_event_)
  286. ? *secondary_pointer_down_event_
  287. : ev,
  288. scroll_x, scroll_y);
  289. last_focus_x_ = focus_x;
  290. last_focus_y_ = focus_y;
  291. all_pointers_within_slop_regions_ = false;
  292. timeout_handler_->Stop();
  293. }
  294. const float delta_x = focus_x - down_focus_x_;
  295. const float delta_y = focus_y - down_focus_y_;
  296. const float distance_square = delta_x * delta_x + delta_y * delta_y;
  297. if (distance_square > double_tap_touch_slop_square_)
  298. always_in_bigger_tap_region_ = false;
  299. } else if (std::abs(scroll_x) > kScrollEpsilon ||
  300. std::abs(scroll_y) > kScrollEpsilon) {
  301. handled = listener_->OnScroll(
  302. *current_down_event_, ev,
  303. (maximum_pointer_count_ > 1 && secondary_pointer_down_event_)
  304. ? *secondary_pointer_down_event_
  305. : ev,
  306. scroll_x, scroll_y);
  307. last_focus_x_ = focus_x;
  308. last_focus_y_ = focus_y;
  309. }
  310. // Try to activate long press gesture early.
  311. if (ev.GetPointerCount() == 1 &&
  312. timeout_handler_->HasTimeout(LONG_PRESS)) {
  313. if (ev.GetToolType(0) == MotionEvent::ToolType::STYLUS &&
  314. stylus_button_accelerated_longpress_enabled_ &&
  315. (ev.GetFlags() & ui::EF_LEFT_MOUSE_BUTTON)) {
  316. // This will generate a ET_GESTURE_LONG_PRESS event with
  317. // EF_LEFT_MOUSE_BUTTON, which is consumed by MetalayerMode if that
  318. // feature is enabled, because MetalayerMode is also activated by a
  319. // stylus button press and has precedence over this press acceleration
  320. // feature.
  321. ActivateShortPressGesture(ev);
  322. ActivateLongPressGesture(ev);
  323. } else if (ev.GetToolType(0) == MotionEvent::ToolType::FINGER &&
  324. deep_press_accelerated_longpress_enabled_ &&
  325. ev.GetClassification() ==
  326. MotionEvent::Classification::DEEP_PRESS) {
  327. // This uses the current_down_event_ to generate the short/long press
  328. // gesture which keeps the original coordinates in case the current
  329. // move event has a different coordinate.
  330. OnShortPressTimeout();
  331. OnLongPressTimeout();
  332. }
  333. }
  334. if (!two_finger_tap_allowed_for_gesture_)
  335. break;
  336. // Two-finger tap should be prevented if either pointer exceeds its
  337. // (independent) slop region.
  338. // If the event has had more than two pointers down at any time,
  339. // two finger tap should be prevented.
  340. if (maximum_pointer_count_ > 2 || !IsWithinTouchSlop(ev)) {
  341. two_finger_tap_allowed_for_gesture_ = false;
  342. }
  343. } break;
  344. case MotionEvent::Action::UP:
  345. still_down_ = false;
  346. {
  347. if (is_double_tapping_ && should_process_double_tap) {
  348. // Finally, give the up event of the double-tap.
  349. DCHECK(double_tap_listener_);
  350. handled |= double_tap_listener_->OnDoubleTapEvent(ev);
  351. } else if (all_pointers_within_slop_regions_ &&
  352. maximum_pointer_count_ == 1) {
  353. if (is_down_candidate_for_repeated_single_tap_) {
  354. current_single_tap_repeat_count_ =
  355. (1 + current_single_tap_repeat_count_) %
  356. single_tap_repeat_interval_;
  357. } else {
  358. current_single_tap_repeat_count_ = 0;
  359. }
  360. handled = listener_->OnSingleTapUp(
  361. ev, 1 + current_single_tap_repeat_count_);
  362. if (defer_confirm_single_tap_ && should_process_double_tap &&
  363. double_tap_listener_) {
  364. double_tap_listener_->OnSingleTapConfirmed(ev);
  365. }
  366. } else if (!all_pointers_within_slop_regions_) {
  367. // A fling must travel the minimum tap distance.
  368. current_single_tap_repeat_count_ = 0;
  369. const int pointer_id = ev.GetPointerId(0);
  370. velocity_tracker_.ComputeCurrentVelocity(1000, max_fling_velocity_);
  371. const float velocity_y = velocity_tracker_.GetYVelocity(pointer_id);
  372. const float velocity_x = velocity_tracker_.GetXVelocity(pointer_id);
  373. if ((std::abs(velocity_y) > min_fling_velocity_) ||
  374. (std::abs(velocity_x) > min_fling_velocity_)) {
  375. handled = listener_->OnFling(*current_down_event_, ev, velocity_x,
  376. velocity_y);
  377. }
  378. handled |= HandleSwipeIfNeeded(ev, velocity_x, velocity_y);
  379. }
  380. previous_up_event_ = ev.Clone();
  381. velocity_tracker_.Clear();
  382. is_double_tapping_ = false;
  383. defer_confirm_single_tap_ = false;
  384. timeout_handler_->StopTimeout(SHOW_PRESS);
  385. timeout_handler_->StopTimeout(SHORT_PRESS);
  386. timeout_handler_->StopTimeout(LONG_PRESS);
  387. }
  388. maximum_pointer_count_ = 0;
  389. break;
  390. case MotionEvent::Action::CANCEL:
  391. Cancel();
  392. break;
  393. }
  394. return handled;
  395. }
  396. void GestureDetector::SetDoubleTapListener(
  397. DoubleTapListener* double_tap_listener) {
  398. if (double_tap_listener == double_tap_listener_)
  399. return;
  400. DCHECK(!is_double_tapping_);
  401. // Null'ing the double-tap listener should flush an active tap timeout.
  402. if (!double_tap_listener) {
  403. if (timeout_handler_->HasTimeout(TAP)) {
  404. timeout_handler_->StopTimeout(TAP);
  405. OnTapTimeout();
  406. }
  407. }
  408. double_tap_listener_ = double_tap_listener;
  409. }
  410. void GestureDetector::Init(const Config& config) {
  411. DCHECK(listener_);
  412. // Using a small epsilon when comparing slop distances allows pixel
  413. // perfect slop determination when using fractional DIP coordinates
  414. // (assuming the slop region and DPI scale are reasonably
  415. // proportioned).
  416. const float kSlopEpsilon = .05f;
  417. const float touch_slop = config.touch_slop + kSlopEpsilon;
  418. const float double_tap_touch_slop = touch_slop;
  419. const float double_tap_slop = config.double_tap_slop + kSlopEpsilon;
  420. touch_slop_square_ = touch_slop * touch_slop;
  421. double_tap_touch_slop_square_ = double_tap_touch_slop * double_tap_touch_slop;
  422. double_tap_slop_square_ = double_tap_slop * double_tap_slop;
  423. double_tap_timeout_ = config.double_tap_timeout;
  424. double_tap_min_time_ = config.double_tap_min_time;
  425. DCHECK(double_tap_min_time_ < double_tap_timeout_);
  426. min_fling_velocity_ = config.minimum_fling_velocity;
  427. max_fling_velocity_ = config.maximum_fling_velocity;
  428. swipe_enabled_ = config.swipe_enabled;
  429. min_swipe_velocity_ = config.minimum_swipe_velocity;
  430. DCHECK_GT(config.maximum_swipe_deviation_angle, 0);
  431. DCHECK_LE(config.maximum_swipe_deviation_angle, 45);
  432. const float maximum_swipe_deviation_angle =
  433. base::clamp(config.maximum_swipe_deviation_angle, 0.001f, 45.0f);
  434. min_swipe_direction_component_ratio_ =
  435. 1.f / tan(gfx::DegToRad(maximum_swipe_deviation_angle));
  436. two_finger_tap_enabled_ = config.two_finger_tap_enabled;
  437. two_finger_tap_distance_square_ = config.two_finger_tap_max_separation *
  438. config.two_finger_tap_max_separation;
  439. two_finger_tap_timeout_ = config.two_finger_tap_timeout;
  440. DCHECK_GE(config.single_tap_repeat_interval, 1);
  441. single_tap_repeat_interval_ = config.single_tap_repeat_interval;
  442. stylus_button_accelerated_longpress_enabled_ =
  443. config.stylus_button_accelerated_longpress_enabled;
  444. deep_press_accelerated_longpress_enabled_ =
  445. config.deep_press_accelerated_longpress_enabled;
  446. }
  447. void GestureDetector::OnShowPressTimeout() {
  448. listener_->OnShowPress(*current_down_event_);
  449. }
  450. void GestureDetector::OnShortPressTimeout() {
  451. ActivateShortPressGesture(*current_down_event_);
  452. }
  453. void GestureDetector::OnLongPressTimeout() {
  454. ActivateLongPressGesture(*current_down_event_);
  455. }
  456. void GestureDetector::OnTapTimeout() {
  457. if (!double_tap_listener_)
  458. return;
  459. if (!still_down_) {
  460. CHECK(previous_up_event_);
  461. double_tap_listener_->OnSingleTapConfirmed(*previous_up_event_);
  462. } else {
  463. defer_confirm_single_tap_ = true;
  464. }
  465. }
  466. void GestureDetector::ActivateShortPressGesture(const MotionEvent& ev) {
  467. timeout_handler_->StopTimeout(SHORT_PRESS);
  468. listener_->OnShortPress(ev);
  469. }
  470. void GestureDetector::ActivateLongPressGesture(const MotionEvent& ev) {
  471. timeout_handler_->Stop();
  472. defer_confirm_single_tap_ = false;
  473. listener_->OnLongPress(ev);
  474. }
  475. void GestureDetector::Cancel() {
  476. // Stop waiting for a second tap and send a GESTURE_TAP_CANCEL to keep the
  477. // gesture stream valid.
  478. if (timeout_handler_->HasTimeout(TAP))
  479. listener_->OnTapCancel(*current_down_event_);
  480. CancelTaps();
  481. velocity_tracker_.Clear();
  482. all_pointers_within_slop_regions_ = false;
  483. still_down_ = false;
  484. }
  485. void GestureDetector::CancelTaps() {
  486. timeout_handler_->Stop();
  487. is_double_tapping_ = false;
  488. always_in_bigger_tap_region_ = false;
  489. defer_confirm_single_tap_ = false;
  490. is_down_candidate_for_repeated_single_tap_ = false;
  491. current_single_tap_repeat_count_ = 0;
  492. }
  493. bool GestureDetector::IsRepeatedTap(const MotionEvent& first_down,
  494. const MotionEvent& first_up,
  495. const MotionEvent& second_down,
  496. bool should_process_double_tap) const {
  497. if (!always_in_bigger_tap_region_)
  498. return false;
  499. const base::TimeDelta delta_time =
  500. second_down.GetEventTime() - first_up.GetEventTime();
  501. if (delta_time > double_tap_timeout_)
  502. return false;
  503. // Only use the min time when in double-tap detection mode. For repeated
  504. // single taps the risk of accidental repeat detection (e.g., from fingernail
  505. // interference) is minimal.
  506. if (should_process_double_tap && double_tap_listener_ &&
  507. delta_time < double_tap_min_time_) {
  508. return false;
  509. }
  510. const float delta_x = first_down.GetX() - second_down.GetX();
  511. const float delta_y = first_down.GetY() - second_down.GetY();
  512. return (delta_x * delta_x + delta_y * delta_y < double_tap_slop_square_);
  513. }
  514. bool GestureDetector::HandleSwipeIfNeeded(const MotionEvent& up,
  515. float vx,
  516. float vy) {
  517. if (!swipe_enabled_ || (!vx && !vy))
  518. return false;
  519. float vx_abs = std::abs(vx);
  520. float vy_abs = std::abs(vy);
  521. if (vx_abs < min_swipe_velocity_)
  522. vx_abs = vx = 0;
  523. if (vy_abs < min_swipe_velocity_)
  524. vy_abs = vy = 0;
  525. // Note that the ratio will be 0 if both velocites are below the min.
  526. float ratio = vx_abs > vy_abs ? vx_abs / std::max(vy_abs, 0.001f)
  527. : vy_abs / std::max(vx_abs, 0.001f);
  528. if (ratio < min_swipe_direction_component_ratio_)
  529. return false;
  530. if (vx_abs > vy_abs)
  531. vy = 0;
  532. else
  533. vx = 0;
  534. return listener_->OnSwipe(*current_down_event_, up, vx, vy);
  535. }
  536. bool GestureDetector::IsWithinTouchSlop(const MotionEvent& ev) {
  537. // If there have been more than two down pointers in the touch sequence,
  538. // tapping is not possible. Slop region check is not needed.
  539. if (maximum_pointer_count_ > 2)
  540. return false;
  541. for (size_t i = 0; i < ev.GetPointerCount(); i++) {
  542. const int pointer_id = ev.GetPointerId(i);
  543. const MotionEvent* source_pointer_down_event = GetSourcePointerDownEvent(
  544. *current_down_event_.get(), secondary_pointer_down_event_.get(),
  545. pointer_id);
  546. if (!source_pointer_down_event)
  547. return false;
  548. int source_index =
  549. source_pointer_down_event->FindPointerIndexOfId(pointer_id);
  550. DCHECK_GE(source_index, 0);
  551. if (source_index < 0)
  552. return false;
  553. float dx = source_pointer_down_event->GetX(source_index) - ev.GetX(i);
  554. float dy = source_pointer_down_event->GetY(source_index) - ev.GetY(i);
  555. if (dx * dx + dy * dy > touch_slop_square_)
  556. return false;
  557. }
  558. return true;
  559. }
  560. const MotionEvent* GestureDetector::GetSourcePointerDownEvent(
  561. const MotionEvent& current_down_event,
  562. const MotionEvent* secondary_pointer_down_event,
  563. const int pointer_id) {
  564. if (current_down_event.GetPointerId(0) == pointer_id)
  565. return &current_down_event;
  566. // Secondary pointer down event is sometimes missing (crbug.com/704426), the
  567. // source pointer down event is not found in these cases.
  568. // crbug.com/704426 is the only related bug report and we don't have any
  569. // reliable repro of the bug.
  570. if (!secondary_pointer_down_event)
  571. return nullptr;
  572. for (size_t i = 0; i < secondary_pointer_down_event->GetPointerCount(); i++) {
  573. if (secondary_pointer_down_event->GetPointerId(i) == pointer_id)
  574. return secondary_pointer_down_event;
  575. }
  576. return nullptr;
  577. }
  578. } // namespace ui