1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
7 #include "base/basictypes.h"
8 #include "base/memory/scoped_ptr.h"
9 #include "base/message_loop/message_loop.h"
10 #include "base/time/time.h"
11 #include "content/browser/renderer_host/input/touch_emulator.h"
12 #include "content/browser/renderer_host/input/touch_emulator_client.h"
13 #include "content/common/input/web_input_event_traits.h"
14 #include "testing/gtest/include/gtest/gtest.h"
17 #include "ui/aura/env.h"
18 #include "ui/aura/test/test_screen.h"
21 using blink::WebGestureEvent
;
22 using blink::WebInputEvent
;
23 using blink::WebKeyboardEvent
;
24 using blink::WebMouseEvent
;
25 using blink::WebMouseWheelEvent
;
26 using blink::WebTouchEvent
;
27 using blink::WebTouchPoint
;
31 class TouchEmulatorTest
: public testing::Test
,
32 public TouchEmulatorClient
{
35 : shift_pressed_(false),
36 mouse_pressed_(false),
37 ack_touches_synchronously_(true),
40 last_event_time_seconds_
=
41 (base::TimeTicks::Now() - base::TimeTicks()).InSecondsF();
42 event_time_delta_seconds_
= 0.1;
45 ~TouchEmulatorTest() override
{}
48 void SetUp() override
{
50 aura::Env::CreateInstance(true);
51 screen_
.reset(aura::TestScreen::Create(gfx::Size()));
52 gfx::Screen::SetScreenInstance(gfx::SCREEN_TYPE_NATIVE
, screen_
.get());
55 emulator_
.reset(new TouchEmulator(this));
56 emulator_
->SetDoubleTapSupportForPageEnabled(false);
57 emulator_
->Enable(ui::GestureProviderConfigType::GENERIC_MOBILE
);
60 void TearDown() override
{
62 EXPECT_EQ("", ExpectedEvents());
65 aura::Env::DeleteInstance();
66 gfx::Screen::SetScreenInstance(gfx::SCREEN_TYPE_NATIVE
, nullptr);
71 void ForwardGestureEvent(const blink::WebGestureEvent
& event
) override
{
72 forwarded_events_
.push_back(event
.type
);
75 void ForwardEmulatedTouchEvent(const blink::WebTouchEvent
& event
) override
{
76 forwarded_events_
.push_back(event
.type
);
77 EXPECT_EQ(1U, event
.touchesLength
);
78 EXPECT_EQ(last_mouse_x_
, event
.touches
[0].position
.x
);
79 EXPECT_EQ(last_mouse_y_
, event
.touches
[0].position
.y
);
80 bool expected_cancelable
= event
.type
!= WebInputEvent::TouchCancel
;
81 EXPECT_EQ(expected_cancelable
, !!event
.cancelable
);
82 if (ack_touches_synchronously_
) {
83 emulator()->HandleTouchEventAck(
84 event
, INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS
);
88 void SetCursor(const WebCursor
& cursor
) override
{}
90 void ShowContextMenuAtPoint(const gfx::Point
& point
) override
{}
93 TouchEmulator
* emulator() const {
94 return emulator_
.get();
97 int modifiers() const {
98 return shift_pressed_
? WebInputEvent::ShiftKey
: 0;
101 std::string
ExpectedEvents() {
103 for (size_t i
= 0; i
< forwarded_events_
.size(); ++i
) {
106 result
+= WebInputEventTraits::GetName(forwarded_events_
[i
]);
108 forwarded_events_
.clear();
112 double GetNextEventTimeSeconds() {
113 last_event_time_seconds_
+= event_time_delta_seconds_
;
114 return last_event_time_seconds_
;
117 void set_event_time_delta_seconds_(double delta
) {
118 event_time_delta_seconds_
= delta
;
121 void SendKeyboardEvent(WebInputEvent::Type type
) {
122 WebKeyboardEvent event
;
123 event
.timeStampSeconds
= GetNextEventTimeSeconds();
125 event
.modifiers
= modifiers();
126 emulator()->HandleKeyboardEvent(event
);
130 DCHECK(!shift_pressed_
);
131 shift_pressed_
= true;
132 SendKeyboardEvent(WebInputEvent::KeyDown
);
135 void ReleaseShift() {
136 DCHECK(shift_pressed_
);
137 shift_pressed_
= false;
138 SendKeyboardEvent(WebInputEvent::KeyUp
);
141 void SendMouseEvent(WebInputEvent::Type type
, int x
, int y
) {
143 event
.timeStampSeconds
= GetNextEventTimeSeconds();
145 event
.button
= mouse_pressed_
? WebMouseEvent::ButtonLeft
:
146 WebMouseEvent::ButtonNone
;
147 event
.modifiers
= modifiers();
150 event
.x
= event
.windowX
= event
.globalX
= x
;
151 event
.y
= event
.windowY
= event
.globalY
= y
;
152 emulator()->HandleMouseEvent(event
);
155 bool SendMouseWheelEvent() {
156 WebMouseWheelEvent event
;
157 event
.type
= WebInputEvent::MouseWheel
;
158 event
.timeStampSeconds
= GetNextEventTimeSeconds();
159 // Return whether mouse wheel is forwarded.
160 return !emulator()->HandleMouseWheelEvent(event
);
163 void MouseDown(int x
, int y
) {
164 DCHECK(!mouse_pressed_
);
165 if (x
!= last_mouse_x_
|| y
!= last_mouse_y_
)
166 SendMouseEvent(WebInputEvent::MouseMove
, x
, y
);
167 mouse_pressed_
= true;
168 SendMouseEvent(WebInputEvent::MouseDown
, x
, y
);
171 void MouseDrag(int x
, int y
) {
172 DCHECK(mouse_pressed_
);
173 SendMouseEvent(WebInputEvent::MouseMove
, x
, y
);
176 void MouseMove(int x
, int y
) {
177 DCHECK(!mouse_pressed_
);
178 SendMouseEvent(WebInputEvent::MouseMove
, x
, y
);
181 void MouseUp(int x
, int y
) {
182 DCHECK(mouse_pressed_
);
183 if (x
!= last_mouse_x_
|| y
!= last_mouse_y_
)
184 SendMouseEvent(WebInputEvent::MouseMove
, x
, y
);
185 SendMouseEvent(WebInputEvent::MouseUp
, x
, y
);
186 mouse_pressed_
= false;
189 bool TouchStart(int x
, int y
, bool ack
) {
190 return SendTouchEvent(
191 WebInputEvent::TouchStart
, WebTouchPoint::StatePressed
, x
, y
, ack
);
194 bool TouchMove(int x
, int y
, bool ack
) {
195 return SendTouchEvent(
196 WebInputEvent::TouchMove
, WebTouchPoint::StateMoved
, x
, y
, ack
);
199 bool TouchEnd(int x
, int y
, bool ack
) {
200 return SendTouchEvent(
201 WebInputEvent::TouchEnd
, WebTouchPoint::StateReleased
, x
, y
, ack
);
204 WebTouchEvent
MakeTouchEvent(WebInputEvent::Type type
,
205 WebTouchPoint::State state
, int x
, int y
) {
208 event
.timeStampSeconds
= GetNextEventTimeSeconds();
209 event
.touchesLength
= 1;
210 event
.touches
[0].id
= 0;
211 event
.touches
[0].state
= state
;
212 event
.touches
[0].position
.x
= x
;
213 event
.touches
[0].position
.y
= y
;
214 event
.touches
[0].screenPosition
.x
= x
;
215 event
.touches
[0].screenPosition
.y
= y
;
219 bool SendTouchEvent(WebInputEvent::Type type
, WebTouchPoint::State state
,
220 int x
, int y
, bool ack
) {
221 WebTouchEvent event
= MakeTouchEvent(type
, state
, x
, y
);
222 if (emulator()->HandleTouchEvent(event
)) {
223 // Touch event is not forwarded.
228 // Can't send ack if there are some pending acks.
229 DCHECK(!touch_events_to_ack_
.size());
231 // Touch event is forwarded, ack should not be handled by emulator.
232 EXPECT_FALSE(emulator()->HandleTouchEventAck(
233 event
, INPUT_EVENT_ACK_STATE_CONSUMED
));
235 touch_events_to_ack_
.push_back(event
);
240 void AckOldestTouchEvent() {
241 DCHECK(touch_events_to_ack_
.size());
242 WebTouchEvent event
= touch_events_to_ack_
[0];
243 touch_events_to_ack_
.erase(touch_events_to_ack_
.begin());
244 // Emulator should not handle ack from native stream.
245 EXPECT_FALSE(emulator()->HandleTouchEventAck(
246 event
, INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS
));
249 void DisableSynchronousTouchAck() { ack_touches_synchronously_
= false; }
252 scoped_ptr
<TouchEmulator
> emulator_
;
253 std::vector
<WebInputEvent::Type
> forwarded_events_
;
254 #if defined(USE_AURA)
255 scoped_ptr
<gfx::Screen
> screen_
;
257 double last_event_time_seconds_
;
258 double event_time_delta_seconds_
;
261 bool ack_touches_synchronously_
;
264 std::vector
<WebTouchEvent
> touch_events_to_ack_
;
265 base::MessageLoopForUI message_loop_
;
269 TEST_F(TouchEmulatorTest
, NoTouches
) {
272 EXPECT_EQ("", ExpectedEvents());
275 TEST_F(TouchEmulatorTest
, Touch
) {
277 EXPECT_EQ("", ExpectedEvents());
279 EXPECT_EQ("TouchStart GestureTapDown", ExpectedEvents());
282 "TouchMove GestureTapCancel GestureScrollBegin GestureScrollUpdate"
283 " TouchEnd GestureScrollEnd",
287 TEST_F(TouchEmulatorTest
, DoubleTapSupport
) {
288 emulator()->SetDoubleTapSupportForPageEnabled(true);
290 EXPECT_EQ("", ExpectedEvents());
292 EXPECT_EQ("TouchStart GestureTapDown", ExpectedEvents());
294 EXPECT_EQ("TouchEnd GestureTapUnconfirmed", ExpectedEvents());
296 EXPECT_EQ("TouchStart GestureTapCancel GestureTapDown", ExpectedEvents());
298 EXPECT_EQ("TouchEnd GestureTapCancel GestureDoubleTap", ExpectedEvents());
301 TEST_F(TouchEmulatorTest
, MultipleTouches
) {
303 EXPECT_EQ("", ExpectedEvents());
305 EXPECT_EQ("TouchStart GestureTapDown", ExpectedEvents());
308 "TouchMove GestureTapCancel GestureScrollBegin GestureScrollUpdate"
309 " TouchEnd GestureScrollEnd",
313 EXPECT_EQ("", ExpectedEvents());
315 EXPECT_EQ("TouchStart GestureTapDown", ExpectedEvents());
318 "TouchMove GestureTapCancel GestureScrollBegin GestureScrollUpdate",
321 EXPECT_EQ("TouchMove GestureScrollUpdate", ExpectedEvents());
324 "TouchMove GestureScrollUpdate TouchEnd GestureScrollEnd",
328 TEST_F(TouchEmulatorTest
, Pinch
) {
330 EXPECT_EQ("TouchStart GestureTapDown", ExpectedEvents());
333 "TouchMove GestureTapCancel GestureScrollBegin GestureScrollUpdate",
336 EXPECT_EQ("", ExpectedEvents());
338 EXPECT_EQ("TouchMove GesturePinchBegin", ExpectedEvents());
340 EXPECT_EQ("", ExpectedEvents());
343 "TouchMove GesturePinchEnd GestureScrollUpdate",
346 EXPECT_EQ("TouchEnd GestureScrollEnd", ExpectedEvents());
349 TEST_F(TouchEmulatorTest
, CancelWithDelayedAck
) {
350 DisableSynchronousTouchAck();
352 // Simulate a sequence that is interrupted by |CancelTouch()|.
354 EXPECT_EQ("TouchStart", ExpectedEvents());
356 EXPECT_EQ("TouchMove", ExpectedEvents());
357 emulator()->CancelTouch();
358 EXPECT_EQ("TouchCancel", ExpectedEvents());
359 // The mouse up should have no effect as the sequence was already cancelled.
361 EXPECT_EQ("", ExpectedEvents());
363 // Simulate a sequence that fully completes before |CancelTouch()|.
365 EXPECT_EQ("TouchStart", ExpectedEvents());
367 EXPECT_EQ("TouchEnd", ExpectedEvents());
368 // |CancelTouch| should have no effect as the sequence was already terminated.
369 emulator()->CancelTouch();
370 EXPECT_EQ("", ExpectedEvents());
373 TEST_F(TouchEmulatorTest
, DisableAndReenable
) {
375 EXPECT_EQ("TouchStart GestureTapDown", ExpectedEvents());
378 "TouchMove GestureTapCancel GestureScrollBegin GestureScrollUpdate",
382 EXPECT_EQ("TouchMove GesturePinchBegin", ExpectedEvents());
384 // Disable while pinch is in progress.
385 emulator()->Disable();
386 EXPECT_EQ("TouchCancel GesturePinchEnd GestureScrollEnd", ExpectedEvents());
390 EXPECT_EQ("", ExpectedEvents());
392 emulator()->Enable(ui::GestureProviderConfigType::GENERIC_MOBILE
);
394 EXPECT_EQ("TouchStart GestureTapDown", ExpectedEvents());
397 "TouchMove GestureTapCancel GestureScrollBegin GestureScrollUpdate",
400 // Disable while scroll is in progress.
401 emulator()->Disable();
402 EXPECT_EQ("TouchCancel GestureScrollEnd", ExpectedEvents());
405 TEST_F(TouchEmulatorTest
, DisableAndReenableDifferentConfig
) {
407 EXPECT_EQ("TouchStart GestureTapDown", ExpectedEvents());
410 "TouchMove GestureTapCancel GestureScrollBegin GestureScrollUpdate",
414 EXPECT_EQ("TouchMove GesturePinchBegin", ExpectedEvents());
416 // Disable while pinch is in progress.
417 emulator()->Disable();
418 EXPECT_EQ("TouchCancel GesturePinchEnd GestureScrollEnd", ExpectedEvents());
422 EXPECT_EQ("", ExpectedEvents());
424 emulator()->Enable(ui::GestureProviderConfigType::GENERIC_DESKTOP
);
426 EXPECT_EQ("TouchStart GestureTapDown", ExpectedEvents());
429 "TouchMove GestureTapCancel GestureScrollBegin GestureScrollUpdate",
432 // Disable while scroll is in progress.
433 emulator()->Disable();
434 EXPECT_EQ("TouchCancel GestureScrollEnd", ExpectedEvents());
437 TEST_F(TouchEmulatorTest
, MouseMovesDropped
) {
439 EXPECT_EQ("", ExpectedEvents());
441 EXPECT_EQ("TouchStart GestureTapDown", ExpectedEvents());
443 // Mouse move after mouse down is never dropped.
444 set_event_time_delta_seconds_(0.001);
447 "TouchMove GestureTapCancel GestureScrollBegin GestureScrollUpdate",
450 // The following mouse moves are dropped.
452 EXPECT_EQ("", ExpectedEvents());
454 EXPECT_EQ("", ExpectedEvents());
456 // Dispatching again.
457 set_event_time_delta_seconds_(0.1);
460 "TouchMove GestureScrollUpdate",
464 "TouchEnd GestureScrollEnd",
468 TEST_F(TouchEmulatorTest
, MouseWheel
) {
470 EXPECT_EQ("", ExpectedEvents());
471 EXPECT_TRUE(SendMouseWheelEvent());
473 EXPECT_EQ("TouchStart GestureTapDown", ExpectedEvents());
474 EXPECT_FALSE(SendMouseWheelEvent());
476 EXPECT_EQ("TouchEnd GestureShowPress GestureTap", ExpectedEvents());
477 EXPECT_TRUE(SendMouseWheelEvent());
479 EXPECT_EQ("TouchStart GestureTapDown", ExpectedEvents());
480 EXPECT_FALSE(SendMouseWheelEvent());
481 emulator()->Disable();
482 EXPECT_EQ("TouchCancel GestureTapCancel", ExpectedEvents());
483 EXPECT_TRUE(SendMouseWheelEvent());
484 emulator()->Enable(ui::GestureProviderConfigType::GENERIC_MOBILE
);
485 EXPECT_TRUE(SendMouseWheelEvent());
488 TEST_F(TouchEmulatorTest
, MultipleTouchStreams
) {
489 // Native stream should be blocked while emulated is active.
491 EXPECT_EQ("", ExpectedEvents());
493 EXPECT_EQ("TouchStart GestureTapDown", ExpectedEvents());
494 EXPECT_FALSE(TouchStart(10, 10, true));
495 EXPECT_FALSE(TouchMove(20, 20, true));
498 "TouchMove GestureTapCancel GestureScrollBegin GestureScrollUpdate"
499 " TouchEnd GestureScrollEnd",
501 EXPECT_FALSE(TouchEnd(20, 20, true));
503 // Emulated stream should be blocked while native is active.
504 EXPECT_TRUE(TouchStart(10, 10, true));
505 EXPECT_TRUE(TouchMove(20, 20, true));
507 EXPECT_EQ("", ExpectedEvents());
508 // Re-enabling in the middle of a touch sequence should not affect this.
509 emulator()->Disable();
510 emulator()->Enable(ui::GestureProviderConfigType::GENERIC_MOBILE
);
512 EXPECT_EQ("", ExpectedEvents());
514 EXPECT_EQ("", ExpectedEvents());
515 EXPECT_TRUE(TouchEnd(20, 20, true));
516 EXPECT_EQ("", ExpectedEvents());
518 // Late ack for TouchEnd should not mess things up.
519 EXPECT_TRUE(TouchStart(10, 10, false));
520 EXPECT_TRUE(TouchMove(20, 20, false));
521 emulator()->Disable();
522 EXPECT_TRUE(TouchEnd(20, 20, false));
523 EXPECT_TRUE(TouchStart(30, 30, false));
524 AckOldestTouchEvent(); // TouchStart.
525 emulator()->Enable(ui::GestureProviderConfigType::GENERIC_MOBILE
);
526 AckOldestTouchEvent(); // TouchMove.
527 AckOldestTouchEvent(); // TouchEnd.
529 EXPECT_EQ("", ExpectedEvents());
531 EXPECT_EQ("", ExpectedEvents());
533 EXPECT_EQ("", ExpectedEvents());
534 AckOldestTouchEvent(); // TouchStart.
536 EXPECT_EQ("", ExpectedEvents());
537 EXPECT_TRUE(TouchMove(30, 40, true));
538 EXPECT_TRUE(TouchEnd(30, 40, true));
540 EXPECT_EQ("", ExpectedEvents());
542 // Emulation should be back to normal.
544 EXPECT_EQ("TouchStart GestureTapDown", ExpectedEvents());
547 "TouchMove GestureTapCancel GestureScrollBegin GestureScrollUpdate"
548 " TouchEnd GestureScrollEnd",
552 TEST_F(TouchEmulatorTest
, MultipleTouchStreamsLateEnable
) {
553 // Enabling in the middle of native touch sequence should be handled.
554 // Send artificial late TouchEnd ack, like it is the first thing emulator
556 WebTouchEvent event
= MakeTouchEvent(
557 WebInputEvent::TouchEnd
, WebTouchPoint::StateReleased
, 10, 10);
558 EXPECT_FALSE(emulator()->HandleTouchEventAck(
559 event
, INPUT_EVENT_ACK_STATE_CONSUMED
));
562 EXPECT_EQ("TouchStart GestureTapDown", ExpectedEvents());
565 "TouchMove GestureTapCancel GestureScrollBegin GestureScrollUpdate"
566 " TouchEnd GestureScrollEnd",
570 TEST_F(TouchEmulatorTest
, CancelAfterDisableDoesNotCrash
) {
571 DisableSynchronousTouchAck();
573 emulator()->Disable();
574 EXPECT_EQ("TouchStart TouchCancel", ExpectedEvents());
575 emulator()->CancelTouch();
578 } // namespace content