gesture_detector.h revision 5c02ac1a9c1b504631c0a3d2b6e737b5d738bae1
1a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved.
2a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
3a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// found in the LICENSE file.
4a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
5a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#ifndef UI_EVENTS_GESTURE_DETECTION_GESTURE_DETECTOR_H_
6a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#define UI_EVENTS_GESTURE_DETECTION_GESTURE_DETECTOR_H_
7a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)#include "base/logging.h"
9a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "base/memory/scoped_ptr.h"
10a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "ui/events/gesture_detection/gesture_detection_export.h"
11a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "ui/events/gesture_detection/velocity_tracker_state.h"
12a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
13a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)namespace ui {
14a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
15a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)class MotionEvent;
16a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
17a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// Port of GestureDetector.java from Android
18a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// * platform/frameworks/base/core/java/android/view/GestureDetector.java
19a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// * Change-Id: Ib470735ec929b0b358fca4597e92dc81084e675f
20a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// * Please update the Change-Id as upstream Android changes are pulled.
21a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)class GestureDetector {
22a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) public:
23a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  struct GESTURE_DETECTION_EXPORT Config {
24a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    Config();
25a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    ~Config();
26a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch
27a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    base::TimeDelta longpress_timeout;
28a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    base::TimeDelta showpress_timeout;
29a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    base::TimeDelta double_tap_timeout;
30a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch
31a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    // Distance a touch can wander before a scroll will occur (in dips).
32a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    float touch_slop;
33a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch
34a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    // Distance the first touch can wander before it is no longer considered a
35a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    // double tap (in dips).
36a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    float double_tap_slop;
37a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch
38a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    // Minimum velocity to initiate a fling (in dips/second).
39a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    float minimum_fling_velocity;
40a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch
41a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    // Maximum velocity of an initiated fling (in dips/second).
42a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    float maximum_fling_velocity;
435c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
445c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    // Whether |OnSwipe| should be called after a secondary touch is released
455c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    // while a logical swipe gesture is active. Defaults to false.
465c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    bool swipe_enabled;
475c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
485c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    // Minimum velocity to initiate a swipe (in dips/second).
495c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    float minimum_swipe_velocity;
505c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
515c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    // Maximum angle of the swipe from its dominant component axis, between
525c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    // (0, 45] degrees. The closer this is to 0, the closer the dominant
535c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    // direction of the swipe must be to up, down left or right.
545c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    float maximum_swipe_deviation_angle;
55a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  };
56a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
57a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  class GestureListener {
58a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)   public:
59a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    virtual ~GestureListener() {}
60a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    virtual bool OnDown(const MotionEvent& e) = 0;
61a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    virtual void OnShowPress(const MotionEvent& e) = 0;
62a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    virtual bool OnSingleTapUp(const MotionEvent& e) = 0;
63a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    virtual bool OnLongPress(const MotionEvent& e) = 0;
645c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    virtual bool OnScroll(const MotionEvent& e1,
655c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu                          const MotionEvent& e2,
665c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu                          float distance_x,
675c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu                          float distance_y) = 0;
685c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    virtual bool OnFling(const MotionEvent& e1,
695c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu                         const MotionEvent& e2,
705c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu                         float velocity_x,
715c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu                         float velocity_y) = 0;
725c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    // Added for Chromium (Aura).
735c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    virtual bool OnSwipe(const MotionEvent& e1,
745c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu                         const MotionEvent& e2,
755c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu                         float velocity_x,
765c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu                         float velocity_y) = 0;
77a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  };
78a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
79a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  class DoubleTapListener {
80a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)   public:
81a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    virtual ~DoubleTapListener() {}
82a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    virtual bool OnSingleTapConfirmed(const MotionEvent& e) = 0;
83a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    virtual bool OnDoubleTap(const MotionEvent& e) = 0;
84a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    virtual bool OnDoubleTapEvent(const MotionEvent& e) = 0;
85a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  };
86a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
87a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // A convenience class to extend when you only want to listen for a subset
88a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // of all the gestures. This implements all methods in the
89a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // |GestureListener| and |DoubleTapListener| but does
90a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // nothing and returns false for all applicable methods.
91a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  class SimpleGestureListener : public GestureListener,
92a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                public DoubleTapListener {
93a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)   public:
94a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    // GestureListener implementation.
95a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    virtual bool OnDown(const MotionEvent& e) OVERRIDE;
96a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    virtual void OnShowPress(const MotionEvent& e) OVERRIDE;
97a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    virtual bool OnSingleTapUp(const MotionEvent& e) OVERRIDE;
98a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    virtual bool OnLongPress(const MotionEvent& e) OVERRIDE;
995c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    virtual bool OnScroll(const MotionEvent& e1,
1005c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu                          const MotionEvent& e2,
1015c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu                          float distance_x,
1025c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu                          float distance_y) OVERRIDE;
1035c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    virtual bool OnFling(const MotionEvent& e1,
1045c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu                         const MotionEvent& e2,
1055c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu                         float velocity_x,
1065c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu                         float velocity_y) OVERRIDE;
1075c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    virtual bool OnSwipe(const MotionEvent& e1,
1085c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu                         const MotionEvent& e2,
1095c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu                         float velocity_x,
1105c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu                         float velocity_y) OVERRIDE;
111a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
112a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    // DoubleTapListener implementation.
113a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    virtual bool OnSingleTapConfirmed(const MotionEvent& e) OVERRIDE;
114a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    virtual bool OnDoubleTap(const MotionEvent& e) OVERRIDE;
115a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    virtual bool OnDoubleTapEvent(const MotionEvent& e) OVERRIDE;
116a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  };
117a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
118a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  GestureDetector(const Config& config,
119a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                  GestureListener* listener,
120a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                  DoubleTapListener* optional_double_tap_listener);
121a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  ~GestureDetector();
122a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
123a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  bool OnTouchEvent(const MotionEvent& ev);
124a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
1250529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  // Setting a valid |double_tap_listener| will enable double-tap detection,
1260529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  // wherein calls to |OnSimpleTapConfirmed| are delayed by the tap timeout.
1270529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  // Note: The listener must never be changed while |is_double_tapping| is true.
1280529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  void SetDoubleTapListener(DoubleTapListener* double_tap_listener);
129a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
130c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  bool has_doubletap_listener() const { return double_tap_listener_ != NULL; }
131c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
132c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  bool is_double_tapping() const { return is_double_tapping_; }
133c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
1345c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  void set_longpress_enabled(bool enabled) { longpress_enabled_ = enabled; }
135a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
136a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) private:
137a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  void Init(const Config& config);
138a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  void OnShowPressTimeout();
139a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  void OnLongPressTimeout();
140a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  void OnTapTimeout();
141a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  void Cancel();
142a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  void CancelTaps();
143a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  bool IsConsideredDoubleTap(const MotionEvent& first_down,
144a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                             const MotionEvent& first_up,
145a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                             const MotionEvent& second_down) const;
146a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
147a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  class TimeoutGestureHandler;
148a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  scoped_ptr<TimeoutGestureHandler> timeout_handler_;
149a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  GestureListener* const listener_;
150a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  DoubleTapListener* double_tap_listener_;
151a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
152a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  float touch_slop_square_;
153a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  float double_tap_touch_slop_square_;
154a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  float double_tap_slop_square_;
155a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  float min_fling_velocity_;
156a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  float max_fling_velocity_;
1575c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  float min_swipe_velocity_;
1585c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  float min_swipe_direction_component_ratio_;
159a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  base::TimeDelta double_tap_timeout_;
160a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
161a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  bool still_down_;
162a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  bool defer_confirm_single_tap_;
163a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  bool in_longpress_;
164a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  bool always_in_tap_region_;
165a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  bool always_in_bigger_tap_region_;
166a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
167a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  scoped_ptr<MotionEvent> current_down_event_;
168a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  scoped_ptr<MotionEvent> previous_up_event_;
169a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
170a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // True when the user is still touching for the second tap (down, move, and
171a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // up events). Can only be true if there is a double tap listener attached.
172a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  bool is_double_tapping_;
173a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
174a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  float last_focus_x_;
175a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  float last_focus_y_;
176a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  float down_focus_x_;
177a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  float down_focus_y_;
178a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
1795c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  bool longpress_enabled_;
1805c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  bool swipe_enabled_;
181a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
182a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // Determines speed during touch scrolling.
183a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  VelocityTrackerState velocity_tracker_;
184a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
185a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(GestureDetector);
186a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)};
187a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
188a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}  // namespace ui
189a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
190a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#endif  // UI_EVENTS_GESTURE_DETECTION_GESTURE_DETECTOR_H_
191