| Index: ui/events/gesture_detection/gesture_detector.cc
|
| diff --git a/ui/events/gesture_detection/gesture_detector.cc b/ui/events/gesture_detection/gesture_detector.cc
|
| index 7ea0a3e0c7204a1ac259a46647e9067871df6030..ec5e5ae86884fd8f70e6b98244d1eabda553affa 100644
|
| --- a/ui/events/gesture_detection/gesture_detector.cc
|
| +++ b/ui/events/gesture_detection/gesture_detector.cc
|
| @@ -55,8 +55,8 @@ GestureDetector::Config::Config()
|
| two_finger_tap_enabled(false),
|
| two_finger_tap_max_separation(300),
|
| two_finger_tap_timeout(base::TimeDelta::FromMilliseconds(700)),
|
| - velocity_tracker_strategy(VelocityTracker::Strategy::STRATEGY_DEFAULT) {
|
| -}
|
| + single_tap_repeat_interval(1),
|
| + velocity_tracker_strategy(VelocityTracker::Strategy::STRATEGY_DEFAULT) {}
|
|
|
| GestureDetector::Config::~Config() {}
|
|
|
| @@ -129,6 +129,9 @@ GestureDetector::GestureDetector(
|
| always_in_bigger_tap_region_(false),
|
| two_finger_tap_allowed_for_gesture_(false),
|
| is_double_tapping_(false),
|
| + is_down_candidate_for_repeated_single_tap_(false),
|
| + current_single_tap_repeat_count_(0),
|
| + single_tap_repeat_interval_(1),
|
| last_focus_x_(0),
|
| last_focus_y_(0),
|
| down_focus_x_(0),
|
| @@ -234,14 +237,16 @@ bool GestureDetector::OnTouchEvent(const MotionEvent& ev) {
|
| two_finger_tap_allowed_for_gesture_ = false;
|
| } break;
|
|
|
| - case MotionEvent::ACTION_DOWN:
|
| + case MotionEvent::ACTION_DOWN: {
|
| + bool is_repeated_tap =
|
| + current_down_event_ && previous_up_event_ &&
|
| + IsRepeatedTap(*current_down_event_, *previous_up_event_, ev);
|
| if (double_tap_listener_) {
|
| + is_down_candidate_for_repeated_single_tap_ = false;
|
| bool had_tap_message = timeout_handler_->HasTimeout(TAP);
|
| if (had_tap_message)
|
| timeout_handler_->StopTimeout(TAP);
|
| - if (current_down_event_ && previous_up_event_ && had_tap_message &&
|
| - IsConsideredDoubleTap(
|
| - *current_down_event_, *previous_up_event_, ev)) {
|
| + if (is_repeated_tap && had_tap_message) {
|
| // This is a second tap.
|
| is_double_tapping_ = true;
|
| // Give a callback with the first tap of the double-tap.
|
| @@ -253,6 +258,8 @@ bool GestureDetector::OnTouchEvent(const MotionEvent& ev) {
|
| DCHECK(double_tap_timeout_ > base::TimeDelta());
|
| timeout_handler_->StartTimeout(TAP);
|
| }
|
| + } else {
|
| + is_down_candidate_for_repeated_single_tap_ = is_repeated_tap;
|
| }
|
|
|
| down_focus_x_ = last_focus_x_ = focus_x;
|
| @@ -273,7 +280,7 @@ bool GestureDetector::OnTouchEvent(const MotionEvent& ev) {
|
| if (longpress_enabled_)
|
| timeout_handler_->StartTimeout(LONG_PRESS);
|
| handled |= listener_->OnDown(ev);
|
| - break;
|
| + } break;
|
|
|
| case MotionEvent::ACTION_MOVE:
|
| {
|
| @@ -343,12 +350,20 @@ bool GestureDetector::OnTouchEvent(const MotionEvent& ev) {
|
| DCHECK(double_tap_listener_);
|
| handled |= double_tap_listener_->OnDoubleTapEvent(ev);
|
| } else if (always_in_tap_region_) {
|
| - handled = listener_->OnSingleTapUp(ev);
|
| + if (is_down_candidate_for_repeated_single_tap_) {
|
| + current_single_tap_repeat_count_ =
|
| + (1 + current_single_tap_repeat_count_) %
|
| + single_tap_repeat_interval_;
|
| + } else {
|
| + current_single_tap_repeat_count_ = 0;
|
| + }
|
| + handled = listener_->OnSingleTapUp(
|
| + ev, 1 + current_single_tap_repeat_count_);
|
| if (defer_confirm_single_tap_ && double_tap_listener_ != NULL) {
|
| double_tap_listener_->OnSingleTapConfirmed(ev);
|
| }
|
| } else {
|
| -
|
| + current_single_tap_repeat_count_ = 0;
|
| // A fling must travel the minimum tap distance.
|
| const int pointer_id = ev.GetPointerId(0);
|
| velocity_tracker_.ComputeCurrentVelocity(1000, max_fling_velocity_);
|
| @@ -428,6 +443,9 @@ void GestureDetector::Init(const Config& config) {
|
| two_finger_tap_distance_square_ = config.two_finger_tap_max_separation *
|
| config.two_finger_tap_max_separation;
|
| two_finger_tap_timeout_ = config.two_finger_tap_timeout;
|
| +
|
| + DCHECK_GE(config.single_tap_repeat_interval, 1);
|
| + single_tap_repeat_interval_ = config.single_tap_repeat_interval;
|
| }
|
|
|
| void GestureDetector::OnShowPressTimeout() {
|
| @@ -463,18 +481,25 @@ void GestureDetector::CancelTaps() {
|
| always_in_tap_region_ = false;
|
| always_in_bigger_tap_region_ = false;
|
| defer_confirm_single_tap_ = false;
|
| + is_down_candidate_for_repeated_single_tap_ = false;
|
| + current_single_tap_repeat_count_ = 0;
|
| }
|
|
|
| -bool GestureDetector::IsConsideredDoubleTap(
|
| - const MotionEvent& first_down,
|
| - const MotionEvent& first_up,
|
| - const MotionEvent& second_down) const {
|
| +bool GestureDetector::IsRepeatedTap(const MotionEvent& first_down,
|
| + const MotionEvent& first_up,
|
| + const MotionEvent& second_down) const {
|
| if (!always_in_bigger_tap_region_)
|
| return false;
|
|
|
| const base::TimeDelta delta_time =
|
| second_down.GetEventTime() - first_up.GetEventTime();
|
| - if (delta_time < double_tap_min_time_ || delta_time > double_tap_timeout_)
|
| + if (delta_time > double_tap_timeout_)
|
| + return false;
|
| +
|
| + // Only use the min time when in double-tap detection mode. For repeated
|
| + // single taps the risk of accidental repeat detection (e.g., from fingernail
|
| + // interference) is minimal.
|
| + if (double_tap_listener_ && delta_time < double_tap_min_time_)
|
| return false;
|
|
|
| const float delta_x = first_down.GetX() - second_down.GetX();
|
|
|