diff options
author | tdresser@chromium.org <tdresser@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-04-17 19:25:25 +0000 |
---|---|---|
committer | tdresser@chromium.org <tdresser@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-04-17 19:25:25 +0000 |
commit | cc1fad52a7d5f4317d63404022a251724e13f667 (patch) | |
tree | a64da9f22c64fdd6c000d01983049e7fd029cab0 /ui | |
parent | a58c97e519a34d9d48d6154f37e7d44346ada85e (diff) | |
download | chromium_src-cc1fad52a7d5f4317d63404022a251724e13f667.zip chromium_src-cc1fad52a7d5f4317d63404022a251724e13f667.tar.gz chromium_src-cc1fad52a7d5f4317d63404022a251724e13f667.tar.bz2 |
On touch capture, cancel non-captured touches.
When a touch capture occurs, any touches locked to other windows are cancelled.
These touches are then locked to a GestureConsumer which ignores all
further events, until the touch is released.
BUG=123211
TEST=WindowTest.TouchCaptureCancelsOtherTouches, TouchCaptureDoesntCancelCapturedTouches
Review URL: http://codereview.chromium.org/10038030
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@132619 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'ui')
-rw-r--r-- | ui/aura/root_window.cc | 78 | ||||
-rw-r--r-- | ui/aura/root_window.h | 7 | ||||
-rw-r--r-- | ui/aura/window_unittest.cc | 76 | ||||
-rw-r--r-- | ui/base/gestures/gesture_recognizer.h | 10 | ||||
-rw-r--r-- | ui/base/gestures/gesture_recognizer_impl.cc | 35 | ||||
-rw-r--r-- | ui/base/gestures/gesture_recognizer_impl.h | 16 | ||||
-rw-r--r-- | ui/base/gestures/gesture_sequence.cc | 1 | ||||
-rw-r--r-- | ui/base/gestures/gesture_types.h | 23 |
8 files changed, 205 insertions, 41 deletions
diff --git a/ui/aura/root_window.cc b/ui/aura/root_window.cc index 2254ff4..d443d62 100644 --- a/ui/aura/root_window.cc +++ b/ui/aura/root_window.cc @@ -268,39 +268,45 @@ bool RootWindow::DispatchTouchEvent(TouchEvent* event) { event->UpdateForRootTransform(layer()->transform()); bool handled = false; - Window* target = NULL; - if (HasCapture(capture_window_, ui::CW_LOCK_TOUCH)) - target = capture_window_; - - if (!target) - target = static_cast<Window*>( - gesture_recognizer_->GetTargetForTouchEvent(event)); - + GestureConsumer* consumer = gesture_recognizer_->GetTouchLockedTarget(event); ui::TouchStatus status = ui::TOUCH_STATUS_UNKNOWN; - if (!target && !bounds().Contains(event->location())) { - // If the touch is outside the root window, set its target to the - // root window. - target = this; - } else { - if (!target) - target = GetEventHandlerForPoint(event->location()); - if (!target) - return false; + if (!consumer || !consumer->ignores_events()) { + Window* target = static_cast<Window*>(consumer); - TouchEvent translated_event(*event, this, target); - status = ProcessTouchEvent(target, &translated_event); - handled = status != ui::TOUCH_STATUS_UNKNOWN; + if (!target && HasCapture(capture_window_, ui::CW_LOCK_TOUCH)) + target = capture_window_; + + if (!target) { + target = static_cast<Window*>( + gesture_recognizer_->GetTargetForLocation(event->GetLocation())); + } - if (status == ui::TOUCH_STATUS_QUEUED || - status == ui::TOUCH_STATUS_QUEUED_END) - gesture_recognizer_->QueueTouchEventForGesture(target, *event); + if (!target && !bounds().Contains(event->location())) { + // If the touch is outside the root window, set its target to the + // root window. + target = this; + } else { + if (!target) + target = GetEventHandlerForPoint(event->location()); + if (!target) + return false; + + TouchEvent translated_event(*event, this, target); + status = ProcessTouchEvent(target, &translated_event); + handled = status != ui::TOUCH_STATUS_UNKNOWN; + + if (status == ui::TOUCH_STATUS_QUEUED || + status == ui::TOUCH_STATUS_QUEUED_END) + gesture_recognizer_->QueueTouchEventForGesture(target, *event); + } + consumer = target; } // Get the list of GestureEvents from GestureRecognizer. scoped_ptr<ui::GestureRecognizer::Gestures> gestures; gestures.reset(gesture_recognizer_->ProcessTouchEventForGesture( - *event, status, target)); + *event, status, consumer)); if (ProcessGestures(gestures.get())) handled = true; @@ -313,9 +319,13 @@ bool RootWindow::DispatchGestureEvent(GestureEvent* event) { Window* target = NULL; if (HasCapture(capture_window_, ui::CW_LOCK_TOUCH)) target = capture_window_; - if (!target) - target = static_cast<Window*>( - gesture_recognizer_->GetTargetForGestureEvent(event)); + if (!target) { + GestureConsumer* consumer = + gesture_recognizer_->GetTargetForGestureEvent(event); + if (consumer->ignores_events()) + return false; + target = static_cast<Window*>(consumer); + } if (target) { GestureEvent translated_event(*event, this, target); @@ -407,6 +417,9 @@ void RootWindow::SetCapture(Window* window, unsigned int flags) { if (capture_window_ == window && flags == capture_window_flags_) return; + if (flags & ui::CW_LOCK_TOUCH) + gesture_recognizer_->CancelNonCapturedTouches(window); + aura::Window* old_capture_window = capture_window_; capture_window_ = window; capture_window_flags_ = flags; @@ -782,6 +795,10 @@ bool RootWindow::DispatchLongPressGestureEvent(ui::GestureEvent* event) { return DispatchGestureEvent(static_cast<GestureEvent*>(event)); } +bool RootWindow::DispatchCancelTouchEvent(ui::TouchEvent* event) { + return DispatchTouchEvent(static_cast<TouchEvent*>(event)); +} + ui::GestureEvent* RootWindow::CreateGestureEvent(ui::EventType type, const gfx::Point& location, int flags, @@ -793,6 +810,13 @@ ui::GestureEvent* RootWindow::CreateGestureEvent(ui::EventType type, param_first, param_second, touch_id_bitfield); } +ui::TouchEvent* RootWindow::CreateTouchEvent(ui::EventType type, + const gfx::Point& location, + int touch_id, + base::TimeDelta time_stamp) { + return new TouchEvent(type, location, touch_id, time_stamp); +} + void RootWindow::OnLayerAnimationEnded( ui::LayerAnimationSequence* animation) { OnHostResized(host_->GetBounds().size()); diff --git a/ui/aura/root_window.h b/ui/aura/root_window.h index 140543e..dd6f533 100644 --- a/ui/aura/root_window.h +++ b/ui/aura/root_window.h @@ -294,7 +294,14 @@ class AURA_EXPORT RootWindow : public ui::CompositorDelegate, float param_first, float param_second, unsigned int touch_id_bitfield) OVERRIDE; + + virtual ui::TouchEvent* CreateTouchEvent(ui::EventType type, + const gfx::Point& location, + int touch_id, + base::TimeDelta time_stamp) OVERRIDE; + virtual bool DispatchLongPressGestureEvent(ui::GestureEvent* event) OVERRIDE; + virtual bool DispatchCancelTouchEvent(ui::TouchEvent* event) OVERRIDE; // Overridden from ui::LayerAnimationObserver: virtual void OnLayerAnimationEnded( diff --git a/ui/aura/window_unittest.cc b/ui/aura/window_unittest.cc index dd95610..30c5dd0 100644 --- a/ui/aura/window_unittest.cc +++ b/ui/aura/window_unittest.cc @@ -125,6 +125,7 @@ class CaptureWindowDelegateImpl : public TestWindowDelegate { capture_lost_count_ = 0; mouse_event_count_ = 0; touch_event_count_ = 0; + gesture_event_count_ = 0; } int capture_changed_event_count() const { @@ -133,6 +134,7 @@ class CaptureWindowDelegateImpl : public TestWindowDelegate { int capture_lost_count() const { return capture_lost_count_; } int mouse_event_count() const { return mouse_event_count_; } int touch_event_count() const { return touch_event_count_; } + int gesture_event_count() const { return gesture_event_count_; } virtual bool OnMouseEvent(MouseEvent* event) OVERRIDE { if (event->type() == ui::ET_MOUSE_CAPTURE_CHANGED) @@ -145,6 +147,7 @@ class CaptureWindowDelegateImpl : public TestWindowDelegate { return ui::TOUCH_STATUS_UNKNOWN; } virtual ui::GestureStatus OnGestureEvent(GestureEvent* event) OVERRIDE { + gesture_event_count_++; return ui::GESTURE_STATUS_UNKNOWN; } virtual void OnCaptureLost() OVERRIDE { @@ -156,6 +159,7 @@ class CaptureWindowDelegateImpl : public TestWindowDelegate { int capture_lost_count_; int mouse_event_count_; int touch_event_count_; + int gesture_event_count_; DISALLOW_COPY_AND_ASSIGN(CaptureWindowDelegateImpl); }; @@ -626,6 +630,78 @@ TEST_F(WindowTest, CaptureTests) { EXPECT_EQ(NULL, root_window()->capture_window()); } +TEST_F(WindowTest, TouchCaptureCancelsOtherTouches) { + CaptureWindowDelegateImpl delegate1; + scoped_ptr<Window> w1(CreateTestWindowWithDelegate( + &delegate1, 0, gfx::Rect(0, 0, 20, 20), NULL)); + CaptureWindowDelegateImpl delegate2; + scoped_ptr<Window> w2(CreateTestWindowWithDelegate( + &delegate2, 0, gfx::Rect(20, 20, 20, 20), NULL)); + + // Press on w1. + TouchEvent press(ui::ET_TOUCH_PRESSED, + gfx::Point(10, 10), 0, getTime()); + root_window()->DispatchTouchEvent(&press); + EXPECT_EQ(1, delegate1.gesture_event_count()); + delegate1.ResetCounts(); + w2->SetCapture(ui::CW_LOCK_TOUCH); + + // The touch was cancelled when the other window + // attained a touch lock. + EXPECT_EQ(1, delegate1.touch_event_count()); + EXPECT_EQ(0, delegate2.touch_event_count()); + + delegate1.ResetCounts(); + delegate2.ResetCounts(); + + TouchEvent move(ui::ET_TOUCH_MOVED, + gfx::Point(10, 10), 0, getTime()); + root_window()->DispatchTouchEvent(&move); + + // This touch id is now ignored, no scroll fired. + EXPECT_EQ(0, delegate1.gesture_event_count()); + EXPECT_EQ(0, delegate2.gesture_event_count()); + + TouchEvent release(ui::ET_TOUCH_RELEASED, + gfx::Point(10, 10), 0, getTime()); + root_window()->DispatchTouchEvent(&release); + EXPECT_EQ(0, delegate1.gesture_event_count()); + EXPECT_EQ(0, delegate2.gesture_event_count()); + + // A new press is captured by w2. + + TouchEvent press2(ui::ET_TOUCH_PRESSED, + gfx::Point(10, 10), 0, getTime()); + root_window()->DispatchTouchEvent(&press2); + EXPECT_EQ(0, delegate1.gesture_event_count()); + EXPECT_EQ(1, delegate2.gesture_event_count()); +} + +TEST_F(WindowTest, TouchCaptureDoesntCancelCapturedTouches) { + CaptureWindowDelegateImpl delegate; + scoped_ptr<Window> window(CreateTestWindowWithDelegate( + &delegate, 0, gfx::Rect(0, 0, 20, 20), NULL)); + + TouchEvent press(ui::ET_TOUCH_PRESSED, + gfx::Point(10, 10), 0, getTime()); + root_window()->DispatchTouchEvent(&press); + + EXPECT_EQ(1, delegate.gesture_event_count()); + delegate.ResetCounts(); + + window->SetCapture(ui::CW_LOCK_TOUCH); + EXPECT_EQ(0, delegate.gesture_event_count()); + delegate.ResetCounts(); + + // The move event should still create a gesture, as this touch was + // on the window which was captured. + TouchEvent release(ui::ET_TOUCH_RELEASED, + gfx::Point(10, 10), 0, getTime() + + base::TimeDelta::FromMilliseconds(50)); + root_window()->DispatchTouchEvent(&release); + EXPECT_EQ(1, delegate.gesture_event_count()); +} + // Changes capture while capture is already ongoing. TEST_F(WindowTest, ChangeCaptureWhileMouseDown) { CaptureWindowDelegateImpl delegate; diff --git a/ui/base/gestures/gesture_recognizer.h b/ui/base/gestures/gesture_recognizer.h index 541d823..84085e5 100644 --- a/ui/base/gestures/gesture_recognizer.h +++ b/ui/base/gestures/gesture_recognizer.h @@ -48,10 +48,9 @@ class UI_EXPORT GestureRecognizer { virtual void FlushTouchQueue(GestureConsumer* consumer) = 0; // Return the window which should handle this TouchEvent, in the case where - // the touch is already associated with a target, or the touch occurs - // near another touch. + // the touch is already associated with a target. // Otherwise, returns null. - virtual GestureConsumer* GetTargetForTouchEvent(TouchEvent* event) = 0; + virtual GestureConsumer* GetTouchLockedTarget(TouchEvent* event) = 0; // Return the window which should handle this GestureEvent. virtual GestureConsumer* GetTargetForGestureEvent(GestureEvent* event) = 0; @@ -60,6 +59,11 @@ class UI_EXPORT GestureRecognizer { // GestureConfiguration::max_separation_for_gesture_touches_in_pixels, // of |location|, returns the target of the nearest active touch. virtual GestureConsumer* GetTargetForLocation(const gfx::Point& location) = 0; + + // For each touch on windows other than |capturer|, a cancel event + // is fired. These touches are then ignored until they are released + // and pressed again. + virtual void CancelNonCapturedTouches(GestureConsumer* capturer) = 0; }; } // namespace ui diff --git a/ui/base/gestures/gesture_recognizer_impl.cc b/ui/base/gestures/gesture_recognizer_impl.cc index 2b9269f..ead6aa0 100644 --- a/ui/base/gestures/gesture_recognizer_impl.cc +++ b/ui/base/gestures/gesture_recognizer_impl.cc @@ -70,6 +70,15 @@ class CancelledTouchEvent : public ui::TouchEvent { DISALLOW_COPY_AND_ASSIGN(CancelledTouchEvent); }; +// Touches which are cancelled by a touch capture are routed to a +// GestureEventIgnorer, which ignores them. +class GestureConsumerIgnorer : public ui::GestureConsumer { + public: + GestureConsumerIgnorer() + : GestureConsumer(true) { + } +}; + } // namespace namespace ui { @@ -79,17 +88,15 @@ namespace ui { GestureRecognizerImpl::GestureRecognizerImpl(GestureEventHelper* helper) : helper_(helper) { + gesture_consumer_ignorer_.reset(new GestureConsumerIgnorer()); } GestureRecognizerImpl::~GestureRecognizerImpl() { } -GestureConsumer* GestureRecognizerImpl::GetTargetForTouchEvent( - TouchEvent* event) { - GestureConsumer* target = touch_id_target_[event->GetTouchId()]; - if (!target) - target = GetTargetForLocation(event->GetLocation()); - return target; +GestureConsumer* GestureRecognizerImpl::GetTouchLockedTarget( + TouchEvent* event) { + return touch_id_target_[event->GetTouchId()]; } GestureConsumer* GestureRecognizerImpl::GetTargetForGestureEvent( @@ -129,6 +136,22 @@ GestureConsumer* GestureRecognizerImpl::GetTargetForLocation( return NULL; } +void GestureRecognizerImpl::CancelNonCapturedTouches( + GestureConsumer* capturer) { + std::map<int, GestureConsumer*>::iterator i; + // Fire touch cancels, and target touch_ids to gesture_consumer_ignorer. + for (i = touch_id_target_.begin(); i != touch_id_target_.end(); ++i) { + if (capturer != i->second) { + scoped_ptr<TouchEvent> touchEvent(helper_->CreateTouchEvent( + ui::ET_TOUCH_CANCELLED, gfx::Point(0, 0), + i->first, + base::Time::NowFromSystemTime() - base::Time())); + helper_->DispatchCancelTouchEvent(touchEvent.get()); + touch_id_target_[i->first] = gesture_consumer_ignorer_.get(); + } + } +} + //////////////////////////////////////////////////////////////////////////////// // GestureRecognizerImpl, protected: diff --git a/ui/base/gestures/gesture_recognizer_impl.h b/ui/base/gestures/gesture_recognizer_impl.h index cb91f33..9c659eb 100644 --- a/ui/base/gestures/gesture_recognizer_impl.h +++ b/ui/base/gestures/gesture_recognizer_impl.h @@ -30,11 +30,8 @@ class UI_EXPORT GestureRecognizerImpl : public GestureRecognizer { virtual ~GestureRecognizerImpl(); // Checks if this finger is already down, if so, returns the current target. - // Otherwise, if the finger is within - // GestureConfiguration::max_separation_for_gesture_touches_in_pixels - // of another touch, returns the target of the closest touch. - // If there is no nearby touch, return null. - virtual GestureConsumer* GetTargetForTouchEvent(TouchEvent* event) OVERRIDE; + // Otherwise, returns NULL. + virtual GestureConsumer* GetTouchLockedTarget(TouchEvent* event) OVERRIDE; // Returns the target of the touches the gesture is composed of. virtual GestureConsumer* GetTargetForGestureEvent( @@ -43,6 +40,11 @@ class UI_EXPORT GestureRecognizerImpl : public GestureRecognizer { virtual GestureConsumer* GetTargetForLocation( const gfx::Point& location) OVERRIDE; + // Each touch which isn't targeted to capturer results in a touch + // cancel event. These touches are then targeted to + // gesture_consumer_ignorer. + virtual void CancelNonCapturedTouches(GestureConsumer* capturer) OVERRIDE; + protected: virtual GestureSequence* CreateSequence(GestureEventHelper* helper); virtual GestureSequence* GetGestureSequenceForConsumer(GestureConsumer* c); @@ -70,6 +72,10 @@ class UI_EXPORT GestureRecognizerImpl : public GestureRecognizer { // removed. std::map<int, GestureConsumer*> touch_id_target_; std::map<int, GestureConsumer*> touch_id_target_for_gestures_; + + // Touches cancelled by touch capture are routed to the + // gesture_consumer_ignorer_. + scoped_ptr<GestureConsumer> gesture_consumer_ignorer_; GestureEventHelper* helper_; DISALLOW_COPY_AND_ASSIGN(GestureRecognizerImpl); diff --git a/ui/base/gestures/gesture_sequence.cc b/ui/base/gestures/gesture_sequence.cc index 321211b..fcab299 100644 --- a/ui/base/gestures/gesture_sequence.cc +++ b/ui/base/gestures/gesture_sequence.cc @@ -314,6 +314,7 @@ void GestureSequence::Reset() { set_state(GS_NO_GESTURE); for (int i = 0; i < kMaxGesturePoints; ++i) points_[i].Reset(); + point_count_ = 0; } //////////////////////////////////////////////////////////////////////////////// diff --git a/ui/base/gestures/gesture_types.h b/ui/base/gestures/gesture_types.h index 27e04d8..b857171 100644 --- a/ui/base/gestures/gesture_types.h +++ b/ui/base/gestures/gesture_types.h @@ -41,12 +41,29 @@ class UI_EXPORT GestureEvent { // An abstract type for consumers of gesture-events created by the // gesture-recognizer. class UI_EXPORT GestureConsumer { + public: + GestureConsumer() + : ignores_events_(false) { + } + + explicit GestureConsumer(bool ignores_events) + : ignores_events_(ignores_events) { + } + + virtual ~GestureConsumer() {} + bool ignores_events() { return ignores_events_; } + + private: + const bool ignores_events_; }; // GestureEventHelper creates implementation-specific gesture events and // can dispatch them. class UI_EXPORT GestureEventHelper { public: + virtual ~GestureEventHelper() { + } + // |flags| is ui::EventFlags. The meaning of |param_first| and |param_second| // depends on the specific gesture type (|type|). virtual GestureEvent* CreateGestureEvent(EventType type, @@ -57,7 +74,13 @@ class UI_EXPORT GestureEventHelper { float param_second, unsigned int touch_id_bitfield) = 0; + virtual TouchEvent* CreateTouchEvent(EventType type, + const gfx::Point& location, + int touch_id, + base::TimeDelta time_stamp) = 0; + virtual bool DispatchLongPressGestureEvent(GestureEvent* event) = 0; + virtual bool DispatchCancelTouchEvent(TouchEvent* event) = 0; }; } // namespace ui |