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

Side by Side Diff: ui/chromeos/touch_exploration_controller_unittest.cc

Issue 262483003: Implementation of the Touch Exploration Mode - Part I (ui) (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@event_source
Patch Set: Addressing nits. Created 6 years, 7 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 unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright (c) 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/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"
18
19 namespace ui {
20
21 // Records all mouse and touch events.
22 class EventCapturer : public ui::EventHandler {
oshima 2014/05/02 19:53:38 nit: put this class into anonymous anmespace
mfomitchev 2014/05/02 21:27:58 Done.
23 public:
24 EventCapturer() {}
25 virtual ~EventCapturer() {}
26
27 void Reset() {
28 events_.clear();
29 }
30
31 virtual void OnEvent(ui::Event* event) OVERRIDE {
32 ui::LocatedEvent* event_copy;
33 if (event->IsMouseEvent())
34 event_copy = new ui::MouseEvent(static_cast<ui::MouseEvent&>(*event));
oshima 2014/05/02 19:53:38 nit: can you just add it to events_ here?
mfomitchev 2014/05/02 21:27:58 Done.
35 else if (event->IsTouchEvent())
36 event_copy = new ui::TouchEvent(static_cast<ui::TouchEvent&>(*event));
37 else
38 return;
39 events_.push_back(event_copy);
40 // Stop event propagation so we don't click on random stuff that
41 // might break test assumptions.
42 event->StopPropagation();
43 // If there is a possibility that we're in an infinite loop, we should
44 // exit early with a sensible error rather than letting the test time out.
45 ASSERT_LT(events_.size(), 100u);
46 }
47 const ScopedVector<ui::LocatedEvent>& captured_events() const {
48 return events_;
49 }
50
51 private:
52 ScopedVector<ui::LocatedEvent> events_;
53
54 DISALLOW_COPY_AND_ASSIGN(EventCapturer);
55 };
56
57 class TouchExplorationTest : public aura::test::AuraTestBase {
58 public:
59 TouchExplorationTest() {}
60 virtual ~TouchExplorationTest() {}
61
62 virtual void SetUp() OVERRIDE {
63 if (gfx::GetGLImplementation() == gfx::kGLImplementationNone)
64 gfx::GLSurface::InitializeOneOffForTests();
oshima 2014/05/02 19:53:38 Is it safe if there is another test calling the sa
mfomitchev 2014/05/02 21:27:58 I think so - answered in detail separately
65 aura::test::AuraTestBase::SetUp();
66 cursor_client_.reset(new aura::test::TestCursorClient(root_window()));
67 root_window()->AddPreTargetHandler(&event_capturer_);
68 }
69
70 virtual void TearDown() OVERRIDE {
71 root_window()->RemovePreTargetHandler(&event_capturer_);
72 SwitchTouchExplorationMode(false);
73 cursor_client_.reset();
74 aura::test::AuraTestBase::TearDown();
75 }
76
77 const ScopedVector<ui::LocatedEvent>& GetCapturedEvents() {
78 return event_capturer_.captured_events();
79 }
80
81 void ClearCapturedEvents() {
82 event_capturer_.Reset();
83 }
84
85 protected:
86 aura::client::CursorClient* cursor_client() {return cursor_client_.get();}
oshima 2014/05/02 19:53:38 nit: space between { and r, and ; and } you can ju
mfomitchev 2014/05/02 21:27:58 Done.
87
88 void SwitchTouchExplorationMode(bool on) {
89 if (!on && touch_exploration_controller_.get())
90 touch_exploration_controller_.reset();
91 else if (on && !touch_exploration_controller_.get())
92 touch_exploration_controller_.reset(
93 new ui::TouchExplorationController(root_window()));
94 }
95
96 bool IsInTouchToMouseMode() {
oshima 2014/05/02 19:53:38 nit: const
mfomitchev 2014/05/02 21:27:58 root_window() is not const. Do you think it should
oshima 2014/05/02 21:30:28 if that's the case, never mind. It probably should
97 aura::client::CursorClient* cursor_client =
98 aura::client::GetCursorClient(root_window());
99 return cursor_client &&
100 cursor_client->IsMouseEventsEnabled() &&
101 !cursor_client->IsCursorVisible();
102 }
103
104 private:
105 EventCapturer event_capturer_;
106 scoped_ptr<ui::TouchExplorationController> touch_exploration_controller_;
107 scoped_ptr<aura::test::TestCursorClient> cursor_client_;
108
109 DISALLOW_COPY_AND_ASSIGN(TouchExplorationTest);
110 };
111
112 // Executes a number of assertions to confirm that |e1| and |e2| are touch
113 // events and are equal to each other.
114 void ConfirmEventsAreTouchAndEqual(ui::Event* e1, ui::Event* e2) {
115 ASSERT_TRUE(e1->IsTouchEvent());
116 ASSERT_TRUE(e2->IsTouchEvent());
117 ui::TouchEvent* touch_event1 = static_cast<ui::TouchEvent*>(e1);
118 ui::TouchEvent* touch_event2 = static_cast<ui::TouchEvent*>(e2);
119 EXPECT_EQ(touch_event1->type(), touch_event2->type());
120 EXPECT_EQ(touch_event1->location(), touch_event2->location());
121 EXPECT_EQ(touch_event1->touch_id(), touch_event2->touch_id());
122 EXPECT_EQ(touch_event1->flags(), touch_event2->flags());
123 EXPECT_EQ(touch_event1->time_stamp(), touch_event2->time_stamp());
124 }
125
126 // Executes a number of assertions to confirm that |e1| and |e2| are mouse
127 // events and are equal to each other.
128 void ConfirmEventsAreMouseAndEqual(ui::Event* e1, ui::Event* e2) {
129 ASSERT_TRUE(e1->IsMouseEvent());
130 ASSERT_TRUE(e2->IsMouseEvent());
131 ui::MouseEvent* mouse_event1 = static_cast<ui::MouseEvent*>(e1);
132 ui::MouseEvent* mouse_event2 = static_cast<ui::MouseEvent*>(e2);
133 EXPECT_EQ(mouse_event1->type(), mouse_event2->type());
134 EXPECT_EQ(mouse_event1->location(), mouse_event2->location());
135 EXPECT_EQ(mouse_event1->root_location(), mouse_event2->root_location());
136 EXPECT_EQ(mouse_event1->flags(), mouse_event2->flags());
137 }
138
139 #define CONFIRM_EVENTS_ARE_TOUCH_AND_EQUAL(e1, e2) \
140 ASSERT_NO_FATAL_FAILURE(ConfirmEventsAreTouchAndEqual(e1, e2))
141
142 #define CONFIRM_EVENTS_ARE_MOUSE_AND_EQUAL(e1, e2) \
143 ASSERT_NO_FATAL_FAILURE(ConfirmEventsAreMouseAndEqual(e1, e2))
144
145 // TODO(mfomitchev): Need to investigate why we don't get mouse enter/exit
146 // events when running these tests as part of ui_unittests. We do get them when
147 // the tests are run as part of ash unit tests.
148
149 // Simple test to confirm one-finger touches are transformed into mouse moves.
150 TEST_F(TouchExplorationTest, OneFingerTouch) {
151 SwitchTouchExplorationMode(true);
152 cursor_client()->ShowCursor();
153 cursor_client()->DisableMouseEvents();
154 aura::test::EventGenerator generator(root_window());
155 gfx::Point location_start = generator.current_location();
156 gfx::Point location_end(11, 12);
157 generator.PressTouch();
158 EXPECT_TRUE(IsInTouchToMouseMode());
159 generator.MoveTouch(location_end);
160 // Confirm the actual mouse moves are unaffected.
161 ui::MouseEvent mouse_move(ui::ET_MOUSE_MOVED,
162 gfx::Point(13, 14),
163 gfx::Point(13, 14),
164 0,
165 0);
166 generator.Dispatch(&mouse_move);
167 generator.ReleaseTouch();
168
169 const ScopedVector<ui::LocatedEvent>& captured_events = GetCapturedEvents();
170 ScopedVector<ui::LocatedEvent>::const_iterator it;
171 // TODO(mfomitchev): mouse enter/exit events
172 int num_mouse_moves = 0;
173 for (it = captured_events.begin(); it != captured_events.end(); ++it) {
174 int type = (*it)->type();
175 // Ignore enter and exit mouse events synthesized when the mouse cursor is
176 // shown or hidden.
177 if (type == ui::ET_MOUSE_ENTERED || type == ui::ET_MOUSE_EXITED)
178 continue;
179 EXPECT_EQ(ui::ET_MOUSE_MOVED, (*it)->type());
180 if (num_mouse_moves == 0)
181 EXPECT_EQ(location_start, (*it)->location());
182 if (num_mouse_moves == 1 || num_mouse_moves == 3)
183 EXPECT_EQ(location_end, (*it)->location());
184 if (num_mouse_moves == 2)
185 CONFIRM_EVENTS_ARE_MOUSE_AND_EQUAL(*it, &mouse_move);
186 if (num_mouse_moves != 2) {
187 EXPECT_TRUE((*it)->flags() & ui::EF_IS_SYNTHESIZED);
188 EXPECT_TRUE((*it)->flags() & ui::EF_FROM_TOUCH);
189 }
190 num_mouse_moves++;
191 }
192 EXPECT_EQ(4, num_mouse_moves);
193 }
194
195 // Turn the touch exploration mode on in the middle of the touch gesture.
196 // Confirm that events from the finger which was touching when the mode was
197 // turned on don't get rewritten.
198 TEST_F(TouchExplorationTest, TurnOnMidTouch) {
199 SwitchTouchExplorationMode(false);
200 cursor_client()->ShowCursor();
201 cursor_client()->DisableMouseEvents();
202 aura::test::EventGenerator generator(root_window());
203 generator.PressTouchId(1);
204 EXPECT_TRUE(cursor_client()->IsCursorVisible());
205 EXPECT_FALSE(cursor_client()->IsMouseEventsEnabled());
206 ClearCapturedEvents();
207
208 // Enable touch exploration mode while the first finger is touching the
209 // screen. Ensure that subsequent events from that first finger are not
210 // affected by the touch exploration mode, while the touch events from another
211 // finger get rewritten.
212 SwitchTouchExplorationMode(true);
213 ui::TouchEvent touch_move(ui::ET_TOUCH_MOVED,
214 gfx::Point(11, 12),
215 1,
216 ui::EventTimeForNow());
217 generator.Dispatch(&touch_move);
218 EXPECT_TRUE(cursor_client()->IsCursorVisible());
219 EXPECT_FALSE(cursor_client()->IsMouseEventsEnabled());
220 const ScopedVector<ui::LocatedEvent>& captured_events = GetCapturedEvents();
221 ASSERT_EQ(1u, captured_events.size());
222 CONFIRM_EVENTS_ARE_TOUCH_AND_EQUAL(captured_events[0], &touch_move);
223 ClearCapturedEvents();
224
225 // The press from the second finger should get rewritten.
226 generator.PressTouchId(2);
227 EXPECT_TRUE(IsInTouchToMouseMode());
228 // TODO(mfomitchev): mouse enter/exit events
229 ScopedVector<ui::LocatedEvent>::const_iterator it;
230 for (it = captured_events.begin(); it != captured_events.end(); ++it) {
231 if ((*it)->type() == ui::ET_MOUSE_MOVED)
232 break;
233 }
234 EXPECT_NE(captured_events.end(), it);
235 ClearCapturedEvents();
236
237 // The release of the first finger shouldn't be affected.
238 ui::TouchEvent touch_release(ui::ET_TOUCH_RELEASED,
239 gfx::Point(11, 12),
240 1,
241 ui::EventTimeForNow());
242 generator.Dispatch(&touch_release);
243 ASSERT_EQ(1u, captured_events.size());
244 CONFIRM_EVENTS_ARE_TOUCH_AND_EQUAL(captured_events[0], &touch_release);
245 ClearCapturedEvents();
246
247 // The move and release from the second finger should get rewritten.
248 generator.MoveTouchId(gfx::Point(13, 14), 2);
249 generator.ReleaseTouchId(2);
250 ASSERT_EQ(2u, captured_events.size());
251 EXPECT_EQ(ui::ET_MOUSE_MOVED, captured_events[0]->type());
252 EXPECT_EQ(ui::ET_MOUSE_MOVED, captured_events[1]->type());
253 }
254
255 TEST_F(TouchExplorationTest, TwoFingerTouch) {
256 SwitchTouchExplorationMode(true);
257 aura::test::EventGenerator generator(root_window());
258 generator.PressTouchId(1);
259 ClearCapturedEvents();
260
261 // Confirm events from the second finger go through as is.
262 cursor_client()->ShowCursor();
263 cursor_client()->DisableMouseEvents();
264 ui::TouchEvent touch_press(ui::ET_TOUCH_PRESSED,
265 gfx::Point(10, 11),
266 2,
267 ui::EventTimeForNow());
268 generator.Dispatch(&touch_press);
269 EXPECT_TRUE(cursor_client()->IsCursorVisible());
270 EXPECT_FALSE(cursor_client()->IsMouseEventsEnabled());
271 const ScopedVector<ui::LocatedEvent>& captured_events = GetCapturedEvents();
272 // TODO(mfomitchev): mouse enter/exit events
273 // There will be a ET_MOUSE_EXITED event synthesized when the mouse cursor is
274 // hidden - ignore it.
275 ScopedVector<ui::LocatedEvent>::const_iterator it;
276 for (it = captured_events.begin(); it != captured_events.end(); ++it) {
277 if ((*it)->type() == ui::ET_TOUCH_PRESSED) {
278 CONFIRM_EVENTS_ARE_TOUCH_AND_EQUAL(*it, &touch_press);
279 break;
280 }
281 }
282 EXPECT_NE(captured_events.end(), it);
283 ClearCapturedEvents();
284 ui::TouchEvent touch_move(ui::ET_TOUCH_MOVED,
285 gfx::Point(20, 21),
286 2,
287 ui::EventTimeForNow());
288 generator.Dispatch(&touch_move);
289 ASSERT_EQ(1u, captured_events.size());
290 CONFIRM_EVENTS_ARE_TOUCH_AND_EQUAL(captured_events[0], &touch_move);
291 ClearCapturedEvents();
292
293 // Confirm mouse moves go through unaffected.
294 ui::MouseEvent mouse_move(ui::ET_MOUSE_MOVED,
295 gfx::Point(13, 14),
296 gfx::Point(13, 14),
297 0,
298 0);
299 generator.Dispatch(&mouse_move);
300 // TODO(mfomitchev): mouse enter/exit events
301 // Ignore synthesized ET_MOUSE_ENTERED/ET_MOUSE_EXITED
302 for (it = captured_events.begin(); it != captured_events.end(); ++it) {
303 if ((*it)->type() == ui::ET_MOUSE_MOVED) {
304 CONFIRM_EVENTS_ARE_MOUSE_AND_EQUAL(*it, &mouse_move);
305 break;
306 }
307 }
308 EXPECT_NE(captured_events.end(), it);
309 ClearCapturedEvents();
310
311 // Have some other fingers touch/move/release
312 generator.PressTouchId(3);
313 generator.PressTouchId(4);
314 generator.MoveTouchId(gfx::Point(30, 31), 3);
315 generator.ReleaseTouchId(3);
316 generator.ReleaseTouchId(4);
317 ClearCapturedEvents();
318
319 // Events from the first finger should not go through while the second finger
320 // is touching.
321 gfx::Point touch1_location = gfx::Point(15, 16);
322 generator.MoveTouchId(touch1_location, 1);
323 EXPECT_EQ(0u, GetCapturedEvents().size());
324
325 EXPECT_TRUE(cursor_client()->IsCursorVisible());
326 EXPECT_FALSE(cursor_client()->IsMouseEventsEnabled());
327
328 // A release of the second finger should go through, plus there should be a
329 // mouse move at |touch1_location| generated.
330 ui::TouchEvent touch_release(ui::ET_TOUCH_RELEASED,
331 gfx::Point(25, 26),
332 2,
333 ui::EventTimeForNow());
334 generator.Dispatch(&touch_release);
335 EXPECT_TRUE(IsInTouchToMouseMode());
336 ASSERT_GE(captured_events.size(), 2u);
337 CONFIRM_EVENTS_ARE_TOUCH_AND_EQUAL(captured_events[0], &touch_release);
338 // TODO(mfomitchev): mouse enter/exit events
339 // Ignore synthesized ET_MOUSE_ENTERED/ET_MOUSE_EXITED
340 for (it = captured_events.begin(); it != captured_events.end(); ++it) {
341 if ((*it)->type() == ui::ET_MOUSE_MOVED) {
342 EXPECT_EQ(touch1_location, (*it)->location());
343 break;
344 }
345 }
346 EXPECT_NE(captured_events.end(), it);
347 }
348
349 TEST_F(TouchExplorationTest, MultiFingerTouch) {
350 SwitchTouchExplorationMode(true);
351 aura::test::EventGenerator generator(root_window());
352 generator.PressTouchId(1);
353 generator.PressTouchId(2);
354 ClearCapturedEvents();
355
356 // Confirm events from other fingers go through as is.
357 ui::TouchEvent touch3_press(ui::ET_TOUCH_PRESSED,
358 gfx::Point(10, 11),
359 3,
360 ui::EventTimeForNow());
361 ui::TouchEvent touch3_move1(ui::ET_TOUCH_MOVED,
362 gfx::Point(12, 13),
363 3,
364 ui::EventTimeForNow());
365 ui::TouchEvent touch4_press(ui::ET_TOUCH_PRESSED,
366 gfx::Point(20, 21),
367 4,
368 ui::EventTimeForNow());
369 ui::TouchEvent touch3_move2(ui::ET_TOUCH_MOVED,
370 gfx::Point(14, 15),
371 3,
372 ui::EventTimeForNow());
373 ui::TouchEvent touch4_move(ui::ET_TOUCH_MOVED,
374 gfx::Point(22, 23),
375 4,
376 ui::EventTimeForNow());
377 ui::TouchEvent touch3_release(ui::ET_TOUCH_RELEASED,
378 gfx::Point(14, 15),
379 3,
380 ui::EventTimeForNow());
381 ui::TouchEvent touch4_release(ui::ET_TOUCH_RELEASED,
382 gfx::Point(22, 23),
383 4,
384 ui::EventTimeForNow());
385 generator.Dispatch(&touch3_press);
386 generator.Dispatch(&touch3_move1);
387 generator.Dispatch(&touch4_press);
388 generator.Dispatch(&touch3_move2);
389 generator.Dispatch(&touch4_move);
390 generator.Dispatch(&touch3_release);
391 generator.Dispatch(&touch4_release);
392
393 const ScopedVector<ui::LocatedEvent>& captured_events = GetCapturedEvents();
394 ASSERT_EQ(7u, captured_events.size());
395 CONFIRM_EVENTS_ARE_TOUCH_AND_EQUAL(captured_events[0], &touch3_press);
396 CONFIRM_EVENTS_ARE_TOUCH_AND_EQUAL(captured_events[1], &touch3_move1);
397 CONFIRM_EVENTS_ARE_TOUCH_AND_EQUAL(captured_events[2], &touch4_press);
398 CONFIRM_EVENTS_ARE_TOUCH_AND_EQUAL(captured_events[3], &touch3_move2);
399 CONFIRM_EVENTS_ARE_TOUCH_AND_EQUAL(captured_events[4], &touch4_move);
400 CONFIRM_EVENTS_ARE_TOUCH_AND_EQUAL(captured_events[5], &touch3_release);
401 CONFIRM_EVENTS_ARE_TOUCH_AND_EQUAL(captured_events[6], &touch4_release);
402 }
403
404 // Test the case when there are multiple fingers on the screen and the first
405 // finger is released. This should be rewritten as a release of the second
406 // finger. Additionally, if the second finger is the only finger left touching,
407 // we should enter a mouse move mode, and a mouse move event should be
408 // dispatched.
409 TEST_F(TouchExplorationTest, FirstFingerLifted) {
410 SwitchTouchExplorationMode(true);
411 aura::test::EventGenerator generator(root_window());
412 generator.PressTouchId(1);
413 generator.PressTouchId(2);
414 gfx::Point touch2_location(10, 11);
415 generator.MoveTouchId(touch2_location, 2);
416 generator.PressTouchId(3);
417 gfx::Point touch3_location(20, 21);
418 generator.MoveTouchId(touch3_location, 3);
419 ClearCapturedEvents();
420
421 // Release of finger 1 should be rewritten as a release of finger 2.
422 generator.ReleaseTouchId(1);
423 const ScopedVector<ui::LocatedEvent>& captured_events = GetCapturedEvents();
424 ASSERT_EQ(1u, captured_events.size());
425 EXPECT_EQ(ui::ET_TOUCH_RELEASED, captured_events[0]->type());
426 ui::TouchEvent* touch_event =
427 static_cast<ui::TouchEvent*>(captured_events[0]);
428 EXPECT_EQ(2, touch_event->touch_id());
429 EXPECT_EQ(touch2_location, touch_event->location());
430 ClearCapturedEvents();
431
432 // Release of finger 2 should be rewritten as a release of finger 3, plus
433 // we should enter the mouse move mode and a mouse move event should be
434 // dispatched.
435 cursor_client()->ShowCursor();
436 cursor_client()->DisableMouseEvents();
437 generator.ReleaseTouchId(2);
438 EXPECT_TRUE(IsInTouchToMouseMode());
439 ASSERT_GE(2u, captured_events.size());
440 EXPECT_EQ(ui::ET_TOUCH_RELEASED, captured_events[0]->type());
441 touch_event = static_cast<ui::TouchEvent*>(captured_events[0]);
442 EXPECT_EQ(3, touch_event->touch_id());
443 EXPECT_EQ(touch3_location, touch_event->location());
444 // TODO(mfomitchev): mouse enter/exit events
445 ScopedVector<ui::LocatedEvent>::const_iterator it;
446 for (it = captured_events.begin(); it != captured_events.end(); ++it) {
447 if ((*it)->type() == ui::ET_MOUSE_MOVED) {
448 EXPECT_EQ(touch3_location, (*it)->location());
449 break;
450 }
451 }
452 EXPECT_NE(captured_events.end(), it);
453 }
454
455 } // namespace ui
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698