Index: ui/aura/gestures/gesture_recognizer_unittest.cc |
diff --git a/ui/aura/gestures/gesture_recognizer_unittest.cc b/ui/aura/gestures/gesture_recognizer_unittest.cc |
index f7d1a4288ad95666b1c97a77ceca15628cfbacc3..6c828286511c23c817bd723b6c5f8f179db42fca 100644 |
--- a/ui/aura/gestures/gesture_recognizer_unittest.cc |
+++ b/ui/aura/gestures/gesture_recognizer_unittest.cc |
@@ -337,7 +337,8 @@ class QueueTouchEventDelegate : public GestureEventConsumeDelegate { |
explicit QueueTouchEventDelegate(WindowEventDispatcher* dispatcher) |
: window_(NULL), |
dispatcher_(dispatcher), |
- queue_events_(true) { |
+ queue_events_(true), |
+ synchronous_ack_for_next_event_(AckState::PENDING) { |
} |
~QueueTouchEventDelegate() override { |
while(!queue_.empty()) { |
@@ -347,10 +348,17 @@ class QueueTouchEventDelegate : public GestureEventConsumeDelegate { |
} |
void OnTouchEvent(ui::TouchEvent* event) override { |
- if (queue_events_) { |
- queue_.push(new ui::TouchEvent(*event, window_, window_)); |
- event->StopPropagation(); |
+ event->DisableSynchronousHandling(); |
+ if (synchronous_ack_for_next_event_ != AckState::PENDING) { |
+ ui::GestureRecognizer::Get()->AckSyncTouchEvent( |
+ *event, synchronous_ack_for_next_event_ == AckState::CONSUMED |
+ ? ui::ER_CONSUMED |
+ : ui::ER_UNHANDLED, |
+ window_); |
+ synchronous_ack_for_next_event_ = AckState::PENDING; |
} |
+ if (queue_events_) |
+ queue_.push(new ui::TouchEvent(*event, window_, window_)); |
} |
void ReceivedAck() { |
@@ -363,8 +371,19 @@ class QueueTouchEventDelegate : public GestureEventConsumeDelegate { |
void set_window(Window* w) { window_ = w; } |
void set_queue_events(bool queue) { queue_events_ = queue; } |
+ void set_synchronous_ack_for_next_event(bool consumed) { |
+ DCHECK(synchronous_ack_for_next_event_ == AckState::PENDING); |
+ synchronous_ack_for_next_event_ = |
+ consumed ? AckState::CONSUMED : AckState::UNCONSUMED; |
+ } |
private: |
+ enum class AckState : int { |
+ PENDING, |
+ CONSUMED, |
+ UNCONSUMED, |
+ }; |
+ |
void ReceivedAckImpl(bool prevent_defaulted) { |
scoped_ptr<ui::TouchEvent> event(queue_.front()); |
dispatcher_->ProcessedTouchEvent(event.get(), window_, |
@@ -376,6 +395,7 @@ class QueueTouchEventDelegate : public GestureEventConsumeDelegate { |
Window* window_; |
WindowEventDispatcher* dispatcher_; |
bool queue_events_; |
+ AckState synchronous_ack_for_next_event_; |
DISALLOW_COPY_AND_ASSIGN(QueueTouchEventDelegate); |
}; |
@@ -4247,7 +4267,7 @@ TEST_F(GestureRecognizerTest, GestureEventSmallPinchEnabled) { |
// Tests that delaying the ack of a touch release doesn't trigger a long press |
// gesture. |
-TEST_F(GestureRecognizerTest, DISABLED_EagerGestureDetection) { |
+TEST_F(GestureRecognizerTest, EagerGestureDetection) { |
scoped_ptr<QueueTouchEventDelegate> delegate( |
new QueueTouchEventDelegate(host()->dispatcher())); |
TimedEvents tes; |
@@ -4280,9 +4300,9 @@ TEST_F(GestureRecognizerTest, DISABLED_EagerGestureDetection) { |
EXPECT_FALSE(delegate->long_press()); |
} |
-// This tests crbug.com/405519, in which events which the gesture detector |
-// ignores cause future events to also be thrown away. |
-TEST_F(GestureRecognizerTest, IgnoredEventsDontPreventFutureEvents) { |
+// This tests crbug.com/405519, in which touch events which the gesture detector |
+// ignores interfere with gesture recognition. |
+TEST_F(GestureRecognizerTest, IgnoredEventsDontBreakGestureRecognition) { |
scoped_ptr<QueueTouchEventDelegate> delegate( |
new QueueTouchEventDelegate(host()->dispatcher())); |
TimedEvents tes; |
@@ -4315,9 +4335,12 @@ TEST_F(GestureRecognizerTest, IgnoredEventsDontPreventFutureEvents) { |
ui::ET_GESTURE_SCROLL_UPDATE); |
delegate->Reset(); |
+ |
+ // Send a valid event, but don't ack it. |
ui::TouchEvent move2( |
ui::ET_TOUCH_MOVED, gfx::Point(65, 202), kTouchId1, tes.Now()); |
DispatchEventUsingWindowDispatcher(&move2); |
+ EXPECT_0_EVENTS(delegate->events()); |
// Send a touchmove event at the same location as the previous touchmove |
// event. This shouldn't do anything. |
@@ -4325,9 +4348,88 @@ TEST_F(GestureRecognizerTest, IgnoredEventsDontPreventFutureEvents) { |
ui::ET_TOUCH_MOVED, gfx::Point(65, 202), kTouchId1, tes.Now()); |
DispatchEventUsingWindowDispatcher(&move3); |
+ // Ack the previous valid event. The intermediary invalid event shouldn't |
+ // interfere. |
delegate->ReceivedAck(); |
EXPECT_1_EVENT(delegate->events(), ui::ET_GESTURE_SCROLL_UPDATE); |
} |
+// Tests that an event stream can have a mix of sync and async acks. |
+TEST_F(GestureRecognizerTest, |
+ MixedSyncAndAsyncAcksDontCauseOutOfOrderDispatch) { |
+ scoped_ptr<QueueTouchEventDelegate> delegate( |
+ new QueueTouchEventDelegate(host()->dispatcher())); |
+ TimedEvents tes; |
+ const int kWindowWidth = 300; |
+ const int kWindowHeight = 400; |
+ const int kTouchId1 = 3; |
+ gfx::Rect bounds(0, 0, kWindowWidth, kWindowHeight); |
+ scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate( |
+ delegate.get(), -1234, bounds, root_window())); |
+ delegate->set_window(window.get()); |
+ |
+ // Start a scroll gesture. |
+ ui::TouchEvent press1( |
+ ui::ET_TOUCH_PRESSED, gfx::Point(0, 0), kTouchId1, tes.Now()); |
+ DispatchEventUsingWindowDispatcher(&press1); |
+ delegate->ReceivedAck(); |
+ |
+ ui::TouchEvent move1( |
+ ui::ET_TOUCH_MOVED, gfx::Point(100, 100), kTouchId1, tes.Now()); |
+ DispatchEventUsingWindowDispatcher(&move1); |
+ delegate->ReceivedAck(); |
+ |
+ delegate->Reset(); |
+ // Dispatch a synchronously consumed touch move, which should be ignored. |
+ delegate->set_synchronous_ack_for_next_event(true); |
+ ui::TouchEvent move2(ui::ET_TOUCH_MOVED, gfx::Point(200, 200), kTouchId1, |
+ tes.Now()); |
+ DispatchEventUsingWindowDispatcher(&move2); |
+ EXPECT_0_EVENTS(delegate->events()); |
+ |
+ // Dispatch a touch move, but don't ack it. |
+ ui::TouchEvent move3(ui::ET_TOUCH_MOVED, gfx::Point(300, 300), kTouchId1, |
+ tes.Now()); |
+ DispatchEventUsingWindowDispatcher(&move3); |
+ |
+ // Dispatch two synchronously consumed touch moves, which should be ignored. |
+ delegate->set_synchronous_ack_for_next_event(true); |
+ ui::TouchEvent move4( |
+ ui::ET_TOUCH_MOVED, gfx::Point(400, 400), kTouchId1, tes.Now()); |
+ DispatchEventUsingWindowDispatcher(&move4); |
+ |
+ delegate->set_synchronous_ack_for_next_event(true); |
+ ui::TouchEvent move5( |
+ ui::ET_TOUCH_MOVED, gfx::Point(500, 500), kTouchId1, tes.Now()); |
+ DispatchEventUsingWindowDispatcher(&move5); |
+ |
+ EXPECT_0_EVENTS(delegate->events()); |
+ EXPECT_EQ(100, delegate->bounding_box().x()); |
+ // Ack the pending touch move, and ensure the most recent gesture event |
+ // used its co-ordinates. |
+ delegate->ReceivedAck(); |
+ EXPECT_EQ(300, delegate->bounding_box().x()); |
+ EXPECT_1_EVENT(delegate->events(), ui::ET_GESTURE_SCROLL_UPDATE); |
+ |
+ // Dispatch a touch move, but don't ack it. |
+ delegate->Reset(); |
+ ui::TouchEvent move6(ui::ET_TOUCH_MOVED, gfx::Point(600, 600), kTouchId1, |
+ tes.Now()); |
+ DispatchEventUsingWindowDispatcher(&move6); |
+ |
+ // Dispatch a synchronously unconsumed touch move. |
+ delegate->set_synchronous_ack_for_next_event(false); |
+ ui::TouchEvent move7( |
+ ui::ET_TOUCH_MOVED, gfx::Point(700, 700), kTouchId1, tes.Now()); |
+ DispatchEventUsingWindowDispatcher(&move7); |
+ |
+ // The synchronous ack is stuck behind the pending touch move. |
+ EXPECT_0_EVENTS(delegate->events()); |
+ |
+ delegate->ReceivedAck(); |
+ EXPECT_2_EVENTS(delegate->events(), ui::ET_GESTURE_SCROLL_UPDATE, |
+ ui::ET_GESTURE_SCROLL_UPDATE); |
+} |
+ |
} // namespace test |
} // namespace aura |