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