Do not double-unref send rights when using POLICY_SUBSTITUE_PORT.
[chromium-blink-merge.git] / ui / chromeos / touch_exploration_controller_unittest.cc
blob8366194152c982477849cab89fb0c984175bad40
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.
5 #include "ui/chromeos/touch_exploration_controller.h"
7 #include "base/time/time.h"
8 #include "ui/aura/client/cursor_client.h"
9 #include "ui/aura/test/aura_test_base.h"
10 #include "ui/aura/test/event_generator.h"
11 #include "ui/aura/test/test_cursor_client.h"
12 #include "ui/aura/window.h"
13 #include "ui/events/event.h"
14 #include "ui/events/event_utils.h"
15 #include "ui/gfx/geometry/point.h"
16 #include "ui/gl/gl_implementation.h"
17 #include "ui/gl/gl_surface.h"
19 namespace ui {
21 namespace {
22 // Records all mouse and touch events.
23 class EventCapturer : public ui::EventHandler {
24 public:
25 EventCapturer() {}
26 virtual ~EventCapturer() {}
28 void Reset() {
29 events_.clear();
32 virtual void OnEvent(ui::Event* event) OVERRIDE {
33 if (event->IsMouseEvent()) {
34 events_.push_back(
35 new ui::MouseEvent(static_cast<ui::MouseEvent&>(*event)));
36 } else if (event->IsTouchEvent()) {
37 events_.push_back(
38 new ui::TouchEvent(static_cast<ui::TouchEvent&>(*event)));
39 } else {
40 return;
42 // Stop event propagation so we don't click on random stuff that
43 // might break test assumptions.
44 event->StopPropagation();
45 // If there is a possibility that we're in an infinite loop, we should
46 // exit early with a sensible error rather than letting the test time out.
47 ASSERT_LT(events_.size(), 100u);
49 const ScopedVector<ui::LocatedEvent>& captured_events() const {
50 return events_;
53 private:
54 ScopedVector<ui::LocatedEvent> events_;
56 DISALLOW_COPY_AND_ASSIGN(EventCapturer);
59 } // namespace
61 class TouchExplorationTest : public aura::test::AuraTestBase {
62 public:
63 TouchExplorationTest() {}
64 virtual ~TouchExplorationTest() {}
66 virtual void SetUp() OVERRIDE {
67 if (gfx::GetGLImplementation() == gfx::kGLImplementationNone)
68 gfx::GLSurface::InitializeOneOffForTests();
69 aura::test::AuraTestBase::SetUp();
70 cursor_client_.reset(new aura::test::TestCursorClient(root_window()));
71 root_window()->AddPreTargetHandler(&event_capturer_);
74 virtual void TearDown() OVERRIDE {
75 root_window()->RemovePreTargetHandler(&event_capturer_);
76 SwitchTouchExplorationMode(false);
77 cursor_client_.reset();
78 aura::test::AuraTestBase::TearDown();
81 const ScopedVector<ui::LocatedEvent>& GetCapturedEvents() {
82 return event_capturer_.captured_events();
85 void ClearCapturedEvents() {
86 event_capturer_.Reset();
89 protected:
90 aura::client::CursorClient* cursor_client() { return cursor_client_.get(); }
92 void SwitchTouchExplorationMode(bool on) {
93 if (!on && touch_exploration_controller_.get())
94 touch_exploration_controller_.reset();
95 else if (on && !touch_exploration_controller_.get())
96 touch_exploration_controller_.reset(
97 new ui::TouchExplorationController(root_window()));
100 bool IsInTouchToMouseMode() {
101 aura::client::CursorClient* cursor_client =
102 aura::client::GetCursorClient(root_window());
103 return cursor_client &&
104 cursor_client->IsMouseEventsEnabled() &&
105 !cursor_client->IsCursorVisible();
108 private:
109 EventCapturer event_capturer_;
110 scoped_ptr<ui::TouchExplorationController> touch_exploration_controller_;
111 scoped_ptr<aura::test::TestCursorClient> cursor_client_;
113 DISALLOW_COPY_AND_ASSIGN(TouchExplorationTest);
116 // Executes a number of assertions to confirm that |e1| and |e2| are touch
117 // events and are equal to each other.
118 void ConfirmEventsAreTouchAndEqual(ui::Event* e1, ui::Event* e2) {
119 ASSERT_TRUE(e1->IsTouchEvent());
120 ASSERT_TRUE(e2->IsTouchEvent());
121 ui::TouchEvent* touch_event1 = static_cast<ui::TouchEvent*>(e1);
122 ui::TouchEvent* touch_event2 = static_cast<ui::TouchEvent*>(e2);
123 EXPECT_EQ(touch_event1->type(), touch_event2->type());
124 EXPECT_EQ(touch_event1->location(), touch_event2->location());
125 EXPECT_EQ(touch_event1->touch_id(), touch_event2->touch_id());
126 EXPECT_EQ(touch_event1->flags(), touch_event2->flags());
127 EXPECT_EQ(touch_event1->time_stamp(), touch_event2->time_stamp());
130 // Executes a number of assertions to confirm that |e1| and |e2| are mouse
131 // events and are equal to each other.
132 void ConfirmEventsAreMouseAndEqual(ui::Event* e1, ui::Event* e2) {
133 ASSERT_TRUE(e1->IsMouseEvent());
134 ASSERT_TRUE(e2->IsMouseEvent());
135 ui::MouseEvent* mouse_event1 = static_cast<ui::MouseEvent*>(e1);
136 ui::MouseEvent* mouse_event2 = static_cast<ui::MouseEvent*>(e2);
137 EXPECT_EQ(mouse_event1->type(), mouse_event2->type());
138 EXPECT_EQ(mouse_event1->location(), mouse_event2->location());
139 EXPECT_EQ(mouse_event1->root_location(), mouse_event2->root_location());
140 EXPECT_EQ(mouse_event1->flags(), mouse_event2->flags());
143 #define CONFIRM_EVENTS_ARE_TOUCH_AND_EQUAL(e1, e2) \
144 ASSERT_NO_FATAL_FAILURE(ConfirmEventsAreTouchAndEqual(e1, e2))
146 #define CONFIRM_EVENTS_ARE_MOUSE_AND_EQUAL(e1, e2) \
147 ASSERT_NO_FATAL_FAILURE(ConfirmEventsAreMouseAndEqual(e1, e2))
149 // TODO(mfomitchev): Need to investigate why we don't get mouse enter/exit
150 // events when running these tests as part of ui_unittests. We do get them when
151 // the tests are run as part of ash unit tests.
153 // Simple test to confirm one-finger touches are transformed into mouse moves.
154 TEST_F(TouchExplorationTest, OneFingerTouch) {
155 SwitchTouchExplorationMode(true);
156 cursor_client()->ShowCursor();
157 cursor_client()->DisableMouseEvents();
158 aura::test::EventGenerator generator(root_window());
159 gfx::Point location_start = generator.current_location();
160 gfx::Point location_end(11, 12);
161 generator.PressTouch();
162 EXPECT_TRUE(IsInTouchToMouseMode());
163 generator.MoveTouch(location_end);
164 // Confirm the actual mouse moves are unaffected.
165 ui::MouseEvent mouse_move(ui::ET_MOUSE_MOVED,
166 gfx::Point(13, 14),
167 gfx::Point(13, 14),
170 generator.Dispatch(&mouse_move);
171 generator.ReleaseTouch();
173 const ScopedVector<ui::LocatedEvent>& captured_events = GetCapturedEvents();
174 ScopedVector<ui::LocatedEvent>::const_iterator it;
175 // TODO(mfomitchev): mouse enter/exit events
176 int num_mouse_moves = 0;
177 for (it = captured_events.begin(); it != captured_events.end(); ++it) {
178 int type = (*it)->type();
179 // Ignore enter and exit mouse events synthesized when the mouse cursor is
180 // shown or hidden.
181 if (type == ui::ET_MOUSE_ENTERED || type == ui::ET_MOUSE_EXITED)
182 continue;
183 EXPECT_EQ(ui::ET_MOUSE_MOVED, (*it)->type());
184 if (num_mouse_moves == 0)
185 EXPECT_EQ(location_start, (*it)->location());
186 if (num_mouse_moves == 1 || num_mouse_moves == 3)
187 EXPECT_EQ(location_end, (*it)->location());
188 if (num_mouse_moves == 2)
189 CONFIRM_EVENTS_ARE_MOUSE_AND_EQUAL(*it, &mouse_move);
190 if (num_mouse_moves != 2) {
191 EXPECT_TRUE((*it)->flags() & ui::EF_IS_SYNTHESIZED);
192 EXPECT_TRUE((*it)->flags() & ui::EF_TOUCH_ACCESSIBILITY);
194 num_mouse_moves++;
196 EXPECT_EQ(4, num_mouse_moves);
199 // Turn the touch exploration mode on in the middle of the touch gesture.
200 // Confirm that events from the finger which was touching when the mode was
201 // turned on don't get rewritten.
202 TEST_F(TouchExplorationTest, TurnOnMidTouch) {
203 SwitchTouchExplorationMode(false);
204 cursor_client()->ShowCursor();
205 cursor_client()->DisableMouseEvents();
206 aura::test::EventGenerator generator(root_window());
207 generator.PressTouchId(1);
208 EXPECT_TRUE(cursor_client()->IsCursorVisible());
209 EXPECT_FALSE(cursor_client()->IsMouseEventsEnabled());
210 ClearCapturedEvents();
212 // Enable touch exploration mode while the first finger is touching the
213 // screen. Ensure that subsequent events from that first finger are not
214 // affected by the touch exploration mode, while the touch events from another
215 // finger get rewritten.
216 SwitchTouchExplorationMode(true);
217 ui::TouchEvent touch_move(ui::ET_TOUCH_MOVED,
218 gfx::Point(11, 12),
220 ui::EventTimeForNow());
221 generator.Dispatch(&touch_move);
222 EXPECT_TRUE(cursor_client()->IsCursorVisible());
223 EXPECT_FALSE(cursor_client()->IsMouseEventsEnabled());
224 const ScopedVector<ui::LocatedEvent>& captured_events = GetCapturedEvents();
225 ASSERT_EQ(1u, captured_events.size());
226 CONFIRM_EVENTS_ARE_TOUCH_AND_EQUAL(captured_events[0], &touch_move);
227 ClearCapturedEvents();
229 // The press from the second finger should get rewritten.
230 generator.PressTouchId(2);
231 EXPECT_TRUE(IsInTouchToMouseMode());
232 // TODO(mfomitchev): mouse enter/exit events
233 ScopedVector<ui::LocatedEvent>::const_iterator it;
234 for (it = captured_events.begin(); it != captured_events.end(); ++it) {
235 if ((*it)->type() == ui::ET_MOUSE_MOVED)
236 break;
238 EXPECT_NE(captured_events.end(), it);
239 ClearCapturedEvents();
241 // The release of the first finger shouldn't be affected.
242 ui::TouchEvent touch_release(ui::ET_TOUCH_RELEASED,
243 gfx::Point(11, 12),
245 ui::EventTimeForNow());
246 generator.Dispatch(&touch_release);
247 ASSERT_EQ(1u, captured_events.size());
248 CONFIRM_EVENTS_ARE_TOUCH_AND_EQUAL(captured_events[0], &touch_release);
249 ClearCapturedEvents();
251 // The move and release from the second finger should get rewritten.
252 generator.MoveTouchId(gfx::Point(13, 14), 2);
253 generator.ReleaseTouchId(2);
254 ASSERT_EQ(2u, captured_events.size());
255 EXPECT_EQ(ui::ET_MOUSE_MOVED, captured_events[0]->type());
256 EXPECT_EQ(ui::ET_MOUSE_MOVED, captured_events[1]->type());
259 TEST_F(TouchExplorationTest, TwoFingerTouch) {
260 SwitchTouchExplorationMode(true);
261 aura::test::EventGenerator generator(root_window());
262 generator.PressTouchId(1);
263 ClearCapturedEvents();
265 // Confirm events from the second finger go through as is.
266 cursor_client()->ShowCursor();
267 cursor_client()->DisableMouseEvents();
268 ui::TouchEvent touch_press(ui::ET_TOUCH_PRESSED,
269 gfx::Point(10, 11),
271 ui::EventTimeForNow());
272 generator.Dispatch(&touch_press);
273 EXPECT_TRUE(cursor_client()->IsCursorVisible());
274 EXPECT_FALSE(cursor_client()->IsMouseEventsEnabled());
275 const ScopedVector<ui::LocatedEvent>& captured_events = GetCapturedEvents();
276 // TODO(mfomitchev): mouse enter/exit events
277 // There will be a ET_MOUSE_EXITED event synthesized when the mouse cursor is
278 // hidden - ignore it.
279 ScopedVector<ui::LocatedEvent>::const_iterator it;
280 for (it = captured_events.begin(); it != captured_events.end(); ++it) {
281 if ((*it)->type() == ui::ET_TOUCH_PRESSED) {
282 CONFIRM_EVENTS_ARE_TOUCH_AND_EQUAL(*it, &touch_press);
283 break;
286 EXPECT_NE(captured_events.end(), it);
287 ClearCapturedEvents();
288 ui::TouchEvent touch_move(ui::ET_TOUCH_MOVED,
289 gfx::Point(20, 21),
291 ui::EventTimeForNow());
292 generator.Dispatch(&touch_move);
293 ASSERT_EQ(1u, captured_events.size());
294 CONFIRM_EVENTS_ARE_TOUCH_AND_EQUAL(captured_events[0], &touch_move);
295 ClearCapturedEvents();
297 // Confirm mouse moves go through unaffected.
298 ui::MouseEvent mouse_move(ui::ET_MOUSE_MOVED,
299 gfx::Point(13, 14),
300 gfx::Point(13, 14),
303 generator.Dispatch(&mouse_move);
304 // TODO(mfomitchev): mouse enter/exit events
305 // Ignore synthesized ET_MOUSE_ENTERED/ET_MOUSE_EXITED
306 for (it = captured_events.begin(); it != captured_events.end(); ++it) {
307 if ((*it)->type() == ui::ET_MOUSE_MOVED) {
308 CONFIRM_EVENTS_ARE_MOUSE_AND_EQUAL(*it, &mouse_move);
309 break;
312 EXPECT_NE(captured_events.end(), it);
313 ClearCapturedEvents();
315 // Have some other fingers touch/move/release
316 generator.PressTouchId(3);
317 generator.PressTouchId(4);
318 generator.MoveTouchId(gfx::Point(30, 31), 3);
319 generator.ReleaseTouchId(3);
320 generator.ReleaseTouchId(4);
321 ClearCapturedEvents();
323 // Events from the first finger should not go through while the second finger
324 // is touching.
325 gfx::Point touch1_location = gfx::Point(15, 16);
326 generator.MoveTouchId(touch1_location, 1);
327 EXPECT_EQ(0u, GetCapturedEvents().size());
329 EXPECT_TRUE(cursor_client()->IsCursorVisible());
330 EXPECT_FALSE(cursor_client()->IsMouseEventsEnabled());
332 // A release of the second finger should go through, plus there should be a
333 // mouse move at |touch1_location| generated.
334 ui::TouchEvent touch_release(ui::ET_TOUCH_RELEASED,
335 gfx::Point(25, 26),
337 ui::EventTimeForNow());
338 generator.Dispatch(&touch_release);
339 EXPECT_TRUE(IsInTouchToMouseMode());
340 ASSERT_GE(captured_events.size(), 2u);
341 CONFIRM_EVENTS_ARE_TOUCH_AND_EQUAL(captured_events[0], &touch_release);
342 // TODO(mfomitchev): mouse enter/exit events
343 // Ignore synthesized ET_MOUSE_ENTERED/ET_MOUSE_EXITED
344 for (it = captured_events.begin(); it != captured_events.end(); ++it) {
345 if ((*it)->type() == ui::ET_MOUSE_MOVED) {
346 EXPECT_EQ(touch1_location, (*it)->location());
347 break;
350 EXPECT_NE(captured_events.end(), it);
353 TEST_F(TouchExplorationTest, MultiFingerTouch) {
354 SwitchTouchExplorationMode(true);
355 aura::test::EventGenerator generator(root_window());
356 generator.PressTouchId(1);
357 generator.PressTouchId(2);
358 ClearCapturedEvents();
360 // Confirm events from other fingers go through as is.
361 ui::TouchEvent touch3_press(ui::ET_TOUCH_PRESSED,
362 gfx::Point(10, 11),
364 ui::EventTimeForNow());
365 ui::TouchEvent touch3_move1(ui::ET_TOUCH_MOVED,
366 gfx::Point(12, 13),
368 ui::EventTimeForNow());
369 ui::TouchEvent touch4_press(ui::ET_TOUCH_PRESSED,
370 gfx::Point(20, 21),
372 ui::EventTimeForNow());
373 ui::TouchEvent touch3_move2(ui::ET_TOUCH_MOVED,
374 gfx::Point(14, 15),
376 ui::EventTimeForNow());
377 ui::TouchEvent touch4_move(ui::ET_TOUCH_MOVED,
378 gfx::Point(22, 23),
380 ui::EventTimeForNow());
381 ui::TouchEvent touch3_release(ui::ET_TOUCH_RELEASED,
382 gfx::Point(14, 15),
384 ui::EventTimeForNow());
385 ui::TouchEvent touch4_release(ui::ET_TOUCH_RELEASED,
386 gfx::Point(22, 23),
388 ui::EventTimeForNow());
389 generator.Dispatch(&touch3_press);
390 generator.Dispatch(&touch3_move1);
391 generator.Dispatch(&touch4_press);
392 generator.Dispatch(&touch3_move2);
393 generator.Dispatch(&touch4_move);
394 generator.Dispatch(&touch3_release);
395 generator.Dispatch(&touch4_release);
397 const ScopedVector<ui::LocatedEvent>& captured_events = GetCapturedEvents();
398 ASSERT_EQ(7u, captured_events.size());
399 CONFIRM_EVENTS_ARE_TOUCH_AND_EQUAL(captured_events[0], &touch3_press);
400 CONFIRM_EVENTS_ARE_TOUCH_AND_EQUAL(captured_events[1], &touch3_move1);
401 CONFIRM_EVENTS_ARE_TOUCH_AND_EQUAL(captured_events[2], &touch4_press);
402 CONFIRM_EVENTS_ARE_TOUCH_AND_EQUAL(captured_events[3], &touch3_move2);
403 CONFIRM_EVENTS_ARE_TOUCH_AND_EQUAL(captured_events[4], &touch4_move);
404 CONFIRM_EVENTS_ARE_TOUCH_AND_EQUAL(captured_events[5], &touch3_release);
405 CONFIRM_EVENTS_ARE_TOUCH_AND_EQUAL(captured_events[6], &touch4_release);
408 // Test the case when there are multiple fingers on the screen and the first
409 // finger is released. This should be rewritten as a release of the second
410 // finger. Additionally, if the second finger is the only finger left touching,
411 // we should enter a mouse move mode, and a mouse move event should be
412 // dispatched.
413 TEST_F(TouchExplorationTest, FirstFingerLifted) {
414 SwitchTouchExplorationMode(true);
415 aura::test::EventGenerator generator(root_window());
416 generator.PressTouchId(1);
417 generator.PressTouchId(2);
418 gfx::Point touch2_location(10, 11);
419 generator.MoveTouchId(touch2_location, 2);
420 generator.PressTouchId(3);
421 gfx::Point touch3_location(20, 21);
422 generator.MoveTouchId(touch3_location, 3);
423 ClearCapturedEvents();
425 // Release of finger 1 should be rewritten as a release of finger 2.
426 generator.ReleaseTouchId(1);
427 const ScopedVector<ui::LocatedEvent>& captured_events = GetCapturedEvents();
428 ASSERT_EQ(1u, captured_events.size());
429 EXPECT_EQ(ui::ET_TOUCH_RELEASED, captured_events[0]->type());
430 ui::TouchEvent* touch_event =
431 static_cast<ui::TouchEvent*>(captured_events[0]);
432 EXPECT_EQ(2, touch_event->touch_id());
433 EXPECT_EQ(touch2_location, touch_event->location());
434 ClearCapturedEvents();
436 // Release of finger 2 should be rewritten as a release of finger 3, plus
437 // we should enter the mouse move mode and a mouse move event should be
438 // dispatched.
439 cursor_client()->ShowCursor();
440 cursor_client()->DisableMouseEvents();
441 generator.ReleaseTouchId(2);
442 EXPECT_TRUE(IsInTouchToMouseMode());
443 ASSERT_GE(2u, captured_events.size());
444 EXPECT_EQ(ui::ET_TOUCH_RELEASED, captured_events[0]->type());
445 touch_event = static_cast<ui::TouchEvent*>(captured_events[0]);
446 EXPECT_EQ(3, touch_event->touch_id());
447 EXPECT_EQ(touch3_location, touch_event->location());
448 // TODO(mfomitchev): mouse enter/exit events
449 ScopedVector<ui::LocatedEvent>::const_iterator it;
450 for (it = captured_events.begin(); it != captured_events.end(); ++it) {
451 if ((*it)->type() == ui::ET_MOUSE_MOVED) {
452 EXPECT_EQ(touch3_location, (*it)->location());
453 break;
456 EXPECT_NE(captured_events.end(), it);
459 } // namespace ui