summaryrefslogtreecommitdiffstats
path: root/ui/events
diff options
context:
space:
mode:
authorjdduke@chromium.org <jdduke@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-04-03 22:37:07 +0000
committerjdduke@chromium.org <jdduke@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-04-03 22:37:07 +0000
commitd3114ed736edf6d02303101cd7bec7d86852fbc5 (patch)
treedf068c8e64136215b08900ee84531a4151d2c0b5 /ui/events
parentfa6f3e8cf3db2a69816f98b79679cc9a68b6c1b6 (diff)
downloadchromium_src-d3114ed736edf6d02303101cd7bec7d86852fbc5.zip
chromium_src-d3114ed736edf6d02303101cd7bec7d86852fbc5.tar.gz
chromium_src-d3114ed736edf6d02303101cd7bec7d86852fbc5.tar.bz2
Adopt "QuickScale" double-tap drag zoom code in the GestureProvider
QuickScale, aka double-tap drag zoom, was added in KitKat on Android. However, the corresponding code in ScaleGestureDetector went unused by Chromium in the old Java-based gesture detection pipeline. Remove the current custom code for double-tap drag zoom, adopting the implementation in ScaleGestureDetector. Note that we maintain one slight difference with the Android platform: instead of diminishing the relative scale delta as the drag focus deiviates from the anchor, continue using a distance-invariant scale delta computation. BUG=332418,359615 Review URL: https://codereview.chromium.org/200623003 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@261552 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'ui/events')
-rw-r--r--ui/events/gesture_detection/gesture_config_helper_android.cc4
-rw-r--r--ui/events/gesture_detection/gesture_config_helper_aura.cc1
-rw-r--r--ui/events/gesture_detection/gesture_detector.h4
-rw-r--r--ui/events/gesture_detection/gesture_provider.cc265
-rw-r--r--ui/events/gesture_detection/gesture_provider.h11
-rw-r--r--ui/events/gesture_detection/gesture_provider_unittest.cc84
-rw-r--r--ui/events/gesture_detection/scale_gesture_detector.cc10
-rw-r--r--ui/events/gesture_detection/scale_gesture_detector.h2
8 files changed, 148 insertions, 233 deletions
diff --git a/ui/events/gesture_detection/gesture_config_helper_android.cc b/ui/events/gesture_detection/gesture_config_helper_android.cc
index db46068..96aa7a6 100644
--- a/ui/events/gesture_detection/gesture_config_helper_android.cc
+++ b/ui/events/gesture_detection/gesture_config_helper_android.cc
@@ -37,9 +37,7 @@ ScaleGestureDetector::Config DefaultScaleGestureDetectorConfig() {
ScaleGestureDetector::Config config;
config.gesture_detector_config = DefaultGestureDetectorConfig();
- // TODO(jdduke): Enable "quick scale" on the ScaleGestureDetector, and remove
- // corresponding double tap drag zoom code from GestureProvider, crbug/331092.
- config.quick_scale_enabled = false;
+ config.quick_scale_enabled = true;
config.min_scaling_touch_major =
ViewConfiguration::GetMinScalingTouchMajorInPixels();
config.min_scaling_span = ViewConfiguration::GetMinScalingSpanInPixels();
diff --git a/ui/events/gesture_detection/gesture_config_helper_aura.cc b/ui/events/gesture_detection/gesture_config_helper_aura.cc
index 4229600..3096db6 100644
--- a/ui/events/gesture_detection/gesture_config_helper_aura.cc
+++ b/ui/events/gesture_detection/gesture_config_helper_aura.cc
@@ -34,7 +34,6 @@ ScaleGestureDetector::Config DefaultScaleGestureDetectorConfig() {
ScaleGestureDetector::Config config;
config.gesture_detector_config = DefaultGestureDetectorConfig();
- config.quick_scale_enabled = false;
config.min_scaling_touch_major = GestureConfiguration::default_radius() / 2;
config.min_scaling_span =
GestureConfiguration::min_distance_for_pinch_scroll_in_pixels();
diff --git a/ui/events/gesture_detection/gesture_detector.h b/ui/events/gesture_detection/gesture_detector.h
index ff60905..29a004a 100644
--- a/ui/events/gesture_detection/gesture_detector.h
+++ b/ui/events/gesture_detection/gesture_detector.h
@@ -88,6 +88,10 @@ class GestureDetector {
double_tap_listener_ = double_tap_listener;
}
+ bool has_doubletap_listener() const { return double_tap_listener_ != NULL; }
+
+ bool is_double_tapping() const { return is_double_tapping_; }
+
void set_is_longpress_enabled(bool is_longpress_enabled) {
is_longpress_enabled_ = is_longpress_enabled;
}
diff --git a/ui/events/gesture_detection/gesture_provider.cc b/ui/events/gesture_detection/gesture_provider.cc
index 4deeba2..eb1794d 100644
--- a/ui/events/gesture_detection/gesture_provider.cc
+++ b/ui/events/gesture_detection/gesture_provider.cc
@@ -43,7 +43,7 @@ GestureEventData CreateGesture(EventType type,
float x,
float y) {
return GestureEventData(type, time, x, y);
- }
+}
GestureEventData CreateGesture(EventType type,
const MotionEvent& event,
@@ -57,10 +57,6 @@ GestureEventData CreateGesture(EventType type,
return CreateGesture(type, event.GetEventTime(), event.GetX(), event.GetY());
}
-float Round(float f) {
- return (f > 0.f) ? std::floor(f + 0.5f) : std::ceil(f - 0.5f);
-}
-
GestureEventDetails CreateTapGestureDetails(EventType type,
const MotionEvent& event) {
// Set the tap count to 1 even for ET_GESTURE_DOUBLE_TAP, in order to be
@@ -86,10 +82,12 @@ class GestureProvider::ScaleGestureListenerImpl
: public ScaleGestureDetector::ScaleGestureListener {
public:
ScaleGestureListenerImpl(const ScaleGestureDetector::Config& config,
+ float device_scale_factor,
GestureProvider* provider)
: scale_gesture_detector_(config, this),
provider_(provider),
- ignore_detector_events_(false),
+ px_to_dp_(1.0f / device_scale_factor),
+ ignore_multitouch_events_(false),
pinch_event_sent_(false) {}
bool OnTouchEvent(const MotionEvent& event) {
@@ -106,7 +104,7 @@ class GestureProvider::ScaleGestureListenerImpl
// ScaleGestureDetector::ScaleGestureListener implementation.
virtual bool OnScaleBegin(const ScaleGestureDetector& detector) OVERRIDE {
- if (ignore_detector_events_)
+ if (ignore_multitouch_events_ && !detector.InDoubleTapMode())
return false;
pinch_event_sent_ = false;
return true;
@@ -121,7 +119,7 @@ class GestureProvider::ScaleGestureListenerImpl
}
virtual bool OnScale(const ScaleGestureDetector& detector) OVERRIDE {
- if (ignore_detector_events_)
+ if (ignore_multitouch_events_ && !detector.InDoubleTapMode())
return false;
if (!pinch_event_sent_) {
pinch_event_sent_ = true;
@@ -130,8 +128,24 @@ class GestureProvider::ScaleGestureListenerImpl
detector.GetFocusX(),
detector.GetFocusY()));
}
- GestureEventDetails pinch_details(
- ET_GESTURE_PINCH_UPDATE, detector.GetScaleFactor(), 0);
+
+ float scale = detector.GetScaleFactor();
+ if (scale == 1)
+ return true;
+
+ if (detector.InDoubleTapMode()) {
+ // Relative changes in the double-tap scale factor computed by |detector|
+ // diminish as the touch moves away from the original double-tap focus.
+ // For historical reasons, Chrome has instead adopted a scale factor
+ // computation that is invariant to the focal distance, where
+ // the scale delta remains constant if the touch velocity is constant.
+ float dy =
+ (detector.GetCurrentSpanY() - detector.GetPreviousSpanY()) * 0.5f;
+ scale = std::pow(scale > 1 ? 1.0f + kDoubleTapDragZoomSpeed
+ : 1.0f - kDoubleTapDragZoomSpeed,
+ std::abs(dy * px_to_dp_));
+ }
+ GestureEventDetails pinch_details(ET_GESTURE_PINCH_UPDATE, scale, 0);
provider_->Send(CreateGesture(ET_GESTURE_PINCH_UPDATE,
detector.GetEventTime(),
detector.GetFocusX(),
@@ -140,26 +154,42 @@ class GestureProvider::ScaleGestureListenerImpl
return true;
}
- bool IsScaleGestureDetectionInProgress() const {
- return !ignore_detector_events_ && scale_gesture_detector_.IsInProgress();
+ void SetDoubleTapEnabled(bool enabled) {
+ DCHECK(!IsDoubleTapInProgress());
+ scale_gesture_detector_.SetQuickScaleEnabled(enabled);
}
- void set_ignore_detector_events(bool value) {
+ void SetMultiTouchEnabled(bool value) {
// Note that returning false from OnScaleBegin / OnScale makes the
// gesture detector not to emit further scaling notifications
// related to this gesture. Thus, if detector events are enabled in
// the middle of the gesture, we don't need to do anything.
- ignore_detector_events_ = value;
+ ignore_multitouch_events_ = value;
+ }
+
+ bool IsDoubleTapInProgress() const {
+ return IsScaleGestureDetectionInProgress() && InDoubleTapMode();
+ }
+
+ bool IsScaleGestureDetectionInProgress() const {
+ return scale_gesture_detector_.IsInProgress();
}
private:
+ bool InDoubleTapMode() const {
+ return scale_gesture_detector_.InDoubleTapMode();
+ }
+
ScaleGestureDetector scale_gesture_detector_;
GestureProvider* const provider_;
- // Completely silence scaling events. Used in WebView when zoom support
- // is turned off.
- bool ignore_detector_events_;
+ // TODO(jdduke): Remove this when all MotionEvent's use DIPs.
+ const float px_to_dp_;
+
+ // Completely silence multi-touch (pinch) scaling events. Used in WebView when
+ // zoom support is turned off.
+ bool ignore_multitouch_events_;
// Whether any pinch zoom event has been sent to native.
bool pinch_event_sent_;
@@ -181,24 +211,16 @@ class GestureProvider::GestureListenerImpl
: gesture_detector_(gesture_detector_config, this, this),
snap_scroll_controller_(snap_scroll_controller_config),
provider_(provider),
- px_to_dp_(1.0f / snap_scroll_controller_config.device_scale_factor),
disable_click_delay_(disable_click_delay),
scaled_touch_slop_(gesture_detector_config.scaled_touch_slop),
scaled_touch_slop_square_(scaled_touch_slop_ * scaled_touch_slop_),
double_tap_timeout_(gesture_detector_config.double_tap_timeout),
ignore_single_tap_(false),
seen_first_scroll_event_(false),
- double_tap_mode_(DOUBLE_TAP_MODE_NONE),
- double_tap_y_(0),
- double_tap_support_enabled_(true),
- double_tap_drag_zoom_anchor_x_(0),
- double_tap_drag_zoom_anchor_y_(0),
last_raw_x_(0),
last_raw_y_(0),
accumulated_scroll_error_x_(0),
- accumulated_scroll_error_y_(0) {
- UpdateDoubleTapListener();
- }
+ accumulated_scroll_error_y_(0) {}
virtual ~GestureListenerImpl() {}
@@ -210,12 +232,8 @@ class GestureProvider::GestureListenerImpl
if (is_scale_gesture_detection_in_progress)
SetIgnoreSingleTap(true);
- if (e.GetAction() == MotionEvent::ACTION_POINTER_DOWN ||
- e.GetAction() == MotionEvent::ACTION_CANCEL) {
- EndDoubleTapDragIfNecessary(e);
- } else if (e.GetAction() == MotionEvent::ACTION_DOWN) {
+ if (e.GetAction() == MotionEvent::ACTION_DOWN)
gesture_detector_.set_is_longpress_enabled(true);
- }
return gesture_detector_.OnTouchEvent(e);
}
@@ -343,7 +361,7 @@ class GestureProvider::GestureListenerImpl
if (!ignore_single_tap_) {
if (e.GetEventTime() - current_down_time_ > double_tap_timeout_) {
return OnSingleTapConfirmed(e);
- } else if (IsDoubleTapDisabled() || disable_click_delay_) {
+ } else if (!IsDoubleTapEnabled() || disable_click_delay_) {
// If double-tap has been disabled, there is no need to wait
// for the double-tap timeout.
return OnSingleTapConfirmed(e);
@@ -381,71 +399,23 @@ class GestureProvider::GestureListenerImpl
virtual bool OnDoubleTapEvent(const MotionEvent& e) OVERRIDE {
switch (e.GetAction()) {
case MotionEvent::ACTION_DOWN:
- // Note that this will be called before the corresponding |onDown()|
- // of the same ACTION_DOWN event. Thus, the preceding TAP_DOWN
- // should be cancelled prior to sending a new one (in |onDown()|).
- double_tap_drag_zoom_anchor_x_ = e.GetX();
- double_tap_drag_zoom_anchor_y_ = e.GetY();
- double_tap_mode_ = DOUBLE_TAP_MODE_DRAG_DETECTION_IN_PROGRESS;
- // If a long-press fires during a double-tap, the GestureDetector
- // will stop feeding MotionEvents to |onDoubleTapEvent()|,
- // preventing double-tap drag zoom. Long press detection will be
- // re-enabled on the next ACTION_DOWN.
gesture_detector_.set_is_longpress_enabled(false);
break;
- case MotionEvent::ACTION_MOVE:
- if (double_tap_mode_ == DOUBLE_TAP_MODE_DRAG_DETECTION_IN_PROGRESS) {
- float distance_x = double_tap_drag_zoom_anchor_x_ - e.GetX();
- float distance_y = double_tap_drag_zoom_anchor_y_ - e.GetY();
-
- // Begin double-tap drag zoom mode if the move distance is
- // further than the threshold.
- if (IsDistanceGreaterThanTouchSlop(distance_x, distance_y)) {
- GestureEventDetails scroll_details(
- ET_GESTURE_SCROLL_BEGIN, -distance_x, -distance_y);
- provider_->Send(
- CreateGesture(ET_GESTURE_SCROLL_BEGIN, e, scroll_details));
- provider_->Send(
- CreateGesture(ET_GESTURE_PINCH_BEGIN,
- e.GetEventTime(),
- Round(double_tap_drag_zoom_anchor_x_),
- Round(double_tap_drag_zoom_anchor_y_)));
- double_tap_mode_ = DOUBLE_TAP_MODE_DRAG_ZOOM;
- }
- } else if (double_tap_mode_ == DOUBLE_TAP_MODE_DRAG_ZOOM) {
- provider_->Send(CreateGesture(ET_GESTURE_SCROLL_UPDATE, e));
-
- float dy = double_tap_y_ - e.GetY();
- float scale = std::pow(dy > 0 ? 1.0f - kDoubleTapDragZoomSpeed
- : 1.0f + kDoubleTapDragZoomSpeed,
- std::abs(dy * px_to_dp_));
- GestureEventDetails pinch_details(ET_GESTURE_PINCH_UPDATE, scale, 0);
- provider_->Send(CreateGesture(ET_GESTURE_PINCH_UPDATE,
- e.GetEventTime(),
- Round(double_tap_drag_zoom_anchor_x_),
- Round(double_tap_drag_zoom_anchor_y_),
- pinch_details));
- }
- break;
+
case MotionEvent::ACTION_UP:
- if (double_tap_mode_ != DOUBLE_TAP_MODE_DRAG_ZOOM) {
- // Normal double-tap gesture.
+ if (!provider_->IsPinchInProgress() &&
+ !provider_->IsScrollInProgress()) {
provider_->Send(
CreateGesture(ET_GESTURE_DOUBLE_TAP,
e,
CreateTapGestureDetails(ET_GESTURE_DOUBLE_TAP, e)));
+ return true;
}
- EndDoubleTapDragIfNecessary(e);
- break;
- case MotionEvent::ACTION_CANCEL:
- EndDoubleTapDragIfNecessary(e);
break;
default:
- NOTREACHED() << "Invalid double-tap event.";
break;
}
- double_tap_y_ = e.GetY();
- return true;
+ return false;
}
virtual bool OnLongPress(const MotionEvent& e) OVERRIDE {
@@ -464,43 +434,23 @@ class GestureProvider::GestureListenerImpl
return false;
}
- void SetDoubleTapSupportForPlatformEnabled(bool enabled) {
+ void SetDoubleTapEnabled(bool enabled) {
DCHECK(!IsDoubleTapInProgress());
- DoubleTapMode double_tap_mode =
- enabled ? DOUBLE_TAP_MODE_NONE : DOUBLE_TAP_MODE_DISABLED;
- if (double_tap_mode_ == double_tap_mode)
- return;
- double_tap_mode_ = double_tap_mode;
- UpdateDoubleTapListener();
- }
-
- void SetDoubleTapSupportForPageEnabled(bool enabled) {
- if (double_tap_support_enabled_ == enabled)
- return;
- double_tap_support_enabled_ = enabled;
- UpdateDoubleTapListener();
- }
-
- bool IsDoubleTapDisabled() const {
- return double_tap_mode_ == DOUBLE_TAP_MODE_DISABLED ||
- !double_tap_support_enabled_;
+ if (enabled) {
+ gesture_detector_.set_doubletap_listener(this);
+ } else {
+ // TODO(jdduke): Send GESTURE_TAP if GESTURE_TAP_UNCONFIRMED already sent.
+ gesture_detector_.set_doubletap_listener(NULL);
+ }
}
bool IsClickDelayDisabled() const { return disable_click_delay_; }
bool IsDoubleTapInProgress() const {
- return double_tap_mode_ != DOUBLE_TAP_MODE_DISABLED &&
- double_tap_mode_ != DOUBLE_TAP_MODE_NONE;
+ return gesture_detector_.is_double_tapping();
}
private:
- enum DoubleTapMode {
- DOUBLE_TAP_MODE_NONE,
- DOUBLE_TAP_MODE_DRAG_DETECTION_IN_PROGRESS,
- DOUBLE_TAP_MODE_DRAG_ZOOM,
- DOUBLE_TAP_MODE_DISABLED
- };
-
bool IsPointOutsideCurrentSlopRegion(float x, float y) const {
return IsDistanceGreaterThanTouchSlop(last_raw_x_ - x, last_raw_y_ - y);
}
@@ -513,27 +463,8 @@ class GestureProvider::GestureListenerImpl
void SetIgnoreSingleTap(bool value) { ignore_single_tap_ = value; }
- void EndDoubleTapDragIfNecessary(const MotionEvent& event) {
- if (!IsDoubleTapInProgress())
- return;
- if (double_tap_mode_ == DOUBLE_TAP_MODE_DRAG_ZOOM) {
- provider_->Send(CreateGesture(ET_GESTURE_PINCH_END, event));
- provider_->Send(CreateGesture(ET_GESTURE_SCROLL_END, event));
- }
- double_tap_mode_ = DOUBLE_TAP_MODE_NONE;
- UpdateDoubleTapListener();
- }
-
- void UpdateDoubleTapListener() {
- if (IsDoubleTapDisabled()) {
- // Defer nulling the DoubleTapListener until the double-tap gesture is
- // complete.
- if (IsDoubleTapInProgress())
- return;
- gesture_detector_.set_doubletap_listener(NULL);
- } else {
- gesture_detector_.set_doubletap_listener(this);
- }
+ bool IsDoubleTapEnabled() const {
+ return gesture_detector_.has_doubletap_listener();
}
GestureDetector gesture_detector_;
@@ -541,8 +472,6 @@ class GestureProvider::GestureListenerImpl
GestureProvider* const provider_;
- const float px_to_dp_;
-
// Whether the click delay should always be disabled by sending clicks for
// double-tap gestures.
const bool disable_click_delay_;
@@ -566,21 +495,6 @@ class GestureProvider::GestureListenerImpl
// gesture.
bool seen_first_scroll_event_;
- // Indicate current double-tap mode state.
- int double_tap_mode_;
-
- // On double-tap this will store the y coordinates of the touch.
- float double_tap_y_;
-
- // The page's viewport and scale sometimes allow us to disable double-tap
- // gesture detection,
- // according to the logic in ContentViewCore.onRenderCoordinatesUpdated().
- bool double_tap_support_enabled_;
-
- // x, y coordinates for an Anchor on double-tap drag zoom.
- float double_tap_drag_zoom_anchor_x_;
- float double_tap_drag_zoom_anchor_y_;
-
// Used to track the last rawX/Y coordinates for moves. This gives absolute
// scroll distance.
// Useful for full screen tracking.
@@ -604,7 +518,9 @@ GestureProvider::GestureProvider(const Config& config,
needs_show_press_event_(false),
needs_tap_ending_event_(false),
touch_scroll_in_progress_(false),
- pinch_in_progress_(false) {
+ pinch_in_progress_(false),
+ double_tap_support_for_page_(true),
+ double_tap_support_for_platform_(true) {
DCHECK(client);
InitGestureDetectors(config);
}
@@ -617,7 +533,6 @@ bool GestureProvider::OnTouchEvent(const MotionEvent& event) {
if (!CanHandle(event))
return false;
- const bool was_touch_scrolling_ = touch_scroll_in_progress_;
const bool in_scale_gesture =
scale_gesture_listener_->IsScaleGestureDetectionInProgress();
@@ -634,16 +549,17 @@ bool GestureProvider::OnTouchEvent(const MotionEvent& event) {
if (event.GetAction() == MotionEvent::ACTION_UP ||
event.GetAction() == MotionEvent::ACTION_CANCEL) {
- // "Last finger raised" could be an end to movement, but it should
- // only terminate scrolling if the event did not cause a fling.
- if (was_touch_scrolling_ && !handled)
- EndTouchScrollIfNecessary(event.GetEventTime(), true);
+ // Note: This call will have no effect if a fling was just generated, as
+ // |Fling()| will have already signalled an end to touch-scrolling.
+ EndTouchScrollIfNecessary(event.GetEventTime(), true);
// We shouldn't necessarily cancel a tap on ACTION_UP, as the double-tap
// timeout may yet trigger a SINGLE_TAP.
if (event.GetAction() == MotionEvent::ACTION_CANCEL)
SendTapCancelIfNecessary(event);
+ UpdateDoubleTapDetectionSupport();
+
current_down_event_.reset();
}
@@ -659,15 +575,17 @@ void GestureProvider::ResetGestureDetectors() {
}
void GestureProvider::SetMultiTouchSupportEnabled(bool enabled) {
- scale_gesture_listener_->set_ignore_detector_events(!enabled);
+ scale_gesture_listener_->SetMultiTouchEnabled(!enabled);
}
void GestureProvider::SetDoubleTapSupportForPlatformEnabled(bool enabled) {
- gesture_listener_->SetDoubleTapSupportForPlatformEnabled(enabled);
+ double_tap_support_for_platform_ = enabled;
+ UpdateDoubleTapDetectionSupport();
}
void GestureProvider::SetDoubleTapSupportForPageEnabled(bool enabled) {
- gesture_listener_->SetDoubleTapSupportForPageEnabled(enabled);
+ double_tap_support_for_page_ = enabled;
+ UpdateDoubleTapDetectionSupport();
}
bool GestureProvider::IsScrollInProgress() const {
@@ -679,7 +597,12 @@ bool GestureProvider::IsScrollInProgress() const {
bool GestureProvider::IsPinchInProgress() const { return pinch_in_progress_; }
bool GestureProvider::IsDoubleTapInProgress() const {
- return gesture_listener_->IsDoubleTapInProgress();
+ return gesture_listener_->IsDoubleTapInProgress() ||
+ scale_gesture_listener_->IsDoubleTapInProgress();
+}
+
+bool GestureProvider::IsDoubleTapSupported() const {
+ return double_tap_support_for_page_ && double_tap_support_for_platform_;
}
bool GestureProvider::IsClickDelayDisabled() const {
@@ -694,8 +617,12 @@ void GestureProvider::InitGestureDetectors(const Config& config) {
config.disable_click_delay,
this));
- scale_gesture_listener_.reset(
- new ScaleGestureListenerImpl(config.scale_gesture_detector_config, this));
+ scale_gesture_listener_.reset(new ScaleGestureListenerImpl(
+ config.scale_gesture_detector_config,
+ config.snap_scroll_controller_config.device_scale_factor,
+ this));
+
+ UpdateDoubleTapDetectionSupport();
}
bool GestureProvider::CanHandle(const MotionEvent& event) const {
@@ -776,6 +703,9 @@ void GestureProvider::Send(const GestureEventData& gesture) {
touch_scroll_in_progress_ = false;
break;
case ET_GESTURE_PINCH_BEGIN:
+ if (!touch_scroll_in_progress_)
+ Send(CreateGesture(
+ ET_GESTURE_SCROLL_BEGIN, gesture.time, gesture.x, gesture.y));
pinch_in_progress_ = true;
break;
case ET_GESTURE_PINCH_END:
@@ -818,4 +748,13 @@ void GestureProvider::EndTouchScrollIfNecessary(base::TimeTicks time,
Send(CreateGesture(ET_GESTURE_SCROLL_END, time, 0, 0));
}
+void GestureProvider::UpdateDoubleTapDetectionSupport() {
+ if (IsDoubleTapInProgress())
+ return;
+
+ const bool supports_double_tap = IsDoubleTapSupported();
+ gesture_listener_->SetDoubleTapEnabled(supports_double_tap);
+ scale_gesture_listener_->SetDoubleTapEnabled(supports_double_tap);
+}
+
} // namespace ui
diff --git a/ui/events/gesture_detection/gesture_provider.h b/ui/events/gesture_detection/gesture_provider.h
index d854219..fce5926 100644
--- a/ui/events/gesture_detection/gesture_provider.h
+++ b/ui/events/gesture_detection/gesture_provider.h
@@ -66,9 +66,13 @@ class GESTURE_DETECTION_EXPORT GestureProvider {
// forwarded and detection is still active).
bool IsPinchInProgress() const;
- // Whether a double tap-gesture is in-progress.
+ // Whether a double-tap gesture is in-progress (either double-tap or
+ // double-tap drag zoom).
bool IsDoubleTapInProgress() const;
+ // Whether double-tap gesture detection is supported.
+ bool IsDoubleTapSupported() const;
+
// Whether the tap gesture delay is explicitly disabled (independent of
// whether double-tap is supported), see |Config.disable_click_delay|.
bool IsClickDelayDisabled() const;
@@ -93,6 +97,7 @@ class GESTURE_DETECTION_EXPORT GestureProvider {
bool SendLongTapIfNecessary(const MotionEvent& event);
void EndTouchScrollIfNecessary(base::TimeTicks time,
bool send_scroll_end_event);
+ void UpdateDoubleTapDetectionSupport();
GestureProviderClient* const client_;
@@ -120,6 +125,10 @@ class GESTURE_DETECTION_EXPORT GestureProvider {
bool touch_scroll_in_progress_;
bool pinch_in_progress_;
+ // Whether double-tap gesture detection is currently supported.
+ bool double_tap_support_for_page_;
+ bool double_tap_support_for_platform_;
+
// Keeps track of the current GESTURE_LONG_PRESS event. If a context menu is
// opened after a GESTURE_LONG_PRESS, this is used to insert a
// GESTURE_TAP_CANCEL for removing any ::active styling.
diff --git a/ui/events/gesture_detection/gesture_provider_unittest.cc b/ui/events/gesture_detection/gesture_provider_unittest.cc
index 1be9ec7..85ced8e 100644
--- a/ui/events/gesture_detection/gesture_provider_unittest.cc
+++ b/ui/events/gesture_detection/gesture_provider_unittest.cc
@@ -405,7 +405,7 @@ TEST_F(GestureProviderTest, DoubleTap) {
EXPECT_EQ(1, double_tap.details.tap_count());
}
-TEST_F(GestureProviderTest, DoubleTapDragZoom) {
+TEST_F(GestureProviderTest, DoubleTapDragZoomBasic) {
const base::TimeTicks down_time_1 = TimeTicks::Now();
const base::TimeTicks down_time_2 = down_time_1 + kOneMicrosecond * 2;
@@ -431,75 +431,31 @@ TEST_F(GestureProviderTest, DoubleTapDragZoom) {
kFakeCoordY + 100);
EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
EXPECT_TRUE(HasReceivedGesture(ET_GESTURE_SCROLL_BEGIN));
- const GestureEventData* scroll_begin_gesture = GetActiveScrollBeginEvent();
- ASSERT_TRUE(!!scroll_begin_gesture);
- EXPECT_EQ(0, scroll_begin_gesture->details.scroll_x_hint());
- EXPECT_EQ(100, scroll_begin_gesture->details.scroll_y_hint());
- EXPECT_EQ(ET_GESTURE_PINCH_BEGIN, GetMostRecentGestureEventType());
+ ASSERT_EQ(ET_GESTURE_PINCH_BEGIN, GetMostRecentGestureEventType());
event = ObtainMotionEvent(down_time_2 + kOneMicrosecond * 2,
MotionEvent::ACTION_MOVE,
kFakeCoordX,
kFakeCoordY + 200);
EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
- EXPECT_TRUE(HasReceivedGesture(ET_GESTURE_SCROLL_UPDATE));
- EXPECT_EQ(ET_GESTURE_PINCH_UPDATE, GetMostRecentGestureEventType());
+ ASSERT_EQ(ET_GESTURE_PINCH_UPDATE, GetMostRecentGestureEventType());
+ EXPECT_LT(1.f, GetMostRecentGestureEvent().details.scale());
event = ObtainMotionEvent(down_time_2 + kOneMicrosecond * 3,
- MotionEvent::ACTION_UP,
- kFakeCoordX,
- kFakeCoordY + 200);
- EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
- EXPECT_TRUE(HasReceivedGesture(ET_GESTURE_PINCH_END));
- EXPECT_EQ(ET_GESTURE_SCROLL_END, GetMostRecentGestureEventType());
-}
-
-TEST_F(GestureProviderTest, DoubleTapDragZoomCancelledOnSecondaryPointerDown) {
- const base::TimeTicks down_time_1 = TimeTicks::Now();
- const base::TimeTicks down_time_2 = down_time_1 + kOneMicrosecond * 2;
-
- MockMotionEvent event =
- ObtainMotionEvent(down_time_1, MotionEvent::ACTION_DOWN);
- EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
- EXPECT_EQ(ET_GESTURE_TAP_DOWN, GetMostRecentGestureEventType());
-
- event = ObtainMotionEvent(down_time_1 + kOneMicrosecond,
- MotionEvent::ACTION_UP);
- gesture_provider_->OnTouchEvent(event);
- EXPECT_EQ(ET_GESTURE_TAP_UNCONFIRMED, GetMostRecentGestureEventType());
-
- event = ObtainMotionEvent(down_time_2, MotionEvent::ACTION_DOWN);
- EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
- EXPECT_EQ(ET_GESTURE_TAP_DOWN, GetMostRecentGestureEventType());
- EXPECT_TRUE(HasReceivedGesture(ET_GESTURE_TAP_CANCEL));
-
- event = ObtainMotionEvent(down_time_2 + kOneMicrosecond,
MotionEvent::ACTION_MOVE,
kFakeCoordX,
- kFakeCoordY - 30);
+ kFakeCoordY + 100);
EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
- EXPECT_TRUE(HasReceivedGesture(ET_GESTURE_SCROLL_BEGIN));
- EXPECT_EQ(ET_GESTURE_PINCH_BEGIN, GetMostRecentGestureEventType());
+ ASSERT_EQ(ET_GESTURE_PINCH_UPDATE, GetMostRecentGestureEventType());
+ EXPECT_GT(1.f, GetMostRecentGestureEvent().details.scale());
- event = ObtainMotionEvent(down_time_2 + kOneMicrosecond * 2,
- MotionEvent::ACTION_POINTER_DOWN,
+ event = ObtainMotionEvent(down_time_2 + kOneMicrosecond * 4,
+ MotionEvent::ACTION_UP,
kFakeCoordX,
- kFakeCoordY - 30,
- kFakeCoordX + 50,
- kFakeCoordY + 50);
- gesture_provider_->OnTouchEvent(event);
+ kFakeCoordY - 200);
+ EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
EXPECT_TRUE(HasReceivedGesture(ET_GESTURE_PINCH_END));
EXPECT_EQ(ET_GESTURE_SCROLL_END, GetMostRecentGestureEventType());
- const size_t gesture_count = GetReceivedGestureCount();
-
- event = ObtainMotionEvent(down_time_2 + kOneMicrosecond * 3,
- MotionEvent::ACTION_POINTER_UP,
- kFakeCoordX,
- kFakeCoordY - 30,
- kFakeCoordX + 50,
- kFakeCoordY + 50);
- gesture_provider_->OnTouchEvent(event);
- EXPECT_EQ(gesture_count, GetReceivedGestureCount());
}
// Generate a scroll gesture and verify that the resulting scroll motion event
@@ -932,8 +888,8 @@ TEST_F(GestureProviderTest, FixedPageScaleDuringDoubleTapDragZoom) {
kFakeCoordX,
kFakeCoordY + 200);
EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
- EXPECT_TRUE(HasReceivedGesture(ET_GESTURE_SCROLL_UPDATE));
EXPECT_EQ(ET_GESTURE_PINCH_UPDATE, GetMostRecentGestureEventType());
+ EXPECT_LT(1.f, GetMostRecentGestureEvent().details.scale());
event = ObtainMotionEvent(down_time_2 + kOneMicrosecond * 3,
MotionEvent::ACTION_UP,
kFakeCoordX,
@@ -1010,20 +966,30 @@ TEST_F(GestureProviderTest, PinchZoom) {
secondary_coord_x += 5 * scaled_touch_slop;
secondary_coord_y += 5 * scaled_touch_slop;
-
event = ObtainMotionEvent(event_time,
MotionEvent::ACTION_MOVE,
kFakeCoordX,
kFakeCoordY,
secondary_coord_x,
secondary_coord_y);
-
EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
EXPECT_TRUE(HasReceivedGesture(ET_GESTURE_PINCH_BEGIN));
EXPECT_TRUE(HasReceivedGesture(ET_GESTURE_SCROLL_BEGIN));
- EXPECT_TRUE(HasReceivedGesture(ET_GESTURE_PINCH_UPDATE));
EXPECT_TRUE(HasReceivedGesture(ET_GESTURE_SCROLL_UPDATE));
+ secondary_coord_x += 2 * scaled_touch_slop;
+ secondary_coord_y += 2 * scaled_touch_slop;
+ event = ObtainMotionEvent(event_time,
+ MotionEvent::ACTION_MOVE,
+ kFakeCoordX,
+ kFakeCoordY,
+ secondary_coord_x,
+ secondary_coord_y);
+ EXPECT_TRUE(gesture_provider_->OnTouchEvent(event));
+ EXPECT_TRUE(HasReceivedGesture(ET_GESTURE_SCROLL_UPDATE));
+ EXPECT_EQ(ET_GESTURE_PINCH_UPDATE, GetMostRecentGestureEventType());
+ EXPECT_LT(1.f, GetMostRecentGestureEvent().details.scale());
+
event = ObtainMotionEvent(event_time,
MotionEvent::ACTION_POINTER_UP,
kFakeCoordX,
diff --git a/ui/events/gesture_detection/scale_gesture_detector.cc b/ui/events/gesture_detection/scale_gesture_detector.cc
index 782f3dd..ea46448 100644
--- a/ui/events/gesture_detection/scale_gesture_detector.cc
+++ b/ui/events/gesture_detection/scale_gesture_detector.cc
@@ -26,7 +26,7 @@ const float kScaleFactor = .5f;
// Note: These constants were taken directly from the default (unscaled)
// versions found in Android's ViewConfiguration.
ScaleGestureDetector::Config::Config()
- : quick_scale_enabled(false),
+ : quick_scale_enabled(true),
min_scaling_touch_major(48),
min_scaling_span(200) {}
@@ -245,6 +245,10 @@ bool ScaleGestureDetector::IsQuickScaleEnabled() const {
bool ScaleGestureDetector::IsInProgress() const { return in_progress_; }
+bool ScaleGestureDetector::InDoubleTapMode() const {
+ return double_tap_mode_ == DOUBLE_TAP_MODE_IN_PROGRESS;
+}
+
float ScaleGestureDetector::GetFocusX() const { return focus_x_; }
float ScaleGestureDetector::GetFocusY() const { return focus_y_; }
@@ -360,8 +364,4 @@ void ScaleGestureDetector::ClearTouchHistory() {
touch_history_last_accepted_time_ = base::TimeTicks();
}
-bool ScaleGestureDetector::InDoubleTapMode() const {
- return double_tap_mode_ == DOUBLE_TAP_MODE_IN_PROGRESS;
-}
-
} // namespace ui
diff --git a/ui/events/gesture_detection/scale_gesture_detector.h b/ui/events/gesture_detection/scale_gesture_detector.h
index 9e84ca5..bd8086a 100644
--- a/ui/events/gesture_detection/scale_gesture_detector.h
+++ b/ui/events/gesture_detection/scale_gesture_detector.h
@@ -71,6 +71,7 @@ class ScaleGestureDetector : public GestureDetector::SimpleGestureListener {
void SetQuickScaleEnabled(bool scales);
bool IsQuickScaleEnabled() const;
bool IsInProgress() const;
+ bool InDoubleTapMode() const;
float GetFocusX() const;
float GetFocusY() const;
float GetCurrentSpan() const;
@@ -93,7 +94,6 @@ class ScaleGestureDetector : public GestureDetector::SimpleGestureListener {
// some hardware/driver combos. Smooth out to get kinder, gentler behavior.
void AddTouchHistory(const MotionEvent& ev);
void ClearTouchHistory();
- bool InDoubleTapMode() const;
ScaleGestureListener* const listener_;