1 // Copyright (c) 2013 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 "ash/touch/touch_observer_hud.h"
7 #include "ash/ash_switches.h"
8 #include "ash/display/display_manager.h"
9 #include "ash/root_window_controller.h"
10 #include "ash/screen_util.h"
11 #include "ash/shell.h"
12 #include "ash/test/ash_test_base.h"
13 #include "ash/test/display_manager_test_api.h"
14 #include "ash/touch/touch_hud_debug.h"
15 #include "ash/touch/touch_hud_projection.h"
16 #include "base/command_line.h"
17 #include "base/format_macros.h"
18 #include "base/strings/stringprintf.h"
19 #include "ui/aura/window.h"
23 class TouchHudTestBase : public test::AshTestBase {
26 virtual ~TouchHudTestBase() {}
28 virtual void SetUp() OVERRIDE {
29 test::AshTestBase::SetUp();
31 // Initialize display infos. They should be initialized after Ash
32 // environment is set up, i.e., after test::AshTestBase::SetUp().
33 internal_display_id_ = test::DisplayManagerTestApi(GetDisplayManager()).
34 SetFirstDisplayAsInternalDisplay();
35 external_display_id_ = 10;
36 mirrored_display_id_ = 11;
38 internal_display_info_ =
39 CreateDisplayInfo(internal_display_id_, gfx::Rect(0, 0, 500, 500));
40 external_display_info_ =
41 CreateDisplayInfo(external_display_id_, gfx::Rect(1, 1, 100, 100));
42 mirrored_display_info_ =
43 CreateDisplayInfo(mirrored_display_id_, gfx::Rect(0, 0, 100, 100));
46 gfx::Display GetPrimaryDisplay() {
47 return Shell::GetScreen()->GetPrimaryDisplay();
50 const gfx::Display& GetSecondaryDisplay() {
51 return ScreenUtil::GetSecondaryDisplay();
54 void SetupSingleDisplay() {
55 display_info_list_.clear();
56 display_info_list_.push_back(internal_display_info_);
57 GetDisplayManager()->OnNativeDisplaysChanged(display_info_list_);
60 void SetupDualDisplays() {
61 display_info_list_.clear();
62 display_info_list_.push_back(internal_display_info_);
63 display_info_list_.push_back(external_display_info_);
64 GetDisplayManager()->OnNativeDisplaysChanged(display_info_list_);
67 void SetInternalAsPrimary() {
68 const gfx::Display& internal_display =
69 GetDisplayManager()->GetDisplayForId(internal_display_id_);
70 GetDisplayController()->SetPrimaryDisplay(internal_display);
73 void SetExternalAsPrimary() {
74 const gfx::Display& external_display =
75 GetDisplayManager()->GetDisplayForId(external_display_id_);
76 GetDisplayController()->SetPrimaryDisplay(external_display);
79 void MirrorDisplays() {
80 DCHECK_EQ(2U, display_info_list_.size());
81 DCHECK_EQ(internal_display_id_, display_info_list_[0].id());
82 DCHECK_EQ(external_display_id_, display_info_list_[1].id());
83 display_info_list_[1] = mirrored_display_info_;
84 GetDisplayManager()->OnNativeDisplaysChanged(display_info_list_);
87 void UnmirrorDisplays() {
88 DCHECK_EQ(2U, display_info_list_.size());
89 DCHECK_EQ(internal_display_id_, display_info_list_[0].id());
90 DCHECK_EQ(mirrored_display_id_, display_info_list_[1].id());
91 display_info_list_[1] = external_display_info_;
92 GetDisplayManager()->OnNativeDisplaysChanged(display_info_list_);
95 void RemoveInternalDisplay() {
96 DCHECK_LT(0U, display_info_list_.size());
97 DCHECK_EQ(internal_display_id_, display_info_list_[0].id());
98 display_info_list_.erase(display_info_list_.begin());
99 GetDisplayManager()->OnNativeDisplaysChanged(display_info_list_);
102 void RemoveExternalDisplay() {
103 DCHECK_EQ(2U, display_info_list_.size());
104 display_info_list_.pop_back();
105 GetDisplayManager()->OnNativeDisplaysChanged(display_info_list_);
108 void AddInternalDisplay() {
109 DCHECK_EQ(0U, display_info_list_.size());
110 display_info_list_.push_back(internal_display_info_);
111 GetDisplayManager()->OnNativeDisplaysChanged(display_info_list_);
114 void AddExternalDisplay() {
115 DCHECK_EQ(1U, display_info_list_.size());
116 display_info_list_.push_back(external_display_info_);
117 GetDisplayManager()->OnNativeDisplaysChanged(display_info_list_);
120 int64 internal_display_id() const {
121 return internal_display_id_;
124 int64 external_display_id() const {
125 return external_display_id_;
129 DisplayManager* GetDisplayManager() {
130 return Shell::GetInstance()->display_manager();
133 DisplayController* GetDisplayController() {
134 return Shell::GetInstance()->display_controller();
137 const gfx::Display& GetInternalDisplay() {
138 return GetDisplayManager()->GetDisplayForId(internal_display_id_);
141 const gfx::Display& GetExternalDisplay() {
142 return GetDisplayManager()->GetDisplayForId(external_display_id_);
145 aura::Window* GetInternalRootWindow() {
146 return GetDisplayController()->GetRootWindowForDisplayId(
147 internal_display_id_);
150 aura::Window* GetExternalRootWindow() {
151 return GetDisplayController()->GetRootWindowForDisplayId(
152 external_display_id_);
155 aura::Window* GetPrimaryRootWindow() {
156 const gfx::Display& display = GetPrimaryDisplay();
157 return GetDisplayController()->GetRootWindowForDisplayId(display.id());
160 aura::Window* GetSecondaryRootWindow() {
161 const gfx::Display& display = GetSecondaryDisplay();
162 return GetDisplayController()->GetRootWindowForDisplayId(display.id());
165 RootWindowController* GetInternalRootController() {
166 aura::Window* root = GetInternalRootWindow();
167 return GetRootWindowController(root);
170 RootWindowController* GetExternalRootController() {
171 aura::Window* root = GetExternalRootWindow();
172 return GetRootWindowController(root);
175 RootWindowController* GetPrimaryRootController() {
176 aura::Window* root = GetPrimaryRootWindow();
177 return GetRootWindowController(root);
180 RootWindowController* GetSecondaryRootController() {
181 aura::Window* root = GetSecondaryRootWindow();
182 return GetRootWindowController(root);
185 DisplayInfo CreateDisplayInfo(int64 id, const gfx::Rect& bounds) {
186 DisplayInfo info(id, base::StringPrintf("x-%" PRId64, id), false);
187 info.SetBounds(bounds);
191 aura::Window* GetRootWindowForTouchHud(TouchObserverHUD* hud) {
192 return hud->root_window_;
195 views::Widget* GetWidgetForTouchHud(TouchObserverHUD* hud) {
199 int64 internal_display_id_;
200 int64 external_display_id_;
201 int64 mirrored_display_id_;
202 DisplayInfo internal_display_info_;
203 DisplayInfo external_display_info_;
204 DisplayInfo mirrored_display_info_;
206 std::vector<DisplayInfo> display_info_list_;
208 DISALLOW_COPY_AND_ASSIGN(TouchHudTestBase);
211 class TouchHudDebugTest : public TouchHudTestBase {
213 TouchHudDebugTest() {}
214 virtual ~TouchHudDebugTest() {}
216 virtual void SetUp() OVERRIDE {
217 // Add ash-touch-hud flag to enable debug touch HUD. This flag should be set
218 // before Ash environment is set up, i.e., before TouchHudTestBase::SetUp().
219 CommandLine::ForCurrentProcess()->AppendSwitch(
220 ash::switches::kAshTouchHud);
222 TouchHudTestBase::SetUp();
225 void CheckInternalDisplay() {
226 EXPECT_NE(static_cast<TouchObserverHUD*>(NULL), GetInternalTouchHudDebug());
227 EXPECT_EQ(internal_display_id(), GetInternalTouchHudDebug()->display_id());
228 EXPECT_EQ(GetInternalRootWindow(),
229 GetRootWindowForTouchHud(GetInternalTouchHudDebug()));
230 EXPECT_EQ(GetInternalRootWindow(),
231 GetWidgetForTouchHud(GetInternalTouchHudDebug())->
232 GetNativeView()->GetRootWindow());
233 EXPECT_EQ(GetInternalDisplay().size(),
234 GetWidgetForTouchHud(GetInternalTouchHudDebug())->
235 GetWindowBoundsInScreen().size());
238 void CheckExternalDisplay() {
239 EXPECT_NE(static_cast<TouchHudDebug*>(NULL), GetExternalTouchHudDebug());
240 EXPECT_EQ(external_display_id(), GetExternalTouchHudDebug()->display_id());
241 EXPECT_EQ(GetExternalRootWindow(),
242 GetRootWindowForTouchHud(GetExternalTouchHudDebug()));
243 EXPECT_EQ(GetExternalRootWindow(),
244 GetWidgetForTouchHud(GetExternalTouchHudDebug())->
245 GetNativeView()->GetRootWindow());
246 EXPECT_EQ(GetExternalDisplay().size(),
247 GetWidgetForTouchHud(GetExternalTouchHudDebug())->
248 GetWindowBoundsInScreen().size());
252 TouchHudDebug* GetInternalTouchHudDebug() {
253 return GetInternalRootController()->touch_hud_debug();
256 TouchHudDebug* GetExternalTouchHudDebug() {
257 return GetExternalRootController()->touch_hud_debug();
260 TouchHudDebug* GetPrimaryTouchHudDebug() {
261 return GetPrimaryRootController()->touch_hud_debug();
264 TouchHudDebug* GetSecondaryTouchHudDebug() {
265 return GetSecondaryRootController()->touch_hud_debug();
268 DISALLOW_COPY_AND_ASSIGN(TouchHudDebugTest);
271 class TouchHudProjectionTest : public TouchHudTestBase {
273 TouchHudProjectionTest() {}
274 virtual ~TouchHudProjectionTest() {}
276 void EnableTouchHudProjection() {
277 Shell::GetInstance()->SetTouchHudProjectionEnabled(true);
280 void DisableTouchHudProjection() {
281 Shell::GetInstance()->SetTouchHudProjectionEnabled(false);
284 TouchHudProjection* GetInternalTouchHudProjection() {
285 return GetInternalRootController()->touch_hud_projection();
288 int GetInternalTouchPointsCount() {
289 return GetInternalTouchHudProjection()->points_.size();
292 void SendTouchEventToInternalHud(ui::EventType type,
293 const gfx::Point& location,
295 ui::TouchEvent event(type, location, touch_id, event_time);
296 GetInternalTouchHudProjection()->OnTouchEvent(&event);
298 // Advance time for next event.
299 event_time += base::TimeDelta::FromMilliseconds(100);
303 base::TimeDelta event_time;
305 DISALLOW_COPY_AND_ASSIGN(TouchHudProjectionTest);
308 // Checks if debug touch HUD is correctly initialized for a single display.
309 TEST_F(TouchHudDebugTest, SingleDisplay) {
310 // Setup a single display setting.
311 SetupSingleDisplay();
313 // Check if touch HUD is set correctly and associated with appropriate
315 CheckInternalDisplay();
318 // Checks if debug touch HUDs are correctly initialized for two displays.
319 TEST_F(TouchHudDebugTest, DualDisplays) {
320 if (!SupportsMultipleDisplays())
323 // Setup a dual display setting.
326 // Check if touch HUDs are set correctly and associated with appropriate
328 CheckInternalDisplay();
329 CheckExternalDisplay();
332 // Checks if debug touch HUDs are correctly handled when primary display is
334 TEST_F(TouchHudDebugTest, SwapPrimaryDisplay) {
335 if (!SupportsMultipleDisplays())
338 // Setup a dual display setting.
341 // Set the primary display to the external one.
342 SetExternalAsPrimary();
344 // Check if displays' touch HUDs are not swapped as root windows are.
345 EXPECT_EQ(external_display_id(), GetPrimaryDisplay().id());
346 EXPECT_EQ(internal_display_id(), GetSecondaryDisplay().id());
347 CheckInternalDisplay();
348 CheckExternalDisplay();
350 // Set the primary display back to the internal one.
351 SetInternalAsPrimary();
353 // Check if displays' touch HUDs are not swapped back as root windows are.
354 EXPECT_EQ(internal_display_id(), GetPrimaryDisplay().id());
355 EXPECT_EQ(external_display_id(), GetSecondaryDisplay().id());
356 CheckInternalDisplay();
357 CheckExternalDisplay();
360 // Checks if debug touch HUDs are correctly handled when displays are mirrored.
361 TEST_F(TouchHudDebugTest, MirrorDisplays) {
362 if (!SupportsMultipleDisplays())
365 // Setup a dual display setting.
371 // Check if the internal display is intact.
372 EXPECT_EQ(internal_display_id(), GetPrimaryDisplay().id());
373 CheckInternalDisplay();
375 // Unmirror displays.
378 // Check if external display is added back correctly.
379 EXPECT_EQ(internal_display_id(), GetPrimaryDisplay().id());
380 EXPECT_EQ(external_display_id(), GetSecondaryDisplay().id());
381 CheckInternalDisplay();
382 CheckExternalDisplay();
385 // Checks if debug touch HUDs are correctly handled when displays are mirrored
386 // after setting the external display as the primary one.
387 TEST_F(TouchHudDebugTest, SwapPrimaryThenMirrorDisplays) {
388 if (!SupportsMultipleDisplays())
391 // Setup a dual display setting.
394 // Set the primary display to the external one.
395 SetExternalAsPrimary();
400 // Check if the internal display is set as the primary one.
401 EXPECT_EQ(internal_display_id(), GetPrimaryDisplay().id());
402 CheckInternalDisplay();
404 // Unmirror displays.
407 // Check if the external display is added back as the primary display and
408 // touch HUDs are set correctly.
409 EXPECT_EQ(external_display_id(), GetPrimaryDisplay().id());
410 EXPECT_EQ(internal_display_id(), GetSecondaryDisplay().id());
411 CheckInternalDisplay();
412 CheckExternalDisplay();
415 // Checks if debug touch HUDs are correctly handled when the external display,
416 // which is the secondary one, is removed.
417 TEST_F(TouchHudDebugTest, RemoveSecondaryDisplay) {
418 if (!SupportsMultipleDisplays())
421 // Setup a dual display setting.
424 // Remove external display which is the secondary one.
425 RemoveExternalDisplay();
427 // Check if the internal display is intact.
428 EXPECT_EQ(internal_display_id(), GetPrimaryDisplay().id());
429 CheckInternalDisplay();
431 // Add external display back.
432 AddExternalDisplay();
434 // Check if displays' touch HUDs are set correctly.
435 EXPECT_EQ(internal_display_id(), GetPrimaryDisplay().id());
436 EXPECT_EQ(external_display_id(), GetSecondaryDisplay().id());
437 CheckInternalDisplay();
438 CheckExternalDisplay();
441 // Checks if debug touch HUDs are correctly handled when the external display,
442 // which is set as the primary display, is removed.
443 TEST_F(TouchHudDebugTest, RemovePrimaryDisplay) {
444 if (!SupportsMultipleDisplays())
447 // Setup a dual display setting.
450 // Set the primary display to the external one.
451 SetExternalAsPrimary();
453 // Remove the external display which is the primary display.
454 RemoveExternalDisplay();
456 // Check if the internal display is set as the primary one.
457 EXPECT_EQ(internal_display_id(), GetPrimaryDisplay().id());
458 CheckInternalDisplay();
460 // Add the external display back.
461 AddExternalDisplay();
463 // Check if the external display is set as primary and touch HUDs are set
465 EXPECT_EQ(external_display_id(), GetPrimaryDisplay().id());
466 EXPECT_EQ(internal_display_id(), GetSecondaryDisplay().id());
467 CheckInternalDisplay();
468 CheckExternalDisplay();
471 // Checks if debug touch HUDs are correctly handled when all displays are
473 TEST_F(TouchHudDebugTest, Headless) {
474 if (!SupportsMultipleDisplays())
477 // Setup a single display setting.
478 SetupSingleDisplay();
480 // Remove the only display which is the internal one.
481 RemoveInternalDisplay();
483 // Add the internal display back.
484 AddInternalDisplay();
486 // Check if the display's touch HUD is set correctly.
487 EXPECT_EQ(internal_display_id(), GetPrimaryDisplay().id());
488 CheckInternalDisplay();
491 // Checks projection touch HUD with a sequence of touch-pressed, touch-moved,
492 // and touch-released events.
493 TEST_F(TouchHudProjectionTest, TouchMoveRelease) {
494 SetupSingleDisplay();
495 EXPECT_EQ(NULL, GetInternalTouchHudProjection());
497 EnableTouchHudProjection();
498 EXPECT_NE(static_cast<TouchHudProjection*>(NULL),
499 GetInternalTouchHudProjection());
500 EXPECT_EQ(0, GetInternalTouchPointsCount());
502 SendTouchEventToInternalHud(ui::ET_TOUCH_PRESSED, gfx::Point(10, 10), 1);
503 EXPECT_EQ(1, GetInternalTouchPointsCount());
505 SendTouchEventToInternalHud(ui::ET_TOUCH_MOVED, gfx::Point(10, 20), 1);
506 EXPECT_EQ(1, GetInternalTouchPointsCount());
508 SendTouchEventToInternalHud(ui::ET_TOUCH_RELEASED, gfx::Point(10, 20), 1);
509 EXPECT_EQ(0, GetInternalTouchPointsCount());
511 // Disabling projection touch HUD shoud remove it without crashing.
512 DisableTouchHudProjection();
513 EXPECT_EQ(NULL, GetInternalTouchHudProjection());
516 // Checks projection touch HUD with a sequence of touch-pressed, touch-moved,
517 // and touch-cancelled events.
518 TEST_F(TouchHudProjectionTest, TouchMoveCancel) {
519 SetupSingleDisplay();
520 EXPECT_EQ(NULL, GetInternalTouchHudProjection());
522 EnableTouchHudProjection();
523 EXPECT_NE(static_cast<TouchHudProjection*>(NULL),
524 GetInternalTouchHudProjection());
525 EXPECT_EQ(0, GetInternalTouchPointsCount());
527 SendTouchEventToInternalHud(ui::ET_TOUCH_PRESSED, gfx::Point(10, 10), 1);
528 EXPECT_EQ(1, GetInternalTouchPointsCount());
530 SendTouchEventToInternalHud(ui::ET_TOUCH_MOVED, gfx::Point(10, 20), 1);
531 EXPECT_EQ(1, GetInternalTouchPointsCount());
533 SendTouchEventToInternalHud(ui::ET_TOUCH_CANCELLED, gfx::Point(10, 20), 1);
534 EXPECT_EQ(0, GetInternalTouchPointsCount());
536 // Disabling projection touch HUD shoud remove it without crashing.
537 DisableTouchHudProjection();
538 EXPECT_EQ(NULL, GetInternalTouchHudProjection());
541 // Checks projection touch HUD with two simultaneous touches.
542 TEST_F(TouchHudProjectionTest, DoubleTouch) {
543 SetupSingleDisplay();
544 EXPECT_EQ(NULL, GetInternalTouchHudProjection());
546 EnableTouchHudProjection();
547 EXPECT_NE(static_cast<TouchHudProjection*>(NULL),
548 GetInternalTouchHudProjection());
549 EXPECT_EQ(0, GetInternalTouchPointsCount());
551 SendTouchEventToInternalHud(ui::ET_TOUCH_PRESSED, gfx::Point(10, 10), 1);
552 EXPECT_EQ(1, GetInternalTouchPointsCount());
554 SendTouchEventToInternalHud(ui::ET_TOUCH_PRESSED, gfx::Point(20, 10), 2);
555 EXPECT_EQ(2, GetInternalTouchPointsCount());
557 SendTouchEventToInternalHud(ui::ET_TOUCH_MOVED, gfx::Point(10, 20), 1);
558 EXPECT_EQ(2, GetInternalTouchPointsCount());
560 SendTouchEventToInternalHud(ui::ET_TOUCH_MOVED, gfx::Point(20, 20), 2);
561 EXPECT_EQ(2, GetInternalTouchPointsCount());
563 SendTouchEventToInternalHud(ui::ET_TOUCH_RELEASED, gfx::Point(10, 20), 1);
564 EXPECT_EQ(1, GetInternalTouchPointsCount());
566 SendTouchEventToInternalHud(ui::ET_TOUCH_RELEASED, gfx::Point(20, 20), 2);
567 EXPECT_EQ(0, GetInternalTouchPointsCount());
569 // Disabling projection touch HUD shoud remove it without crashing.
570 DisableTouchHudProjection();
571 EXPECT_EQ(NULL, GetInternalTouchHudProjection());
574 // Checks if turning off touch HUD projection while touching the screen is
575 // handled correctly.
576 TEST_F(TouchHudProjectionTest, DisableWhileTouching) {
577 SetupSingleDisplay();
578 EXPECT_EQ(NULL, GetInternalTouchHudProjection());
580 EnableTouchHudProjection();
581 EXPECT_NE(static_cast<TouchHudProjection*>(NULL),
582 GetInternalTouchHudProjection());
583 EXPECT_EQ(0, GetInternalTouchPointsCount());
585 SendTouchEventToInternalHud(ui::ET_TOUCH_PRESSED, gfx::Point(10, 10), 1);
586 EXPECT_EQ(1, GetInternalTouchPointsCount());
588 // Disabling projection touch HUD shoud remove it without crashing.
589 DisableTouchHudProjection();
590 EXPECT_EQ(NULL, GetInternalTouchHudProjection());