Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1173)

Unified Diff: content/browser/renderer_host/input/gesture_event_queue_unittest.cc

Issue 120513005: [Android] Perform eager gesture recognition on MotionEvents (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: More testing Created 6 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: content/browser/renderer_host/input/gesture_event_queue_unittest.cc
diff --git a/content/browser/renderer_host/input/gesture_event_queue_unittest.cc b/content/browser/renderer_host/input/gesture_event_queue_unittest.cc
new file mode 100644
index 0000000000000000000000000000000000000000..a81bc97ed3e256b4f89496e4f68f9890a0ded471
--- /dev/null
+++ b/content/browser/renderer_host/input/gesture_event_queue_unittest.cc
@@ -0,0 +1,449 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/basictypes.h"
+#include "base/memory/scoped_ptr.h"
+#include "content/browser/renderer_host/input/gesture_event_queue.h"
+#include "content/common/input/synthetic_web_input_event_builders.h"
+#include "content/common/input/web_input_event_traits.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/WebKit/public/web/WebInputEvent.h"
+
+using blink::WebGestureEvent;
+using blink::WebInputEvent;
+using blink::WebTouchEvent;
+using blink::WebTouchPoint;
+
+namespace content {
+
+class GestureEventQueueTest : public testing::Test,
+ public GestureEventQueueClient {
+ public:
+ GestureEventQueueTest() : sent_gesture_count_(0) {}
+
+ virtual ~GestureEventQueueTest() {}
+
+ // testing::Test
+ virtual void SetUp() OVERRIDE {
+ queue_.reset(new GestureEventQueue(this));
+ }
+
+ virtual void TearDown() OVERRIDE {
+ queue_.reset();
+ }
+
+ // GestureEventQueueClient
+ virtual void ForwardGestureEvent(const WebGestureEvent& event) OVERRIDE {
+ ++sent_gesture_count_;
+ sent_gestures_.push_back(event.type);
+ }
+
+ protected:
+ typedef std::vector<WebInputEvent::Type> GestureList;
+
+ ::testing::AssertionResult GesturesMatch(const GestureList& expected,
+ const GestureList& actual) {
+ if (expected.size() != actual.size()) {
+ return ::testing::AssertionFailure()
+ << "actual.size(" << actual.size()
+ << ") != expected.size(" << expected.size() << ")";
+ }
+
+ for (size_t i = 0; i < expected.size(); ++i) {
+ if (expected[i] != actual[i]) {
+ return ::testing::AssertionFailure()
+ << "actual[" << i << "] ("
+ << WebInputEventTraits::GetName(actual[i])
+ << ") != expected[" << i << "] ("
+ << WebInputEventTraits::GetName(expected[i]) << ")";
+ }
+ }
+
+ return ::testing::AssertionSuccess();
+ }
+
+ GestureList Gestures(WebInputEvent::Type type) {
+ return GestureList(1, type);
+ }
+
+ GestureList Gestures(WebInputEvent::Type type0, WebInputEvent::Type type1) {
+ GestureList gestures(2);
+ gestures[0] = type0;
+ gestures[1] = type1;
+ return gestures;
+ }
+
+ GestureList Gestures(WebInputEvent::Type type0,
+ WebInputEvent::Type type1,
+ WebInputEvent::Type type2) {
+ GestureList gestures(3);
+ gestures[0] = type0;
+ gestures[1] = type1;
+ gestures[2] = type2;
+ return gestures;
+ }
+
+ GestureList Gestures(WebInputEvent::Type type0,
+ WebInputEvent::Type type1,
+ WebInputEvent::Type type2,
+ WebInputEvent::Type type3) {
+ GestureList gestures(4);
+ gestures[0] = type0;
+ gestures[1] = type1;
+ gestures[2] = type2;
+ gestures[3] = type3;
+ return gestures;
+ }
+
+ void SendTouchGestures() {
+ GestureEventPacket gesture_packet;
+ std::swap(gesture_packet, pending_gesture_packet_);
+ SendTouchGestures(touch_event_, gesture_packet);
+ touch_event_.ResetPoints();
+ }
+
+ void SendTouchGestures(const WebTouchEvent& touch,
+ const GestureEventPacket& packet) {
+ GestureEventPacket touch_packet = GestureEventPacket::FromTouch(touch);
+ for (size_t i = 0; i < packet.gesture_count(); ++i)
+ touch_packet.Push(packet.gesture(i));
+ queue_->OnGestureEventPacket(touch_packet);
+ }
+
+ void SendTimeoutGesture(WebInputEvent::Type type) {
+ queue_->OnGestureEventPacket(
+ GestureEventPacket::FromTouchTimeout(CreateGesture(type)));
+ }
+
+ void SendTouchEventACK(InputEventAckState ack_result) {
+ queue_->OnTouchEventAck(ack_result);
+ }
+
+ void PushGesture(WebInputEvent::Type type) {
+ pending_gesture_packet_.Push(CreateGesture(type));
+ }
+
+ void PressTouchPoint(int x, int y) {
+ touch_event_.PressPoint(x, y);
+ SendTouchGestures();
+ }
+
+ void MoveTouchPoint(int index, int x, int y) {
+ touch_event_.MovePoint(index, x, y);
+ SendTouchGestures();
+ }
+
+ void ReleaseTouchPoint(int index) {
+ touch_event_.ReleasePoint(index);
+ SendTouchGestures();
+ }
+
+ void CancelTouchPoint(int index) {
+ touch_event_.CancelPoint(index);
+ SendTouchGestures();
+ }
+
+ bool GesturesSent() const {
+ return !sent_gestures_.empty();
+ }
+
+ GestureList GetAndResetSentGestures() {
+ GestureList sent_gestures;
+ sent_gestures.swap(sent_gestures_);
+ return sent_gestures;
+ }
+
+ static WebGestureEvent CreateGesture(WebInputEvent::Type type) {
+ return SyntheticWebGestureEventBuilder::Build(
+ type, WebGestureEvent::Touchscreen);
+ }
+
+ private:
+ scoped_ptr<GestureEventQueue> queue_;
+ SyntheticWebTouchEvent touch_event_;
+ GestureEventPacket pending_gesture_packet_;
+ size_t sent_gesture_count_;
+ GestureList sent_gestures_;
+};
+
+TEST_F(GestureEventQueueTest, BasicNoGestures) {
+ PressTouchPoint(1, 1);
+ EXPECT_FALSE(GesturesSent());
+
+ MoveTouchPoint(0, 2, 2);
+ EXPECT_FALSE(GesturesSent());
+
+ // No gestures should be dispatched by the ack, as the queued packets
+ // contained no gestures.
+ SendTouchEventACK(INPUT_EVENT_ACK_STATE_CONSUMED);
+ EXPECT_FALSE(GesturesSent());
+
+ // Release the touch gesture.
+ ReleaseTouchPoint(0);
+ SendTouchEventACK(INPUT_EVENT_ACK_STATE_CONSUMED);
+ SendTouchEventACK(INPUT_EVENT_ACK_STATE_CONSUMED);
+ EXPECT_FALSE(GesturesSent());
+}
+
+TEST_F(GestureEventQueueTest, BasicGestures) {
+ // An unconsumed touch's gesture should be sent.
+ PushGesture(WebInputEvent::GestureScrollBegin);
+ PressTouchPoint(1, 1);
+ EXPECT_FALSE(GesturesSent());
+ SendTouchEventACK(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+ EXPECT_TRUE(GesturesMatch(Gestures(WebInputEvent::GestureScrollBegin),
+ GetAndResetSentGestures()));
+
+ // Multiple gestures can be queued for a single event.
+ PushGesture(WebInputEvent::GestureFlingStart);
+ PushGesture(WebInputEvent::GestureFlingCancel);
+ MoveTouchPoint(0, 1, 1);
+ EXPECT_FALSE(GesturesSent());
+ SendTouchEventACK(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+ EXPECT_TRUE(GesturesMatch(Gestures(WebInputEvent::GestureFlingStart,
+ WebInputEvent::GestureFlingCancel),
+ GetAndResetSentGestures()));
+
+ // A consumed touch's gesture should not be sent.
+ PushGesture(WebInputEvent::GestureFlingStart);
+ PushGesture(WebInputEvent::GestureFlingCancel);
+ ReleaseTouchPoint(0);
+ EXPECT_FALSE(GesturesSent());
+ SendTouchEventACK(INPUT_EVENT_ACK_STATE_CONSUMED);
+ EXPECT_FALSE(GesturesSent());
+}
+
+TEST_F(GestureEventQueueTest, ConsumedThenNotConsumed) {
+ // A consumed touch's gesture should not be sent.
+ PushGesture(WebInputEvent::GestureScrollBegin);
+ PressTouchPoint(1, 1);
+ SendTouchEventACK(INPUT_EVENT_ACK_STATE_CONSUMED);
+ EXPECT_FALSE(GesturesSent());
+
+ // Even if the subsequent touch is not consumed, continue dropping gestures.
+ PushGesture(WebInputEvent::GestureScrollUpdate);
+ MoveTouchPoint(0, 2, 2);
+ SendTouchEventACK(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+ EXPECT_FALSE(GesturesSent());
+
+ // Even if the subsequent touch had no consumer, continue dropping gestures.
+ PushGesture(WebInputEvent::GestureFlingStart);
+ ReleaseTouchPoint(0);
+ SendTouchEventACK(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+ EXPECT_FALSE(GesturesSent());
+}
+
+TEST_F(GestureEventQueueTest, NotConsumedThenNoConsumer) {
+ // An unconsumed touch's gesture should be sent.
+ PushGesture(WebInputEvent::GestureScrollBegin);
+ PressTouchPoint(1, 1);
+ SendTouchEventACK(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+ EXPECT_TRUE(GesturesMatch(Gestures(WebInputEvent::GestureScrollBegin),
+ GetAndResetSentGestures()));
+
+ // If the subsequent touch has no consumer (e.g., a secondary pointer is
+ // pressed but not on a touch handling rect), send the gesture.
+ PushGesture(WebInputEvent::GesturePinchBegin);
+ PressTouchPoint(2, 2);
+ SendTouchEventACK(INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS);
+ EXPECT_TRUE(GesturesMatch(Gestures(WebInputEvent::GesturePinchBegin),
+ GetAndResetSentGestures()));
+
+ // If the subsequent touch is consumed, then the remaining gesture sequence
+ // should be dropped, regardless of subsequent touch ack disposition.
+ PushGesture(WebInputEvent::GestureScrollUpdate);
+ PushGesture(WebInputEvent::GesturePinchUpdate);
+ MoveTouchPoint(0, 2, 2);
+ SendTouchEventACK(INPUT_EVENT_ACK_STATE_CONSUMED);
+ EXPECT_FALSE(GesturesSent());
+
+ PushGesture(WebInputEvent::GesturePinchEnd);
+ ReleaseTouchPoint(1);
+ SendTouchEventACK(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+ EXPECT_FALSE(GesturesSent());
+
+ PushGesture(WebInputEvent::GestureScrollEnd);
+ ReleaseTouchPoint(0);
+ SendTouchEventACK(INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS);
+ EXPECT_FALSE(GesturesSent());
+}
+
+TEST_F(GestureEventQueueTest, MultipleTouchSequences) {
+ // Queue two touch-to-gestures sequences.
+ PushGesture(WebInputEvent::GestureFlingStart);
+ PressTouchPoint(1, 1);
+ PushGesture(WebInputEvent::GestureFlingCancel);
+ ReleaseTouchPoint(0);
+ PushGesture(WebInputEvent::GestureFlingStart);
+ PressTouchPoint(1, 1);
+ PushGesture(WebInputEvent::GestureFlingCancel);
+ ReleaseTouchPoint(0);
+
+ // The first gesture sequence should not be allowed.
+ SendTouchEventACK(INPUT_EVENT_ACK_STATE_CONSUMED);
+ SendTouchEventACK(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+ EXPECT_FALSE(GesturesSent());
+
+ // The subsequent sequence should "reset" allowance.
+ SendTouchEventACK(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+ SendTouchEventACK(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+ EXPECT_TRUE(GesturesMatch(Gestures(WebInputEvent::GestureFlingStart,
+ WebInputEvent::GestureFlingCancel),
+ GetAndResetSentGestures()));
+}
+
+TEST_F(GestureEventQueueTest, FlingCancelledOnNewTouchSequence) {
+ // Simulate a fling.
+ PressTouchPoint(1, 1);
+ SendTouchEventACK(INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS);
+ PushGesture(WebInputEvent::GestureFlingStart);
+ ReleaseTouchPoint(0);
+ SendTouchEventACK(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+ EXPECT_TRUE(GesturesMatch(Gestures(WebInputEvent::GestureFlingStart),
+ GetAndResetSentGestures()));
+
+ // A new touch seqeuence should cancel the outstanding fling.
+ PressTouchPoint(1, 1);
+ ReleaseTouchPoint(0);
+ SendTouchEventACK(INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS);
+ EXPECT_TRUE(GesturesMatch(Gestures(WebInputEvent::GestureFlingCancel),
+ GetAndResetSentGestures()));
+}
+
+TEST_F(GestureEventQueueTest, FlingCancelledOnScrollBegin) {
+ // Simulate a fling sequence.
+ PushGesture(WebInputEvent::GestureScrollBegin);
+ PushGesture(WebInputEvent::GestureFlingStart);
+ PressTouchPoint(1, 1);
+ SendTouchEventACK(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+ EXPECT_TRUE(GesturesMatch(Gestures(WebInputEvent::GestureScrollBegin,
+ WebInputEvent::GestureFlingStart),
+ GetAndResetSentGestures()));
+
+ // The new fling should cancel the preceding one.
+ PushGesture(WebInputEvent::GestureScrollBegin);
+ PushGesture(WebInputEvent::GestureFlingStart);
+ ReleaseTouchPoint(0);
+ SendTouchEventACK(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+ EXPECT_TRUE(GesturesMatch(Gestures(WebInputEvent::GestureFlingCancel,
+ WebInputEvent::GestureScrollBegin,
+ WebInputEvent::GestureFlingStart),
+ GetAndResetSentGestures()));
+}
+
+TEST_F(GestureEventQueueTest, FlingNotCancelledIfGFCEventReceived) {
+ // Simulate a fling that is started then cancelled.
+ PushGesture(WebInputEvent::GestureFlingStart);
+ PressTouchPoint(1, 1);
+ SendTouchEventACK(INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS);
+ PushGesture(WebInputEvent::GestureFlingCancel);
+ ReleaseTouchPoint(0);
+ SendTouchEventACK(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+ EXPECT_TRUE(GesturesMatch(Gestures(WebInputEvent::GestureFlingStart,
+ WebInputEvent::GestureFlingCancel),
+ GetAndResetSentGestures()));
+
+ // A new touch sequence will not inject a GestureFlingCancel, as the fling
+ // has already been cancelled.
+ PressTouchPoint(1, 1);
+ ReleaseTouchPoint(0);
+ SendTouchEventACK(INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS);
+ EXPECT_FALSE(GesturesSent());
+}
+
+TEST_F(GestureEventQueueTest, TapCancelledWhenScrollBegins) {
+ PushGesture(WebInputEvent::GestureTapDown);
+ PressTouchPoint(1, 1);
+ SendTouchEventACK(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+ EXPECT_TRUE(GesturesMatch(Gestures(WebInputEvent::GestureTapDown),
+ GetAndResetSentGestures()));
+
+ // If the subsequent touch turns into a scroll, the tap should be cancelled.
+ PushGesture(WebInputEvent::GestureScrollBegin);
+ MoveTouchPoint(0, 2, 2);
+ SendTouchEventACK(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+ EXPECT_TRUE(GesturesMatch(Gestures(WebInputEvent::GestureTapCancel,
+ WebInputEvent::GestureScrollBegin),
+ GetAndResetSentGestures()));
+}
+
+TEST_F(GestureEventQueueTest, TapCancelledWhenTouchConsumed) {
+ PushGesture(WebInputEvent::GestureTapDown);
+ PressTouchPoint(1, 1);
+ SendTouchEventACK(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+ EXPECT_TRUE(GesturesMatch(Gestures(WebInputEvent::GestureTapDown),
+ GetAndResetSentGestures()));
+
+ // If the subsequent touch is consumed, the tap should be cancelled.
+ PushGesture(WebInputEvent::GestureScrollBegin);
+ MoveTouchPoint(0, 2, 2);
+ SendTouchEventACK(INPUT_EVENT_ACK_STATE_CONSUMED);
+ EXPECT_TRUE(GesturesMatch(Gestures(WebInputEvent::GestureTapCancel),
+ GetAndResetSentGestures()));
+}
+
+TEST_F(GestureEventQueueTest, TapNotCancelledIfTapEndingEventReceived) {
+ PushGesture(WebInputEvent::GestureTapDown);
+ PressTouchPoint(1, 1);
+ PressTouchPoint(2, 2);
+ SendTouchEventACK(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+ SendTouchEventACK(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+ EXPECT_TRUE(GesturesMatch(Gestures(WebInputEvent::GestureTapDown),
+ GetAndResetSentGestures()));
+
+ PushGesture(WebInputEvent::GestureTap);
+ ReleaseTouchPoint(1);
+ SendTouchEventACK(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+ EXPECT_TRUE(GesturesMatch(Gestures(WebInputEvent::GestureTap),
+ GetAndResetSentGestures()));
+
+ // The tap should not be cancelled as it was terminated by a |GestureTap|.
+ ReleaseTouchPoint(0);
+ SendTouchEventACK(INPUT_EVENT_ACK_STATE_CONSUMED);
+ EXPECT_FALSE(GesturesSent());
+}
+
+TEST_F(GestureEventQueueTest, TimeoutGestures) {
+ // If the sequence is allowed, and there are no preceding gestures, the
+ // timeout gestures should be forwarded immediately.
+ PressTouchPoint(1, 1);
+ SendTouchEventACK(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+ EXPECT_FALSE(GesturesSent());
+
+ SendTimeoutGesture(WebInputEvent::GestureShowPress);
+ EXPECT_TRUE(GesturesMatch(Gestures(WebInputEvent::GestureShowPress),
+ GetAndResetSentGestures()));
+
+ SendTimeoutGesture(WebInputEvent::GestureLongPress);
+ EXPECT_TRUE(GesturesMatch(Gestures(WebInputEvent::GestureLongPress),
+ GetAndResetSentGestures()));
+
+ ReleaseTouchPoint(0);
+ SendTouchEventACK(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+
+ // If the sequence is disallowed, and there are no preceding gestures, the
+ // timeout gestures should be dropped immediately.
+ PressTouchPoint(1, 1);
+ SendTouchEventACK(INPUT_EVENT_ACK_STATE_CONSUMED);
+ EXPECT_FALSE(GesturesSent());
+
+ SendTimeoutGesture(WebInputEvent::GestureShowPress);
+ EXPECT_FALSE(GesturesSent());
+ ReleaseTouchPoint(0);
+ SendTouchEventACK(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+
+ // If the sequence has a pending ack, the timeout gestures should
+ // remain queued until the ack is received.
+ PressTouchPoint(1, 1);
+ EXPECT_FALSE(GesturesSent());
+
+ SendTimeoutGesture(WebInputEvent::GestureLongPress);
+ EXPECT_FALSE(GesturesSent());
+
+ SendTouchEventACK(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+ EXPECT_TRUE(GesturesMatch(Gestures(WebInputEvent::GestureLongPress),
+ GetAndResetSentGestures()));
+}
+
+} // namespace content
« no previous file with comments | « content/browser/renderer_host/input/gesture_event_queue.cc ('k') | content/browser/renderer_host/render_widget_host_impl.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698