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.
4
5 #include "ui/chromeos/touch_exploration_controller.h"
6
7 #include "base/test/simple_test_tick_clock.h"
8 #include "base/time/time.h"
9 #include "ui/aura/client/cursor_client.h"
10 #include "ui/aura/test/aura_test_base.h"
11 #include "ui/aura/test/event_generator.h"
12 #include "ui/aura/test/test_cursor_client.h"
13 #include "ui/aura/window.h"
14 #include "ui/events/event.h"
15 #include "ui/events/event_utils.h"
16 #include "ui/gfx/geometry/point.h"
17 #include "ui/gl/gl_implementation.h"
18 #include "ui/gl/gl_surface.h"
19
20 namespace ui {
21
22 namespace {
23 // Records all mouse and touch events.
24 class EventCapturer : public ui::EventHandler {
25 public:
EventCapturer()26 EventCapturer() {}
~EventCapturer()27 virtual ~EventCapturer() {}
28
Reset()29 void Reset() {
30 events_.clear();
31 }
32
OnEvent(ui::Event * event)33 virtual void OnEvent(ui::Event* event) OVERRIDE {
34 if (event->IsMouseEvent()) {
35 events_.push_back(
36 new ui::MouseEvent(static_cast<ui::MouseEvent&>(*event)));
37 } else if (event->IsTouchEvent()) {
38 events_.push_back(
39 new ui::TouchEvent(static_cast<ui::TouchEvent&>(*event)));
40 } else {
41 return;
42 }
43 // Stop event propagation so we don't click on random stuff that
44 // might break test assumptions.
45 event->StopPropagation();
46 // If there is a possibility that we're in an infinite loop, we should
47 // exit early with a sensible error rather than letting the test time out.
48 ASSERT_LT(events_.size(), 100u);
49 }
captured_events() const50 const ScopedVector<ui::LocatedEvent>& captured_events() const {
51 return events_;
52 }
53
54 private:
55 ScopedVector<ui::LocatedEvent> events_;
56
57 DISALLOW_COPY_AND_ASSIGN(EventCapturer);
58 };
59
60 } // namespace
61
62 class TouchExplorationTest : public aura::test::AuraTestBase {
63 public:
TouchExplorationTest()64 TouchExplorationTest()
65 : simulated_clock_(new base::SimpleTestTickClock()) {}
~TouchExplorationTest()66 virtual ~TouchExplorationTest() {}
67
SetUp()68 virtual void SetUp() OVERRIDE {
69 if (gfx::GetGLImplementation() == gfx::kGLImplementationNone)
70 gfx::GLSurface::InitializeOneOffForTests();
71 aura::test::AuraTestBase::SetUp();
72 cursor_client_.reset(new aura::test::TestCursorClient(root_window()));
73 root_window()->AddPreTargetHandler(&event_capturer_);
74 generator_.reset(new aura::test::EventGenerator(root_window()));
75 // The generator takes ownership of the clock.
76 generator_->SetTickClock(scoped_ptr<base::TickClock>(simulated_clock_));
77 cursor_client()->ShowCursor();
78 cursor_client()->DisableMouseEvents();
79 }
80
TearDown()81 virtual void TearDown() OVERRIDE {
82 root_window()->RemovePreTargetHandler(&event_capturer_);
83 SwitchTouchExplorationMode(false);
84 cursor_client_.reset();
85 aura::test::AuraTestBase::TearDown();
86 }
87
88 protected:
cursor_client()89 aura::client::CursorClient* cursor_client() { return cursor_client_.get(); }
90
GetCapturedEvents()91 const ScopedVector<ui::LocatedEvent>& GetCapturedEvents() {
92 return event_capturer_.captured_events();
93 }
94
GetCapturedEventsOfType(int type)95 std::vector<ui::LocatedEvent*> GetCapturedEventsOfType(int type) {
96 const ScopedVector<ui::LocatedEvent>& all_events = GetCapturedEvents();
97 std::vector<ui::LocatedEvent*> events;
98 for (size_t i = 0; i < all_events.size(); ++i) {
99 if (type == all_events[i]->type())
100 events.push_back(all_events[i]);
101 }
102 return events;
103 }
104
ClearCapturedEvents()105 void ClearCapturedEvents() {
106 event_capturer_.Reset();
107 }
108
AdvanceSimulatedTimePastTapDelay()109 void AdvanceSimulatedTimePastTapDelay() {
110 simulated_clock_->Advance(base::TimeDelta::FromMilliseconds(1000));
111 touch_exploration_controller_->CallTapTimerNowForTesting();
112 }
113
SwitchTouchExplorationMode(bool on)114 void SwitchTouchExplorationMode(bool on) {
115 if (!on && touch_exploration_controller_.get()) {
116 touch_exploration_controller_.reset();
117 } else if (on && !touch_exploration_controller_.get()) {
118 touch_exploration_controller_.reset(
119 new ui::TouchExplorationController(root_window()));
120 touch_exploration_controller_->SetEventHandlerForTesting(
121 &event_capturer_);
122 cursor_client()->ShowCursor();
123 cursor_client()->DisableMouseEvents();
124 }
125 }
126
EnterTouchExplorationModeAtLocation(gfx::Point tap_location)127 void EnterTouchExplorationModeAtLocation(gfx::Point tap_location) {
128 ui::TouchEvent touch_press(ui::ET_TOUCH_PRESSED, tap_location, 0, Now());
129 generator_->Dispatch(&touch_press);
130 AdvanceSimulatedTimePastTapDelay();
131 EXPECT_TRUE(IsInTouchToMouseMode());
132 }
133
IsInTouchToMouseMode()134 bool IsInTouchToMouseMode() {
135 aura::client::CursorClient* cursor_client =
136 aura::client::GetCursorClient(root_window());
137 return cursor_client &&
138 cursor_client->IsMouseEventsEnabled() &&
139 !cursor_client->IsCursorVisible();
140 }
141
IsInNoFingersDownState()142 bool IsInNoFingersDownState() {
143 return touch_exploration_controller_->IsInNoFingersDownStateForTesting();
144 }
145
Now()146 base::TimeDelta Now() {
147 // This is the same as what EventTimeForNow() does, but here we do it
148 // with our simulated clock.
149 return base::TimeDelta::FromInternalValue(
150 simulated_clock_->NowTicks().ToInternalValue());
151 }
152
153 scoped_ptr<aura::test::EventGenerator> generator_;
154 ui::GestureDetector::Config gesture_detector_config_;
155 // Owned by |generator_|.
156 base::SimpleTestTickClock* simulated_clock_;
157
158 private:
159 EventCapturer event_capturer_;
160 scoped_ptr<ui::TouchExplorationController> touch_exploration_controller_;
161 scoped_ptr<aura::test::TestCursorClient> cursor_client_;
162
163 DISALLOW_COPY_AND_ASSIGN(TouchExplorationTest);
164 };
165
166 // Executes a number of assertions to confirm that |e1| and |e2| are touch
167 // events and are equal to each other.
ConfirmEventsAreTouchAndEqual(ui::Event * e1,ui::Event * e2)168 void ConfirmEventsAreTouchAndEqual(ui::Event* e1, ui::Event* e2) {
169 ASSERT_TRUE(e1->IsTouchEvent());
170 ASSERT_TRUE(e2->IsTouchEvent());
171 ui::TouchEvent* touch_event1 = static_cast<ui::TouchEvent*>(e1);
172 ui::TouchEvent* touch_event2 = static_cast<ui::TouchEvent*>(e2);
173 EXPECT_EQ(touch_event1->type(), touch_event2->type());
174 EXPECT_EQ(touch_event1->location(), touch_event2->location());
175 EXPECT_EQ(touch_event1->touch_id(), touch_event2->touch_id());
176 EXPECT_EQ(touch_event1->flags(), touch_event2->flags());
177 EXPECT_EQ(touch_event1->time_stamp(), touch_event2->time_stamp());
178 }
179
180 // Executes a number of assertions to confirm that |e1| and |e2| are mouse
181 // events and are equal to each other.
ConfirmEventsAreMouseAndEqual(ui::Event * e1,ui::Event * e2)182 void ConfirmEventsAreMouseAndEqual(ui::Event* e1, ui::Event* e2) {
183 ASSERT_TRUE(e1->IsMouseEvent());
184 ASSERT_TRUE(e2->IsMouseEvent());
185 ui::MouseEvent* mouse_event1 = static_cast<ui::MouseEvent*>(e1);
186 ui::MouseEvent* mouse_event2 = static_cast<ui::MouseEvent*>(e2);
187 EXPECT_EQ(mouse_event1->type(), mouse_event2->type());
188 EXPECT_EQ(mouse_event1->location(), mouse_event2->location());
189 EXPECT_EQ(mouse_event1->root_location(), mouse_event2->root_location());
190 EXPECT_EQ(mouse_event1->flags(), mouse_event2->flags());
191 }
192
193 #define CONFIRM_EVENTS_ARE_TOUCH_AND_EQUAL(e1, e2) \
194 ASSERT_NO_FATAL_FAILURE(ConfirmEventsAreTouchAndEqual(e1, e2))
195
196 #define CONFIRM_EVENTS_ARE_MOUSE_AND_EQUAL(e1, e2) \
197 ASSERT_NO_FATAL_FAILURE(ConfirmEventsAreMouseAndEqual(e1, e2))
198
199 // TODO(mfomitchev): Need to investigate why we don't get mouse enter/exit
200 // events when running these tests as part of ui_unittests. We do get them when
201 // the tests are run as part of ash unit tests.
202
TEST_F(TouchExplorationTest,EntersTouchToMouseModeAfterPressAndDelay)203 TEST_F(TouchExplorationTest, EntersTouchToMouseModeAfterPressAndDelay) {
204 SwitchTouchExplorationMode(true);
205 EXPECT_FALSE(IsInTouchToMouseMode());
206 generator_->PressTouch();
207 AdvanceSimulatedTimePastTapDelay();
208 EXPECT_TRUE(IsInTouchToMouseMode());
209 }
210
TEST_F(TouchExplorationTest,EntersTouchToMouseModeAfterMoveOutsideSlop)211 TEST_F(TouchExplorationTest, EntersTouchToMouseModeAfterMoveOutsideSlop) {
212 int slop = gesture_detector_config_.touch_slop;
213 int half_slop = slop / 2;
214
215 SwitchTouchExplorationMode(true);
216 EXPECT_FALSE(IsInTouchToMouseMode());
217 generator_->set_current_location(gfx::Point(11, 12));
218 generator_->PressTouch();
219 generator_->MoveTouch(gfx::Point(11 + half_slop, 12));
220 EXPECT_FALSE(IsInTouchToMouseMode());
221 generator_->MoveTouch(gfx::Point(11, 12 + half_slop));
222 EXPECT_FALSE(IsInTouchToMouseMode());
223 generator_->MoveTouch(gfx::Point(11 + slop + 1, 12));
224 EXPECT_TRUE(IsInTouchToMouseMode());
225 }
226
TEST_F(TouchExplorationTest,OneFingerTap)227 TEST_F(TouchExplorationTest, OneFingerTap) {
228 SwitchTouchExplorationMode(true);
229 gfx::Point location(11, 12);
230 generator_->set_current_location(location);
231 generator_->PressTouch();
232 generator_->ReleaseTouch();
233 AdvanceSimulatedTimePastTapDelay();
234
235 std::vector<ui::LocatedEvent*> events =
236 GetCapturedEventsOfType(ui::ET_MOUSE_MOVED);
237 ASSERT_EQ(1U, events.size());
238
239 EXPECT_EQ(location, events[0]->location());
240 EXPECT_TRUE(events[0]->flags() & ui::EF_IS_SYNTHESIZED);
241 EXPECT_TRUE(events[0]->flags() & ui::EF_TOUCH_ACCESSIBILITY);
242 EXPECT_TRUE(IsInNoFingersDownState());
243 }
244
TEST_F(TouchExplorationTest,ActualMouseMovesUnaffected)245 TEST_F(TouchExplorationTest, ActualMouseMovesUnaffected) {
246 SwitchTouchExplorationMode(true);
247
248 gfx::Point location_start(11, 12);
249 gfx::Point location_end(13, 14);
250 generator_->set_current_location(location_start);
251 generator_->PressTouch();
252 AdvanceSimulatedTimePastTapDelay();
253 generator_->MoveTouch(location_end);
254
255 gfx::Point location_real_mouse_move(15, 16);
256 ui::MouseEvent mouse_move(ui::ET_MOUSE_MOVED,
257 location_real_mouse_move,
258 location_real_mouse_move,
259 0,
260 0);
261 generator_->Dispatch(&mouse_move);
262 generator_->ReleaseTouch();
263
264 std::vector<ui::LocatedEvent*> events =
265 GetCapturedEventsOfType(ui::ET_MOUSE_MOVED);
266 ASSERT_EQ(4U, events.size());
267
268 EXPECT_EQ(location_start, events[0]->location());
269 EXPECT_TRUE(events[0]->flags() & ui::EF_IS_SYNTHESIZED);
270 EXPECT_TRUE(events[0]->flags() & ui::EF_TOUCH_ACCESSIBILITY);
271
272 EXPECT_EQ(location_end, events[1]->location());
273 EXPECT_TRUE(events[1]->flags() & ui::EF_IS_SYNTHESIZED);
274 EXPECT_TRUE(events[1]->flags() & ui::EF_TOUCH_ACCESSIBILITY);
275
276 // The real mouse move goes through.
277 EXPECT_EQ(location_real_mouse_move, events[2]->location());
278 CONFIRM_EVENTS_ARE_MOUSE_AND_EQUAL(events[2], &mouse_move);
279 EXPECT_FALSE(events[2]->flags() & ui::EF_IS_SYNTHESIZED);
280 EXPECT_FALSE(events[2]->flags() & ui::EF_TOUCH_ACCESSIBILITY);
281
282 // The touch release gets written as a mouse move.
283 EXPECT_EQ(location_end, events[3]->location());
284 EXPECT_TRUE(events[3]->flags() & ui::EF_IS_SYNTHESIZED);
285 EXPECT_TRUE(events[3]->flags() & ui::EF_TOUCH_ACCESSIBILITY);
286 EXPECT_TRUE(IsInNoFingersDownState());
287 }
288
289 // Turn the touch exploration mode on in the middle of the touch gesture.
290 // Confirm that events from the finger which was touching when the mode was
291 // turned on don't get rewritten.
TEST_F(TouchExplorationTest,TurnOnMidTouch)292 TEST_F(TouchExplorationTest, TurnOnMidTouch) {
293 SwitchTouchExplorationMode(false);
294 generator_->PressTouchId(1);
295 EXPECT_TRUE(cursor_client()->IsCursorVisible());
296 ClearCapturedEvents();
297
298 // Enable touch exploration mode while the first finger is touching the
299 // screen. Ensure that subsequent events from that first finger are not
300 // affected by the touch exploration mode, while the touch events from another
301 // finger get rewritten.
302 SwitchTouchExplorationMode(true);
303 ui::TouchEvent touch_move(ui::ET_TOUCH_MOVED,
304 gfx::Point(11, 12),
305 1,
306 Now());
307 generator_->Dispatch(&touch_move);
308 EXPECT_TRUE(cursor_client()->IsCursorVisible());
309 EXPECT_FALSE(cursor_client()->IsMouseEventsEnabled());
310 const ScopedVector<ui::LocatedEvent>& captured_events = GetCapturedEvents();
311 ASSERT_EQ(1u, captured_events.size());
312 CONFIRM_EVENTS_ARE_TOUCH_AND_EQUAL(captured_events[0], &touch_move);
313 ClearCapturedEvents();
314
315 // The press from the second finger should get rewritten.
316 generator_->PressTouchId(2);
317 AdvanceSimulatedTimePastTapDelay();
318 EXPECT_TRUE(IsInTouchToMouseMode());
319 ScopedVector<ui::LocatedEvent>::const_iterator it;
320 for (it = captured_events.begin(); it != captured_events.end(); ++it) {
321 if ((*it)->type() == ui::ET_MOUSE_MOVED)
322 break;
323 }
324 EXPECT_NE(captured_events.end(), it);
325 ClearCapturedEvents();
326
327 // The release of the first finger shouldn't be affected.
328 ui::TouchEvent touch_release(ui::ET_TOUCH_RELEASED,
329 gfx::Point(11, 12),
330 1,
331 Now());
332 generator_->Dispatch(&touch_release);
333 ASSERT_EQ(1u, captured_events.size());
334 CONFIRM_EVENTS_ARE_TOUCH_AND_EQUAL(captured_events[0], &touch_release);
335 ClearCapturedEvents();
336
337 // The move and release from the second finger should get rewritten.
338 generator_->MoveTouchId(gfx::Point(13, 14), 2);
339 generator_->ReleaseTouchId(2);
340 ASSERT_EQ(2u, captured_events.size());
341 EXPECT_EQ(ui::ET_MOUSE_MOVED, captured_events[0]->type());
342 EXPECT_EQ(ui::ET_MOUSE_MOVED, captured_events[1]->type());
343 EXPECT_TRUE(IsInNoFingersDownState());
344 }
345
TEST_F(TouchExplorationTest,TwoFingerTouch)346 TEST_F(TouchExplorationTest, TwoFingerTouch) {
347 SwitchTouchExplorationMode(true);
348 generator_->PressTouchId(1);
349 ClearCapturedEvents();
350
351 // Confirm events from the second finger go through as is.
352 ui::TouchEvent touch_press(
353 ui::ET_TOUCH_PRESSED,
354 gfx::Point(10, 11),
355 2,
356 Now());
357 generator_->Dispatch(&touch_press);
358 EXPECT_TRUE(cursor_client()->IsCursorVisible());
359 EXPECT_FALSE(cursor_client()->IsMouseEventsEnabled());
360 const ScopedVector<ui::LocatedEvent>& captured_events = GetCapturedEvents();
361 // TODO(mfomitchev): mouse enter/exit events
362 // There will be a ET_MOUSE_EXITED event synthesized when the mouse cursor is
363 // hidden - ignore it.
364 ScopedVector<ui::LocatedEvent>::const_iterator it;
365 for (it = captured_events.begin(); it != captured_events.end(); ++it) {
366 if ((*it)->type() == ui::ET_TOUCH_PRESSED) {
367 CONFIRM_EVENTS_ARE_TOUCH_AND_EQUAL(*it, &touch_press);
368 break;
369 }
370 }
371 EXPECT_NE(captured_events.end(), it);
372 ClearCapturedEvents();
373 ui::TouchEvent touch_move(
374 ui::ET_TOUCH_MOVED,
375 gfx::Point(20, 21),
376 2,
377 Now());
378 generator_->Dispatch(&touch_move);
379 ASSERT_EQ(1u, captured_events.size());
380 CONFIRM_EVENTS_ARE_TOUCH_AND_EQUAL(captured_events[0], &touch_move);
381 ClearCapturedEvents();
382
383 // Confirm mouse moves go through unaffected.
384 ui::MouseEvent mouse_move(ui::ET_MOUSE_MOVED,
385 gfx::Point(13, 14),
386 gfx::Point(13, 14),
387 0,
388 0);
389 generator_->Dispatch(&mouse_move);
390 // TODO(mfomitchev): mouse enter/exit events
391 // Ignore synthesized ET_MOUSE_ENTERED/ET_MOUSE_EXITED
392 for (it = captured_events.begin(); it != captured_events.end(); ++it) {
393 if ((*it)->type() == ui::ET_MOUSE_MOVED) {
394 CONFIRM_EVENTS_ARE_MOUSE_AND_EQUAL(*it, &mouse_move);
395 break;
396 }
397 }
398 EXPECT_NE(captured_events.end(), it);
399 ClearCapturedEvents();
400
401 // Events from the first finger should not go through while the second finger
402 // is touching.
403 gfx::Point touch1_location = gfx::Point(15, 16);
404 generator_->MoveTouchId(touch1_location, 1);
405 EXPECT_EQ(0u, GetCapturedEvents().size());
406
407 EXPECT_TRUE(cursor_client()->IsCursorVisible());
408 EXPECT_FALSE(cursor_client()->IsMouseEventsEnabled());
409
410 // A release of the second finger should be rewritten as a mouse move
411 // of that finger to the |touch1_location| and we stay in passthrough
412 // mode.
413 ui::TouchEvent touch_release(
414 ui::ET_TOUCH_RELEASED,
415 gfx::Point(25, 26),
416 2,
417 Now());
418 generator_->Dispatch(&touch_release);
419 EXPECT_FALSE(IsInTouchToMouseMode());
420 ASSERT_EQ(captured_events.size(), 1u);
421 EXPECT_EQ(touch1_location, captured_events[0]->location());
422 }
423
TEST_F(TouchExplorationTest,MultiFingerTouch)424 TEST_F(TouchExplorationTest, MultiFingerTouch) {
425 SwitchTouchExplorationMode(true);
426 generator_->PressTouchId(1);
427 generator_->PressTouchId(2);
428 ClearCapturedEvents();
429
430 // Confirm events from other fingers go through as is.
431 ui::TouchEvent touch3_press(ui::ET_TOUCH_PRESSED,
432 gfx::Point(10, 11),
433 3,
434 Now());
435 ui::TouchEvent touch3_move1(ui::ET_TOUCH_MOVED,
436 gfx::Point(12, 13),
437 3,
438 Now());
439 ui::TouchEvent touch4_press(ui::ET_TOUCH_PRESSED,
440 gfx::Point(20, 21),
441 4,
442 Now());
443 ui::TouchEvent touch3_move2(ui::ET_TOUCH_MOVED,
444 gfx::Point(14, 15),
445 3,
446 Now());
447 ui::TouchEvent touch4_move(ui::ET_TOUCH_MOVED,
448 gfx::Point(22, 23),
449 4,
450 Now());
451 ui::TouchEvent touch3_release(ui::ET_TOUCH_RELEASED,
452 gfx::Point(14, 15),
453 3,
454 Now());
455 ui::TouchEvent touch4_release(ui::ET_TOUCH_RELEASED,
456 gfx::Point(22, 23),
457 4,
458 Now());
459 generator_->Dispatch(&touch3_press);
460 generator_->Dispatch(&touch3_move1);
461 generator_->Dispatch(&touch4_press);
462 generator_->Dispatch(&touch3_move2);
463 generator_->Dispatch(&touch4_move);
464 generator_->Dispatch(&touch3_release);
465 generator_->Dispatch(&touch4_release);
466
467 const ScopedVector<ui::LocatedEvent>& captured_events = GetCapturedEvents();
468 ASSERT_EQ(7u, captured_events.size());
469 CONFIRM_EVENTS_ARE_TOUCH_AND_EQUAL(captured_events[0], &touch3_press);
470 CONFIRM_EVENTS_ARE_TOUCH_AND_EQUAL(captured_events[1], &touch3_move1);
471 CONFIRM_EVENTS_ARE_TOUCH_AND_EQUAL(captured_events[2], &touch4_press);
472 CONFIRM_EVENTS_ARE_TOUCH_AND_EQUAL(captured_events[3], &touch3_move2);
473 CONFIRM_EVENTS_ARE_TOUCH_AND_EQUAL(captured_events[4], &touch4_move);
474
475 // The release of finger 3 is rewritten as a move to the former location
476 // of finger 1.
477 EXPECT_EQ(ui::ET_TOUCH_MOVED, captured_events[5]->type());
478 CONFIRM_EVENTS_ARE_TOUCH_AND_EQUAL(captured_events[6], &touch4_release);
479 }
480
481 // Test the case when there are multiple fingers on the screen and the first
482 // finger is released. This should be ignored, but then the second finger
483 // release should be passed through.
TEST_F(TouchExplorationTest,FirstFingerLifted)484 TEST_F(TouchExplorationTest, FirstFingerLifted) {
485 SwitchTouchExplorationMode(true);
486 generator_->PressTouchId(1);
487 generator_->PressTouchId(2);
488 gfx::Point touch2_location(10, 11);
489 generator_->MoveTouchId(touch2_location, 2);
490 generator_->PressTouchId(3);
491 gfx::Point touch3_location(20, 21);
492 generator_->MoveTouchId(touch3_location, 3);
493 ClearCapturedEvents();
494
495 // Release of finger 1 should be ignored.
496 generator_->ReleaseTouchId(1);
497 const ScopedVector<ui::LocatedEvent>& captured_events = GetCapturedEvents();
498 ASSERT_EQ(0u, captured_events.size());
499
500 // Move of finger 2 should be passed through.
501 gfx::Point touch2_new_location(20, 11);
502 generator_->MoveTouchId(touch2_new_location, 2);
503 ASSERT_EQ(1u, captured_events.size());
504 EXPECT_EQ(ui::ET_TOUCH_MOVED, captured_events[0]->type());
505 EXPECT_EQ(touch2_new_location, captured_events[0]->location());
506 ClearCapturedEvents();
507
508 // Release of finger 2 should be passed through.
509 ui::TouchEvent touch2_release(
510 ui::ET_TOUCH_RELEASED,
511 gfx::Point(14, 15),
512 2,
513 Now());
514 generator_->Dispatch(&touch2_release);
515 ASSERT_EQ(1u, captured_events.size());
516 CONFIRM_EVENTS_ARE_TOUCH_AND_EQUAL(captured_events[0], &touch2_release);
517 }
518
519 // Test the case when there are multiple fingers on the screen and the
520 // second finger is released. This should be rewritten as a move to the
521 // location of the first finger.
TEST_F(TouchExplorationTest,SecondFingerLifted)522 TEST_F(TouchExplorationTest, SecondFingerLifted) {
523 SwitchTouchExplorationMode(true);
524 gfx::Point touch1_location(0, 11);
525 generator_->set_current_location(touch1_location);
526 generator_->PressTouchId(1);
527 generator_->PressTouchId(2);
528 gfx::Point touch2_location(10, 11);
529 generator_->MoveTouchId(touch2_location, 2);
530 generator_->PressTouchId(3);
531 gfx::Point touch3_location(20, 21);
532 generator_->MoveTouchId(touch3_location, 3);
533 ClearCapturedEvents();
534
535 // Release of finger 2 should be rewritten as a move to the location
536 // of the first finger.
537 generator_->ReleaseTouchId(2);
538 const ScopedVector<ui::LocatedEvent>& captured_events = GetCapturedEvents();
539 ASSERT_EQ(1u, captured_events.size());
540 EXPECT_EQ(ui::ET_TOUCH_MOVED, captured_events[0]->type());
541 EXPECT_EQ(2, static_cast<ui::TouchEvent*>(captured_events[0])->touch_id());
542 EXPECT_EQ(touch1_location, captured_events[0]->location());
543 ClearCapturedEvents();
544
545 // Move of finger 1 should be rewritten as a move of finger 2.
546 gfx::Point touch1_new_location(0, 41);
547 generator_->MoveTouchId(touch1_new_location, 1);
548 ASSERT_EQ(1u, captured_events.size());
549 EXPECT_EQ(ui::ET_TOUCH_MOVED, captured_events[0]->type());
550 EXPECT_EQ(2, static_cast<ui::TouchEvent*>(captured_events[0])->touch_id());
551 EXPECT_EQ(touch1_new_location, captured_events[0]->location());
552 ClearCapturedEvents();
553
554 // Release of finger 1 should be rewritten as release of finger 2.
555 gfx::Point touch1_final_location(0, 41);
556 ui::TouchEvent touch1_release(
557 ui::ET_TOUCH_RELEASED,
558 touch1_final_location,
559 1,
560 Now());
561 generator_->Dispatch(&touch1_release);
562 ASSERT_EQ(1u, captured_events.size());
563 EXPECT_EQ(ui::ET_TOUCH_RELEASED, captured_events[0]->type());
564 EXPECT_EQ(2, static_cast<ui::TouchEvent*>(captured_events[0])->touch_id());
565 EXPECT_EQ(touch1_final_location, captured_events[0]->location());
566 }
567
568 // If an event is received after the double-tap timeout has elapsed, but
569 // before the timer has fired, a mouse move should still be generated.
TEST_F(TouchExplorationTest,TimerFiresLateDuringTouchExploration)570 TEST_F(TouchExplorationTest, TimerFiresLateDuringTouchExploration) {
571 SwitchTouchExplorationMode(true);
572
573 // Send a press, then add another finger after the double-tap timeout.
574 generator_->PressTouchId(1);
575 simulated_clock_->Advance(base::TimeDelta::FromMilliseconds(1000));
576 generator_->PressTouchId(2);
577 std::vector<ui::LocatedEvent*> events =
578 GetCapturedEventsOfType(ui::ET_MOUSE_MOVED);
579 ASSERT_EQ(1U, events.size());
580 EXPECT_TRUE(events[0]->flags() & ui::EF_IS_SYNTHESIZED);
581 EXPECT_TRUE(events[0]->flags() & ui::EF_TOUCH_ACCESSIBILITY);
582
583 generator_->ReleaseTouchId(2);
584 generator_->ReleaseTouchId(1);
585 EXPECT_TRUE(IsInNoFingersDownState());
586 }
587
588 // If a new tap is received after the double-tap timeout has elapsed from
589 // a previous tap, but before the timer has fired, a mouse move should
590 // still be generated from the old tap.
TEST_F(TouchExplorationTest,TimerFiresLateAfterTap)591 TEST_F(TouchExplorationTest, TimerFiresLateAfterTap) {
592 SwitchTouchExplorationMode(true);
593
594 // Send a tap at location1.
595 gfx::Point location0(11, 12);
596 generator_->set_current_location(location0);
597 generator_->PressTouch();
598 generator_->ReleaseTouch();
599
600 // Send a tap at location2, after the double-tap timeout, but before the
601 // timer fires.
602 gfx::Point location1(33, 34);
603 generator_->set_current_location(location1);
604 simulated_clock_->Advance(base::TimeDelta::FromMilliseconds(301));
605 generator_->PressTouch();
606 generator_->ReleaseTouch();
607 AdvanceSimulatedTimePastTapDelay();
608
609 std::vector<ui::LocatedEvent*> events =
610 GetCapturedEventsOfType(ui::ET_MOUSE_MOVED);
611 ASSERT_EQ(2U, events.size());
612 EXPECT_EQ(location0, events[0]->location());
613 EXPECT_TRUE(events[0]->flags() & ui::EF_IS_SYNTHESIZED);
614 EXPECT_TRUE(events[0]->flags() & ui::EF_TOUCH_ACCESSIBILITY);
615 EXPECT_EQ(location1, events[1]->location());
616 EXPECT_TRUE(events[1]->flags() & ui::EF_IS_SYNTHESIZED);
617 EXPECT_TRUE(events[1]->flags() & ui::EF_TOUCH_ACCESSIBILITY);
618 EXPECT_TRUE(IsInNoFingersDownState());
619 }
620
621 // Double-tapping should send a touch press and release through to the location
622 // of the last successful touch exploration.
TEST_F(TouchExplorationTest,DoubleTap)623 TEST_F(TouchExplorationTest, DoubleTap) {
624 SwitchTouchExplorationMode(true);
625
626 // Tap at one location, and get a mouse move event.
627 gfx::Point tap_location(11, 12);
628 generator_->set_current_location(tap_location);
629 generator_->PressTouch();
630 generator_->ReleaseTouch();
631 AdvanceSimulatedTimePastTapDelay();
632
633 std::vector<ui::LocatedEvent*> events =
634 GetCapturedEventsOfType(ui::ET_MOUSE_MOVED);
635 ASSERT_EQ(1U, events.size());
636
637 EXPECT_EQ(tap_location, events[0]->location());
638 EXPECT_TRUE(events[0]->flags() & ui::EF_IS_SYNTHESIZED);
639 EXPECT_TRUE(events[0]->flags() & ui::EF_TOUCH_ACCESSIBILITY);
640 ClearCapturedEvents();
641
642 // Now double-tap at a different location. This should result in
643 // a single touch press and release at the location of the tap,
644 // not at the location of the double-tap.
645 gfx::Point double_tap_location(33, 34);
646 generator_->set_current_location(double_tap_location);
647 generator_->PressTouch();
648 generator_->ReleaseTouch();
649 generator_->PressTouch();
650 generator_->ReleaseTouch();
651
652 const ScopedVector<ui::LocatedEvent>& captured_events = GetCapturedEvents();
653 ASSERT_EQ(2U, captured_events.size());
654 EXPECT_EQ(ui::ET_TOUCH_PRESSED, captured_events[0]->type());
655 EXPECT_EQ(tap_location, captured_events[0]->location());
656 EXPECT_EQ(ui::ET_TOUCH_RELEASED, captured_events[1]->type());
657 EXPECT_EQ(tap_location, captured_events[1]->location());
658 EXPECT_TRUE(IsInNoFingersDownState());
659 }
660
661
662 // Double-tapping where the user holds their finger down for the second time
663 // for a longer press should send a touch press and released (right click)
664 // to the location of the last successful touch exploration.
TEST_F(TouchExplorationTest,DoubleTapLongPress)665 TEST_F(TouchExplorationTest, DoubleTapLongPress) {
666 SwitchTouchExplorationMode(true);
667
668 // Tap at one location, and get a mouse move event.
669 gfx::Point tap_location(11, 12);
670 generator_->set_current_location(tap_location);
671 generator_->PressTouch();
672 generator_->ReleaseTouch();
673 AdvanceSimulatedTimePastTapDelay();
674
675 std::vector<ui::LocatedEvent*> events =
676 GetCapturedEventsOfType(ui::ET_MOUSE_MOVED);
677 ASSERT_EQ(1U, events.size());
678
679 EXPECT_EQ(tap_location, events[0]->location());
680 EXPECT_TRUE(events[0]->flags() & ui::EF_IS_SYNTHESIZED);
681 EXPECT_TRUE(events[0]->flags() & ui::EF_TOUCH_ACCESSIBILITY);
682 ClearCapturedEvents();
683
684 // Now double-tap and hold at a different location.
685 // This should result in a single touch long press and release
686 // at the location of the tap, not at the location of the double-tap.
687 // There should be a time delay between the touch press and release.
688 gfx::Point first_tap_location(33, 34);
689 generator_->set_current_location(first_tap_location);
690 generator_->PressTouch();
691 generator_->ReleaseTouch();
692 gfx::Point second_tap_location(23, 24);
693 generator_->set_current_location(second_tap_location);
694 generator_->PressTouch();
695 simulated_clock_->Advance(gesture_detector_config_.longpress_timeout);
696 generator_->ReleaseTouch();
697
698 const ScopedVector<ui::LocatedEvent>& captured_events = GetCapturedEvents();
699 ASSERT_EQ(2U, captured_events.size());
700 EXPECT_EQ(ui::ET_TOUCH_PRESSED, captured_events[0]->type());
701 EXPECT_EQ(tap_location, captured_events[0]->location());
702 base::TimeDelta pressed_time = captured_events[0]->time_stamp();
703 EXPECT_EQ(ui::ET_TOUCH_RELEASED, captured_events[1]->type());
704 EXPECT_EQ(tap_location, captured_events[1]->location());
705 base::TimeDelta released_time = captured_events[1]->time_stamp();
706 EXPECT_EQ(gesture_detector_config_.longpress_timeout,
707 released_time - pressed_time);
708 }
709
710 // Double-tapping without coming from touch exploration (no previous touch
711 // exploration event) should not generate any events.
TEST_F(TouchExplorationTest,DoubleTapNoTouchExplore)712 TEST_F(TouchExplorationTest, DoubleTapNoTouchExplore) {
713 SwitchTouchExplorationMode(true);
714
715 // Double-tap without any previous touch.
716 // Touch exploration mode has not been entered, so there is no previous
717 // touch exploration event. The double-tap should be discarded, and no events
718 // should be generated at all.
719 gfx::Point double_tap_location(33, 34);
720 generator_->set_current_location(double_tap_location);
721 generator_->PressTouch();
722 generator_->ReleaseTouch();
723 generator_->PressTouch();
724 generator_->ReleaseTouch();
725
726 const ScopedVector<ui::LocatedEvent>& captured_events = GetCapturedEvents();
727 ASSERT_EQ(0U, captured_events.size());
728 }
729
730 // Tapping and releasing with a second finger when in touch exploration mode
731 // should send a touch press and released to the location of the last
732 // successful touch exploration and return to touch explore.
TEST_F(TouchExplorationTest,SplitTap)733 TEST_F(TouchExplorationTest, SplitTap) {
734 SwitchTouchExplorationMode(true);
735 gfx::Point initial_touch_location(11, 12);
736 gfx::Point second_touch_location(33, 34);
737
738 // Tap and hold at one location, and get a mouse move event in touch explore.
739 EnterTouchExplorationModeAtLocation(initial_touch_location);
740 std::vector<ui::LocatedEvent*> events =
741 GetCapturedEventsOfType(ui::ET_MOUSE_MOVED);
742 ASSERT_EQ(1U, events.size());
743
744 EXPECT_EQ(initial_touch_location, events[0]->location());
745 EXPECT_TRUE(events[0]->flags() & ui::EF_IS_SYNTHESIZED);
746 EXPECT_TRUE(events[0]->flags() & ui::EF_TOUCH_ACCESSIBILITY);
747 ClearCapturedEvents();
748
749 // Now tap and release at a different location. This should result in a
750 // single touch and release at the location of the first (held) tap,
751 // not at the location of the second tap and release.
752 // After the release, there is still a finger in touch explore mode.
753 ui::TouchEvent split_tap_press(
754 ui::ET_TOUCH_PRESSED, second_touch_location, 1, Now());
755 generator_->Dispatch(&split_tap_press);
756 ui::TouchEvent split_tap_release(
757 ui::ET_TOUCH_RELEASED, second_touch_location, 1, Now());
758 generator_->Dispatch(&split_tap_release);
759 EXPECT_FALSE(IsInNoFingersDownState());
760
761 const ScopedVector<ui::LocatedEvent>& captured_events = GetCapturedEvents();
762 ASSERT_EQ(2U, captured_events.size());
763 EXPECT_EQ(ui::ET_TOUCH_PRESSED, captured_events[0]->type());
764 EXPECT_EQ(initial_touch_location, captured_events[0]->location());
765 EXPECT_EQ(ui::ET_TOUCH_RELEASED, captured_events[1]->type());
766 EXPECT_EQ(initial_touch_location, captured_events[1]->location());
767 }
768
769 // If split tap is started but the touch explore finger is released first,
770 // there should still be a touch press and release sent to the location of
771 // the last successful touch exploration.
772 // Both fingers should be released after the click goes through.
TEST_F(TouchExplorationTest,SplitTapRelease)773 TEST_F(TouchExplorationTest, SplitTapRelease) {
774 SwitchTouchExplorationMode(true);
775
776 gfx::Point initial_touch_location(11, 12);
777 gfx::Point second_touch_location(33, 34);
778
779 // Tap and hold at one location, and get a mouse move event in touch explore.
780 EnterTouchExplorationModeAtLocation(initial_touch_location);
781
782 std::vector<ui::LocatedEvent*> events =
783 GetCapturedEventsOfType(ui::ET_MOUSE_MOVED);
784 ASSERT_EQ(1U, events.size());
785
786 ClearCapturedEvents();
787
788 // Now tap at a different location. Release at the first location,
789 // then release at the second. This should result in a
790 // single touch and release at the location of the first (held) tap,
791 // not at the location of the second tap and release.
792 ui::TouchEvent split_tap_press(
793 ui::ET_TOUCH_PRESSED, second_touch_location, 1, Now());
794 generator_->Dispatch(&split_tap_press);
795 ui::TouchEvent touch_explore_release(
796 ui::ET_TOUCH_RELEASED, initial_touch_location, 0, Now());
797 generator_->Dispatch(&touch_explore_release);
798 ui::TouchEvent split_tap_release(
799 ui::ET_TOUCH_RELEASED, second_touch_location , 1, Now());
800 generator_->Dispatch(&split_tap_release);
801 EXPECT_TRUE(IsInNoFingersDownState());
802
803 const ScopedVector<ui::LocatedEvent>& captured_events = GetCapturedEvents();
804 ASSERT_EQ(2U, captured_events.size());
805 EXPECT_EQ(ui::ET_TOUCH_PRESSED, captured_events[0]->type());
806 EXPECT_EQ(initial_touch_location, captured_events[0]->location());
807 EXPECT_EQ(ui::ET_TOUCH_RELEASED, captured_events[1]->type());
808 EXPECT_EQ(initial_touch_location, captured_events[1]->location());
809 }
810
811 // When in touch exploration mode, making a long press with a second finger
812 // should send a touch press and released to the location of the last
813 // successful touch exploration. There should be a delay between the
814 // touch and release events (right click).
TEST_F(TouchExplorationTest,SplitTapLongPress)815 TEST_F(TouchExplorationTest, SplitTapLongPress) {
816 SwitchTouchExplorationMode(true);
817 gfx::Point initial_touch_location(11, 12);
818 gfx::Point second_touch_location(33, 34);
819
820 // Tap and hold at one location, and get a mouse move event in touch explore.
821 EnterTouchExplorationModeAtLocation(initial_touch_location);
822 std::vector<ui::LocatedEvent*> events =
823 GetCapturedEventsOfType(ui::ET_MOUSE_MOVED);
824 ASSERT_EQ(1U, events.size());
825
826 ClearCapturedEvents();
827
828 // Now tap and release at a different location. This should result in a
829 // single touch and release at the location of the first (held) tap,
830 // not at the location of the second tap and release.
831 // After the release, there is still a finger in touch explore mode.
832 ui::TouchEvent split_tap_press(
833 ui::ET_TOUCH_PRESSED, second_touch_location, 1, Now());
834 generator_->Dispatch(&split_tap_press);
835 simulated_clock_->Advance(gesture_detector_config_.longpress_timeout);
836 ui::TouchEvent split_tap_release(
837 ui::ET_TOUCH_RELEASED, second_touch_location, 1, Now());
838 generator_->Dispatch(&split_tap_release);
839 EXPECT_FALSE(IsInNoFingersDownState());
840
841 const ScopedVector<ui::LocatedEvent>& captured_events = GetCapturedEvents();
842 ASSERT_EQ(2U, captured_events.size());
843 EXPECT_EQ(ui::ET_TOUCH_PRESSED, captured_events[0]->type());
844 EXPECT_EQ(initial_touch_location, captured_events[0]->location());
845 base::TimeDelta pressed_time = captured_events[0]->time_stamp();
846 EXPECT_EQ(ui::ET_TOUCH_RELEASED, captured_events[1]->type());
847 EXPECT_EQ(initial_touch_location, captured_events[1]->location());
848 base::TimeDelta released_time = captured_events[1]->time_stamp();
849 EXPECT_EQ(gesture_detector_config_.longpress_timeout,
850 released_time - pressed_time);
851 }
852
853 // If split tap is started but the touch explore finger is released first,
854 // there should still be a touch press and release sent to the location of
855 // the last successful touch exploration. If the remaining finger is held
856 // as a longpress, there should be a delay between the sent touch and release
857 // events (right click).All fingers should be released after the click
858 // goes through.
TEST_F(TouchExplorationTest,SplitTapReleaseLongPress)859 TEST_F(TouchExplorationTest, SplitTapReleaseLongPress) {
860 SwitchTouchExplorationMode(true);
861 gfx::Point initial_touch_location(11, 12);
862 gfx::Point second_touch_location(33, 34);
863
864 // Tap and hold at one location, and get a mouse move event in touch explore.
865 EnterTouchExplorationModeAtLocation(initial_touch_location);
866 std::vector<ui::LocatedEvent*> events =
867 GetCapturedEventsOfType(ui::ET_MOUSE_MOVED);
868 ASSERT_EQ(1U, events.size());
869 ClearCapturedEvents();
870
871 // Now tap at a different location. Release at the first location,
872 // then release at the second. This should result in a
873 // single touch and release at the location of the first (held) tap,
874 // not at the location of the second tap and release.
875 // After the release, TouchToMouseMode should still be on.
876 ui::TouchEvent split_tap_press(
877 ui::ET_TOUCH_PRESSED, second_touch_location, 1, Now());
878 generator_->Dispatch(&split_tap_press);
879 ui::TouchEvent touch_explore_release(
880 ui::ET_TOUCH_RELEASED, initial_touch_location, 0, Now());
881 generator_->Dispatch(&touch_explore_release);
882 simulated_clock_->Advance(gesture_detector_config_.longpress_timeout);
883 ui::TouchEvent split_tap_release(
884 ui::ET_TOUCH_RELEASED, second_touch_location, 1, Now());
885 generator_->Dispatch(&split_tap_release);
886 EXPECT_TRUE(IsInTouchToMouseMode());
887
888 const ScopedVector<ui::LocatedEvent>& captured_events = GetCapturedEvents();
889 ASSERT_EQ(2U, captured_events.size());
890 EXPECT_EQ(ui::ET_TOUCH_PRESSED, captured_events[0]->type());
891 EXPECT_EQ(initial_touch_location, captured_events[0]->location());
892 base::TimeDelta pressed_time = captured_events[0]->time_stamp();
893 EXPECT_EQ(ui::ET_TOUCH_RELEASED, captured_events[1]->type());
894 EXPECT_EQ(initial_touch_location, captured_events[1]->location());
895 base::TimeDelta released_time = captured_events[1]->time_stamp();
896 EXPECT_EQ(gesture_detector_config_.longpress_timeout,
897 released_time - pressed_time);
898 }
899
TEST_F(TouchExplorationTest,SplitTapLongPressMultiFinger)900 TEST_F(TouchExplorationTest, SplitTapLongPressMultiFinger) {
901 SwitchTouchExplorationMode(true);
902 gfx::Point initial_touch_location(11, 12);
903 gfx::Point second_touch_location(33, 34);
904 gfx::Point third_touch_location(16, 17);
905
906 // Tap and hold at one location, and get a mouse move event in touch explore.
907 EnterTouchExplorationModeAtLocation(initial_touch_location);
908
909 std::vector<ui::LocatedEvent*> events =
910 GetCapturedEventsOfType(ui::ET_MOUSE_MOVED);
911 ASSERT_EQ(1U, events.size());
912
913 EXPECT_EQ(initial_touch_location, events[0]->location());
914 EXPECT_TRUE(events[0]->flags() & ui::EF_IS_SYNTHESIZED);
915 EXPECT_TRUE(events[0]->flags() & ui::EF_TOUCH_ACCESSIBILITY);
916 ClearCapturedEvents();
917
918 // Now tap at a different location and hold for long press.
919 ui::TouchEvent split_tap_press(
920 ui::ET_TOUCH_PRESSED, second_touch_location, 1, Now());
921 generator_->Dispatch(&split_tap_press);
922 simulated_clock_->Advance(gesture_detector_config_.longpress_timeout);
923
924 // Placing a third finger on the screen should be discarded and not affect
925 // the events passed through.
926 ui::TouchEvent third_press(
927 ui::ET_TOUCH_PRESSED, third_touch_location, 2, Now());
928 generator_->Dispatch(&third_press);
929
930 // When all three fingers are released, there should be only two captured
931 // events: touch press and touch release. All fingers should then be up.
932 ui::TouchEvent touch_explore_release(
933 ui::ET_TOUCH_RELEASED, initial_touch_location, 0, Now());
934 generator_->Dispatch(&touch_explore_release);
935 ui::TouchEvent split_tap_release(
936 ui::ET_TOUCH_RELEASED, second_touch_location, 1, Now());
937 generator_->Dispatch(&split_tap_release);
938 ui::TouchEvent third_tap_release(
939 ui::ET_TOUCH_RELEASED, third_touch_location, 2, Now());
940 generator_->Dispatch(&third_tap_release);
941
942 const ScopedVector<ui::LocatedEvent>& captured_events = GetCapturedEvents();
943 ASSERT_EQ(2U, captured_events.size());
944 EXPECT_EQ(ui::ET_TOUCH_PRESSED, captured_events[0]->type());
945 EXPECT_EQ(initial_touch_location, captured_events[0]->location());
946 base::TimeDelta pressed_time = captured_events[0]->time_stamp();
947 EXPECT_EQ(ui::ET_TOUCH_RELEASED, captured_events[1]->type());
948 EXPECT_EQ(initial_touch_location, captured_events[1]->location());
949 base::TimeDelta released_time = captured_events[1]->time_stamp();
950 EXPECT_EQ(gesture_detector_config_.longpress_timeout,
951 released_time - pressed_time);
952 EXPECT_TRUE(IsInNoFingersDownState());
953 }
954
955 } // namespace ui
956