summaryrefslogtreecommitdiffstats
path: root/ui
diff options
context:
space:
mode:
authortdresser@chromium.org <tdresser@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-04-17 19:25:25 +0000
committertdresser@chromium.org <tdresser@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-04-17 19:25:25 +0000
commitcc1fad52a7d5f4317d63404022a251724e13f667 (patch)
treea64da9f22c64fdd6c000d01983049e7fd029cab0 /ui
parenta58c97e519a34d9d48d6154f37e7d44346ada85e (diff)
downloadchromium_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.cc78
-rw-r--r--ui/aura/root_window.h7
-rw-r--r--ui/aura/window_unittest.cc76
-rw-r--r--ui/base/gestures/gesture_recognizer.h10
-rw-r--r--ui/base/gestures/gesture_recognizer_impl.cc35
-rw-r--r--ui/base/gestures/gesture_recognizer_impl.h16
-rw-r--r--ui/base/gestures/gesture_sequence.cc1
-rw-r--r--ui/base/gestures/gesture_types.h23
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