| // Copyright 2014 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef UI_EVENTS_GESTURE_DETECTION_GESTURE_DETECTOR_H_ |
| #define UI_EVENTS_GESTURE_DETECTION_GESTURE_DETECTOR_H_ |
| |
| #include <memory> |
| |
| #include "base/memory/raw_ptr.h" |
| #include "base/task/sequenced_task_runner.h" |
| #include "base/time/time.h" |
| #include "ui/events/gesture_detection/gesture_detection_export.h" |
| #include "ui/events/velocity_tracker/velocity_tracker_state.h" |
| |
| namespace ui { |
| |
| class DoubleTapListener; |
| class GestureListener; |
| class MotionEvent; |
| |
| // Port of GestureDetector.java from Android |
| // * platform/frameworks/base/core/java/android/view/GestureDetector.java |
| // * Change-Id: Ib470735ec929b0b358fca4597e92dc81084e675f |
| // * Please update the Change-Id as upstream Android changes are pulled. |
| class GESTURE_DETECTION_EXPORT GestureDetector { |
| public: |
| struct GESTURE_DETECTION_EXPORT Config { |
| Config(); |
| Config(const Config& other); |
| ~Config(); |
| |
| // Note: Most of these constants were taken directly from the default |
| // (unscaled) versions found in Android's ViewConfiguration. Do not change |
| // these default values without explicitly consulting an OWNER. |
| // |
| // Many of these default values get over-ridden by GestureConfiguration |
| // parameters. We have encountered exceptions to this behavior in certain |
| // tests, see https://crbug.com/1294244. |
| |
| base::TimeDelta shortpress_timeout = base::Milliseconds(400); |
| base::TimeDelta longpress_timeout = base::Milliseconds(500); |
| base::TimeDelta showpress_timeout = base::Milliseconds(180); |
| base::TimeDelta double_tap_timeout = base::Milliseconds(300); |
| |
| // The minimum duration between the first tap's up event and the second |
| // tap's down event for an interaction to be considered a double-tap. |
| base::TimeDelta double_tap_min_time = base::Milliseconds(40); |
| |
| // Distance a stylus-contact can wander before a scroll will occur (in |
| // dips). |
| float stylus_slop = 12; |
| |
| // Distance a touch can wander before a scroll will occur (in dips). |
| float touch_slop = 8; |
| |
| // Distance the first touch can wander before it is no longer considered a |
| // double tap (in dips). |
| float double_tap_slop = 100; |
| |
| // Minimum velocity to initiate a fling (in dips/second). |
| float minimum_fling_velocity = 50; |
| |
| // Maximum velocity of an initiated fling (in dips/second). |
| float maximum_fling_velocity = 8000; |
| |
| // Whether |OnSwipe| should be called after a secondary touch is released |
| // while a logical swipe gesture is active. Defaults to false. |
| bool swipe_enabled = false; |
| |
| // Minimum velocity to initiate a swipe (in dips/second). |
| float minimum_swipe_velocity = 20; |
| |
| // Maximum angle of the swipe from its dominant component axis, between |
| // (0, 45] degrees. The closer this is to 0, the closer the dominant |
| // direction of the swipe must be to up, down left or right. |
| float maximum_swipe_deviation_angle = 20; |
| |
| // Whether |OnTwoFingerTap| should be called for two finger tap |
| // gestures. Defaults to false. |
| bool two_finger_tap_enabled = false; |
| |
| // Maximum distance between pointers for a two finger tap. |
| float two_finger_tap_max_separation = 300; |
| |
| // Maximum time the second pointer can be active for a two finger tap. |
| base::TimeDelta two_finger_tap_timeout = base::Milliseconds(700); |
| |
| // Single tap count repetition length. Defaults to 1 (no repetition count). |
| // Note that when double-tap detection is enabled, the single tap repeat |
| // count will always be 1. |
| int single_tap_repeat_interval = 1; |
| |
| // Whether a longpress should be generated immediately when a stylus button |
| // is pressed, given that the longpress timeout is still active. |
| #if BUILDFLAG(IS_CHROMEOS_ASH) |
| bool stylus_button_accelerated_longpress_enabled = true; |
| #else |
| bool stylus_button_accelerated_longpress_enabled = false; |
| #endif |
| |
| // Whether a longpress should be generated immediately when a pointer is |
| // deep-pressing, given that the longpress timeout is still active. |
| #if BUILDFLAG(IS_ANDROID) |
| bool deep_press_accelerated_longpress_enabled = true; |
| #else |
| bool deep_press_accelerated_longpress_enabled = false; |
| #endif |
| |
| VelocityTracker::Strategy velocity_tracker_strategy = |
| VelocityTracker::Strategy::STRATEGY_DEFAULT; |
| |
| // If set the task runner to use for tasks generated by the |
| // GestureDetector. If null the current sequence is used. This should be a |
| // Browser UI thread task runner. |
| scoped_refptr<base::SequencedTaskRunner> task_runner; |
| }; |
| |
| GestureDetector(const Config& config, |
| GestureListener* listener, |
| DoubleTapListener* optional_double_tap_listener); |
| |
| GestureDetector(const GestureDetector&) = delete; |
| GestureDetector& operator=(const GestureDetector&) = delete; |
| |
| ~GestureDetector(); |
| |
| bool OnTouchEvent(const MotionEvent& ev, bool should_process_double_tap); |
| |
| // Setting a valid |double_tap_listener| will enable double-tap detection, |
| // wherein calls to |OnSimpleTapConfirmed| are delayed by the tap timeout. |
| // Note: The listener must never be changed while |is_double_tapping| is true. |
| void SetDoubleTapListener(DoubleTapListener* double_tap_listener); |
| |
| bool has_doubletap_listener() const { return !!double_tap_listener_; } |
| |
| bool is_double_tapping() const { return is_double_tapping_; } |
| |
| // Enables or disables gestures that require holding the finger steady for a |
| // while (i.e. both short-press and long-press). |
| void set_press_and_hold_enabled(bool enabled) { |
| press_and_hold_enabled_ = enabled; |
| } |
| void set_showpress_enabled(bool enabled) { showpress_enabled_ = enabled; } |
| |
| // Returns the event storing the initial position of the pointer with given |
| // pointer ID. This returns nullptr if the source event isn't |
| // current_down_event_ or secondary_pointer_down_event_. |
| const MotionEvent* GetSourcePointerDownEvent( |
| const MotionEvent& current_down_event, |
| const MotionEvent* secondary_pointer_down_event, |
| const int pointer_id); |
| |
| private: |
| void Init(const Config& config); |
| void OnShowPressTimeout(); |
| void OnShortPressTimeout(); |
| void OnLongPressTimeout(); |
| void OnTapTimeout(); |
| void ActivateShortPressGesture(const MotionEvent& ev); |
| void ActivateLongPressGesture(const MotionEvent& ev); |
| void Cancel(); |
| void CancelTaps(); |
| bool IsRepeatedTap(const MotionEvent& first_down, |
| const MotionEvent& first_up, |
| const MotionEvent& second_down, |
| bool should_process_double_tap) const; |
| bool HandleSwipeIfNeeded(const MotionEvent& up, float vx, float vy); |
| bool IsWithinSlopForTap(const MotionEvent& ev); |
| |
| class TimeoutGestureHandler; |
| std::unique_ptr<TimeoutGestureHandler> timeout_handler_; |
| const raw_ptr<GestureListener> listener_; |
| raw_ptr<DoubleTapListener> double_tap_listener_; |
| |
| float stylus_slop_square_ = 0; |
| float touch_slop_square_ = 0; |
| float double_tap_touch_slop_square_ = 0; |
| float double_tap_slop_square_ = 0; |
| float two_finger_tap_distance_square_ = 0; |
| float min_fling_velocity_ = 1; |
| float max_fling_velocity_ = 1; |
| float min_swipe_velocity_ = 0; |
| float min_swipe_direction_component_ratio_ = 0; |
| base::TimeDelta double_tap_timeout_; |
| base::TimeDelta two_finger_tap_timeout_; |
| base::TimeDelta double_tap_min_time_; |
| |
| bool still_down_ = false; |
| bool defer_confirm_single_tap_ = false; |
| bool all_pointers_within_slop_regions_ = false; |
| bool always_in_bigger_tap_region_ = false; |
| bool two_finger_tap_allowed_for_gesture_ = false; |
| |
| std::unique_ptr<MotionEvent> current_down_event_; |
| std::unique_ptr<MotionEvent> previous_up_event_; |
| std::unique_ptr<MotionEvent> secondary_pointer_down_event_; |
| |
| // True when the user is still touching for the second tap (down, move, and |
| // up events). Can only be true if there is a double tap listener attached. |
| bool is_double_tapping_ = false; |
| |
| // Whether the current ACTION_DOWN event meets the criteria for being a |
| // repeated tap. Note that it will be considered a repeated tap only if the |
| // corresponding ACTION_UP yields a valid tap and double-tap detection is |
| // disabled. |
| bool is_down_candidate_for_repeated_single_tap_ = false; |
| |
| // Stores the maximum number of pointers that have been down simultaneously |
| // during the current touch sequence. |
| int maximum_pointer_count_ = 0; |
| |
| // The number of repeated taps in the current sequence, i.e., for the initial |
| // tap this is 0, for the first *repeated* tap 1, etc... |
| int current_single_tap_repeat_count_ = 0; |
| int single_tap_repeat_interval_ = 1; |
| |
| float last_focus_x_ = 0; |
| float last_focus_y_ = 0; |
| float down_focus_x_ = 0; |
| float down_focus_y_ = 0; |
| |
| bool stylus_button_accelerated_longpress_enabled_ = false; |
| bool deep_press_accelerated_longpress_enabled_ = false; |
| bool press_and_hold_enabled_ = true; |
| bool showpress_enabled_ = true; |
| bool swipe_enabled_ = false; |
| bool two_finger_tap_enabled_ = false; |
| |
| // Determines speed during touch scrolling. |
| VelocityTrackerState velocity_tracker_; |
| }; |
| |
| } // namespace ui |
| |
| #endif // UI_EVENTS_GESTURE_DETECTION_GESTURE_DETECTOR_H_ |