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. 4 5 #include "ash/touch/touch_observer_hud.h" 6 7 #include "ash/ash_switches.h" 8 #include "ash/display/display_manager.h" 9 #include "ash/root_window_controller.h" 10 #include "ash/screen_ash.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" 20 21 namespace ash { 22 namespace internal { 23 24 class TouchHudTestBase : public test::AshTestBase { 25 public: 26 TouchHudTestBase() {} 27 virtual ~TouchHudTestBase() {} 28 29 virtual void SetUp() OVERRIDE { 30 test::AshTestBase::SetUp(); 31 32 // Initialize display infos. They should be initialized after Ash 33 // environment is set up, i.e., after test::AshTestBase::SetUp(). 34 internal_display_id_ = test::DisplayManagerTestApi(GetDisplayManager()). 35 SetFirstDisplayAsInternalDisplay(); 36 external_display_id_ = 10; 37 mirrored_display_id_ = 11; 38 39 internal_display_info_ = 40 CreateDisplayInfo(internal_display_id_, gfx::Rect(0, 0, 500, 500)); 41 external_display_info_ = 42 CreateDisplayInfo(external_display_id_, gfx::Rect(1, 1, 100, 100)); 43 mirrored_display_info_ = 44 CreateDisplayInfo(mirrored_display_id_, gfx::Rect(0, 0, 100, 100)); 45 } 46 47 gfx::Display GetPrimaryDisplay() { 48 return Shell::GetScreen()->GetPrimaryDisplay(); 49 } 50 51 const gfx::Display& GetSecondaryDisplay() { 52 return ScreenAsh::GetSecondaryDisplay(); 53 } 54 55 void SetupSingleDisplay() { 56 display_info_list_.clear(); 57 display_info_list_.push_back(internal_display_info_); 58 GetDisplayManager()->OnNativeDisplaysChanged(display_info_list_); 59 } 60 61 void SetupDualDisplays() { 62 display_info_list_.clear(); 63 display_info_list_.push_back(internal_display_info_); 64 display_info_list_.push_back(external_display_info_); 65 GetDisplayManager()->OnNativeDisplaysChanged(display_info_list_); 66 } 67 68 void SetInternalAsPrimary() { 69 const gfx::Display& internal_display = 70 GetDisplayManager()->GetDisplayForId(internal_display_id_); 71 GetDisplayController()->SetPrimaryDisplay(internal_display); 72 } 73 74 void SetExternalAsPrimary() { 75 const gfx::Display& external_display = 76 GetDisplayManager()->GetDisplayForId(external_display_id_); 77 GetDisplayController()->SetPrimaryDisplay(external_display); 78 } 79 80 void MirrorDisplays() { 81 DCHECK_EQ(2U, display_info_list_.size()); 82 DCHECK_EQ(internal_display_id_, display_info_list_[0].id()); 83 DCHECK_EQ(external_display_id_, display_info_list_[1].id()); 84 display_info_list_[1] = mirrored_display_info_; 85 GetDisplayManager()->OnNativeDisplaysChanged(display_info_list_); 86 } 87 88 void UnmirrorDisplays() { 89 DCHECK_EQ(2U, display_info_list_.size()); 90 DCHECK_EQ(internal_display_id_, display_info_list_[0].id()); 91 DCHECK_EQ(mirrored_display_id_, display_info_list_[1].id()); 92 display_info_list_[1] = external_display_info_; 93 GetDisplayManager()->OnNativeDisplaysChanged(display_info_list_); 94 } 95 96 void RemoveInternalDisplay() { 97 DCHECK_LT(0U, display_info_list_.size()); 98 DCHECK_EQ(internal_display_id_, display_info_list_[0].id()); 99 display_info_list_.erase(display_info_list_.begin()); 100 GetDisplayManager()->OnNativeDisplaysChanged(display_info_list_); 101 } 102 103 void RemoveExternalDisplay() { 104 DCHECK_EQ(2U, display_info_list_.size()); 105 display_info_list_.pop_back(); 106 GetDisplayManager()->OnNativeDisplaysChanged(display_info_list_); 107 } 108 109 void AddInternalDisplay() { 110 DCHECK_EQ(0U, display_info_list_.size()); 111 display_info_list_.push_back(internal_display_info_); 112 GetDisplayManager()->OnNativeDisplaysChanged(display_info_list_); 113 } 114 115 void AddExternalDisplay() { 116 DCHECK_EQ(1U, display_info_list_.size()); 117 display_info_list_.push_back(external_display_info_); 118 GetDisplayManager()->OnNativeDisplaysChanged(display_info_list_); 119 } 120 121 int64 internal_display_id() const { 122 return internal_display_id_; 123 } 124 125 int64 external_display_id() const { 126 return external_display_id_; 127 } 128 129 protected: 130 DisplayManager* GetDisplayManager() { 131 return Shell::GetInstance()->display_manager(); 132 } 133 134 DisplayController* GetDisplayController() { 135 return Shell::GetInstance()->display_controller(); 136 } 137 138 const gfx::Display& GetInternalDisplay() { 139 return GetDisplayManager()->GetDisplayForId(internal_display_id_); 140 } 141 142 const gfx::Display& GetExternalDisplay() { 143 return GetDisplayManager()->GetDisplayForId(external_display_id_); 144 } 145 146 aura::Window* GetInternalRootWindow() { 147 return GetDisplayController()->GetRootWindowForDisplayId( 148 internal_display_id_); 149 } 150 151 aura::Window* GetExternalRootWindow() { 152 return GetDisplayController()->GetRootWindowForDisplayId( 153 external_display_id_); 154 } 155 156 aura::Window* GetPrimaryRootWindow() { 157 const gfx::Display& display = GetPrimaryDisplay(); 158 return GetDisplayController()->GetRootWindowForDisplayId(display.id()); 159 } 160 161 aura::Window* GetSecondaryRootWindow() { 162 const gfx::Display& display = GetSecondaryDisplay(); 163 return GetDisplayController()->GetRootWindowForDisplayId(display.id()); 164 } 165 166 internal::RootWindowController* GetInternalRootController() { 167 aura::Window* root = GetInternalRootWindow(); 168 return GetRootWindowController(root); 169 } 170 171 internal::RootWindowController* GetExternalRootController() { 172 aura::Window* root = GetExternalRootWindow(); 173 return GetRootWindowController(root); 174 } 175 176 internal::RootWindowController* GetPrimaryRootController() { 177 aura::Window* root = GetPrimaryRootWindow(); 178 return GetRootWindowController(root); 179 } 180 181 internal::RootWindowController* GetSecondaryRootController() { 182 aura::Window* root = GetSecondaryRootWindow(); 183 return GetRootWindowController(root); 184 } 185 186 DisplayInfo CreateDisplayInfo(int64 id, const gfx::Rect& bounds) { 187 DisplayInfo info(id, base::StringPrintf("x-%" PRId64, id), false); 188 info.SetBounds(bounds); 189 return info; 190 } 191 192 aura::Window* GetRootWindowForTouchHud(internal::TouchObserverHUD* hud) { 193 return hud->root_window_; 194 } 195 196 views::Widget* GetWidgetForTouchHud(internal::TouchObserverHUD* hud) { 197 return hud->widget_; 198 } 199 200 int64 internal_display_id_; 201 int64 external_display_id_; 202 int64 mirrored_display_id_; 203 DisplayInfo internal_display_info_; 204 DisplayInfo external_display_info_; 205 DisplayInfo mirrored_display_info_; 206 207 std::vector<DisplayInfo> display_info_list_; 208 209 DISALLOW_COPY_AND_ASSIGN(TouchHudTestBase); 210 }; 211 212 class TouchHudDebugTest : public TouchHudTestBase { 213 public: 214 TouchHudDebugTest() {} 215 virtual ~TouchHudDebugTest() {} 216 217 virtual void SetUp() OVERRIDE { 218 // Add ash-touch-hud flag to enable debug touch HUD. This flag should be set 219 // before Ash environment is set up, i.e., before TouchHudTestBase::SetUp(). 220 CommandLine::ForCurrentProcess()->AppendSwitch( 221 ash::switches::kAshTouchHud); 222 223 TouchHudTestBase::SetUp(); 224 } 225 226 void CheckInternalDisplay() { 227 EXPECT_NE(static_cast<internal::TouchObserverHUD*>(NULL), 228 GetInternalTouchHudDebug()); 229 EXPECT_EQ(internal_display_id(), GetInternalTouchHudDebug()->display_id()); 230 EXPECT_EQ(GetInternalRootWindow(), 231 GetRootWindowForTouchHud(GetInternalTouchHudDebug())); 232 EXPECT_EQ(GetInternalRootWindow(), 233 GetWidgetForTouchHud(GetInternalTouchHudDebug())-> 234 GetNativeView()->GetRootWindow()); 235 EXPECT_EQ(GetInternalDisplay().size(), 236 GetWidgetForTouchHud(GetInternalTouchHudDebug())-> 237 GetWindowBoundsInScreen().size()); 238 } 239 240 void CheckExternalDisplay() { 241 EXPECT_NE(static_cast<internal::TouchHudDebug*>(NULL), 242 GetExternalTouchHudDebug()); 243 EXPECT_EQ(external_display_id(), GetExternalTouchHudDebug()->display_id()); 244 EXPECT_EQ(GetExternalRootWindow(), 245 GetRootWindowForTouchHud(GetExternalTouchHudDebug())); 246 EXPECT_EQ(GetExternalRootWindow(), 247 GetWidgetForTouchHud(GetExternalTouchHudDebug())-> 248 GetNativeView()->GetRootWindow()); 249 EXPECT_EQ(GetExternalDisplay().size(), 250 GetWidgetForTouchHud(GetExternalTouchHudDebug())-> 251 GetWindowBoundsInScreen().size()); 252 } 253 254 private: 255 internal::TouchHudDebug* GetInternalTouchHudDebug() { 256 return GetInternalRootController()->touch_hud_debug(); 257 } 258 259 internal::TouchHudDebug* GetExternalTouchHudDebug() { 260 return GetExternalRootController()->touch_hud_debug(); 261 } 262 263 internal::TouchHudDebug* GetPrimaryTouchHudDebug() { 264 return GetPrimaryRootController()->touch_hud_debug(); 265 } 266 267 internal::TouchHudDebug* GetSecondaryTouchHudDebug() { 268 return GetSecondaryRootController()->touch_hud_debug(); 269 } 270 271 DISALLOW_COPY_AND_ASSIGN(TouchHudDebugTest); 272 }; 273 274 class TouchHudProjectionTest : public TouchHudTestBase { 275 public: 276 TouchHudProjectionTest() {} 277 virtual ~TouchHudProjectionTest() {} 278 279 void EnableTouchHudProjection() { 280 Shell::GetInstance()->SetTouchHudProjectionEnabled(true); 281 } 282 283 void DisableTouchHudProjection() { 284 Shell::GetInstance()->SetTouchHudProjectionEnabled(false); 285 } 286 287 internal::TouchHudProjection* GetInternalTouchHudProjection() { 288 return GetInternalRootController()->touch_hud_projection(); 289 } 290 291 int GetInternalTouchPointsCount() { 292 return GetInternalTouchHudProjection()->points_.size(); 293 } 294 295 void SendTouchEventToInternalHud(ui::EventType type, 296 const gfx::Point& location, 297 int touch_id) { 298 ui::TouchEvent event(type, location, touch_id, event_time); 299 GetInternalTouchHudProjection()->OnTouchEvent(&event); 300 301 // Advance time for next event. 302 event_time += base::TimeDelta::FromMilliseconds(100); 303 } 304 305 private: 306 base::TimeDelta event_time; 307 308 DISALLOW_COPY_AND_ASSIGN(TouchHudProjectionTest); 309 }; 310 311 // Checks if debug touch HUD is correctly initialized for a single display. 312 TEST_F(TouchHudDebugTest, SingleDisplay) { 313 // Setup a single display setting. 314 SetupSingleDisplay(); 315 316 // Check if touch HUD is set correctly and associated with appropriate 317 // display. 318 CheckInternalDisplay(); 319 } 320 321 // Checks if debug touch HUDs are correctly initialized for two displays. 322 TEST_F(TouchHudDebugTest, DualDisplays) { 323 if (!SupportsMultipleDisplays()) 324 return; 325 326 // Setup a dual display setting. 327 SetupDualDisplays(); 328 329 // Check if touch HUDs are set correctly and associated with appropriate 330 // displays. 331 CheckInternalDisplay(); 332 CheckExternalDisplay(); 333 } 334 335 // Checks if debug touch HUDs are correctly handled when primary display is 336 // changed. 337 TEST_F(TouchHudDebugTest, SwapPrimaryDisplay) { 338 if (!SupportsMultipleDisplays()) 339 return; 340 341 // Setup a dual display setting. 342 SetupDualDisplays(); 343 344 // Set the primary display to the external one. 345 SetExternalAsPrimary(); 346 347 // Check if displays' touch HUDs are not swapped as root windows are. 348 EXPECT_EQ(external_display_id(), GetPrimaryDisplay().id()); 349 EXPECT_EQ(internal_display_id(), GetSecondaryDisplay().id()); 350 CheckInternalDisplay(); 351 CheckExternalDisplay(); 352 353 // Set the primary display back to the internal one. 354 SetInternalAsPrimary(); 355 356 // Check if displays' touch HUDs are not swapped back as root windows are. 357 EXPECT_EQ(internal_display_id(), GetPrimaryDisplay().id()); 358 EXPECT_EQ(external_display_id(), GetSecondaryDisplay().id()); 359 CheckInternalDisplay(); 360 CheckExternalDisplay(); 361 } 362 363 // Checks if debug touch HUDs are correctly handled when displays are mirrored. 364 TEST_F(TouchHudDebugTest, MirrorDisplays) { 365 if (!SupportsMultipleDisplays()) 366 return; 367 368 // Setup a dual display setting. 369 SetupDualDisplays(); 370 371 // Mirror displays. 372 MirrorDisplays(); 373 374 // Check if the internal display is intact. 375 EXPECT_EQ(internal_display_id(), GetPrimaryDisplay().id()); 376 CheckInternalDisplay(); 377 378 // Unmirror displays. 379 UnmirrorDisplays(); 380 381 // Check if external display is added back correctly. 382 EXPECT_EQ(internal_display_id(), GetPrimaryDisplay().id()); 383 EXPECT_EQ(external_display_id(), GetSecondaryDisplay().id()); 384 CheckInternalDisplay(); 385 CheckExternalDisplay(); 386 } 387 388 // Checks if debug touch HUDs are correctly handled when displays are mirrored 389 // after setting the external display as the primary one. 390 TEST_F(TouchHudDebugTest, SwapPrimaryThenMirrorDisplays) { 391 if (!SupportsMultipleDisplays()) 392 return; 393 394 // Setup a dual display setting. 395 SetupDualDisplays(); 396 397 // Set the primary display to the external one. 398 SetExternalAsPrimary(); 399 400 // Mirror displays. 401 MirrorDisplays(); 402 403 // Check if the internal display is set as the primary one. 404 EXPECT_EQ(internal_display_id(), GetPrimaryDisplay().id()); 405 CheckInternalDisplay(); 406 407 // Unmirror displays. 408 UnmirrorDisplays(); 409 410 // Check if the external display is added back as the primary display and 411 // touch HUDs are set correctly. 412 EXPECT_EQ(external_display_id(), GetPrimaryDisplay().id()); 413 EXPECT_EQ(internal_display_id(), GetSecondaryDisplay().id()); 414 CheckInternalDisplay(); 415 CheckExternalDisplay(); 416 } 417 418 // Checks if debug touch HUDs are correctly handled when the external display, 419 // which is the secondary one, is removed. 420 TEST_F(TouchHudDebugTest, RemoveSecondaryDisplay) { 421 if (!SupportsMultipleDisplays()) 422 return; 423 424 // Setup a dual display setting. 425 SetupDualDisplays(); 426 427 // Remove external display which is the secondary one. 428 RemoveExternalDisplay(); 429 430 // Check if the internal display is intact. 431 EXPECT_EQ(internal_display_id(), GetPrimaryDisplay().id()); 432 CheckInternalDisplay(); 433 434 // Add external display back. 435 AddExternalDisplay(); 436 437 // Check if displays' touch HUDs are set correctly. 438 EXPECT_EQ(internal_display_id(), GetPrimaryDisplay().id()); 439 EXPECT_EQ(external_display_id(), GetSecondaryDisplay().id()); 440 CheckInternalDisplay(); 441 CheckExternalDisplay(); 442 } 443 444 // Checks if debug touch HUDs are correctly handled when the external display, 445 // which is set as the primary display, is removed. 446 TEST_F(TouchHudDebugTest, RemovePrimaryDisplay) { 447 if (!SupportsMultipleDisplays()) 448 return; 449 450 // Setup a dual display setting. 451 SetupDualDisplays(); 452 453 // Set the primary display to the external one. 454 SetExternalAsPrimary(); 455 456 // Remove the external display which is the primary display. 457 RemoveExternalDisplay(); 458 459 // Check if the internal display is set as the primary one. 460 EXPECT_EQ(internal_display_id(), GetPrimaryDisplay().id()); 461 CheckInternalDisplay(); 462 463 // Add the external display back. 464 AddExternalDisplay(); 465 466 // Check if the external display is set as primary and touch HUDs are set 467 // correctly. 468 EXPECT_EQ(external_display_id(), GetPrimaryDisplay().id()); 469 EXPECT_EQ(internal_display_id(), GetSecondaryDisplay().id()); 470 CheckInternalDisplay(); 471 CheckExternalDisplay(); 472 } 473 474 // Checks if debug touch HUDs are correctly handled when all displays are 475 // removed. 476 TEST_F(TouchHudDebugTest, Headless) { 477 if (!SupportsMultipleDisplays()) 478 return; 479 480 // Setup a single display setting. 481 SetupSingleDisplay(); 482 483 // Remove the only display which is the internal one. 484 RemoveInternalDisplay(); 485 486 // Add the internal display back. 487 AddInternalDisplay(); 488 489 // Check if the display's touch HUD is set correctly. 490 EXPECT_EQ(internal_display_id(), GetPrimaryDisplay().id()); 491 CheckInternalDisplay(); 492 } 493 494 // Checks projection touch HUD with a sequence of touch-pressed, touch-moved, 495 // and touch-released events. 496 TEST_F(TouchHudProjectionTest, TouchMoveRelease) { 497 SetupSingleDisplay(); 498 EXPECT_EQ(NULL, GetInternalTouchHudProjection()); 499 500 EnableTouchHudProjection(); 501 EXPECT_NE(static_cast<internal::TouchHudProjection*>(NULL), 502 GetInternalTouchHudProjection()); 503 EXPECT_EQ(0, GetInternalTouchPointsCount()); 504 505 SendTouchEventToInternalHud(ui::ET_TOUCH_PRESSED, gfx::Point(10, 10), 1); 506 EXPECT_EQ(1, GetInternalTouchPointsCount()); 507 508 SendTouchEventToInternalHud(ui::ET_TOUCH_MOVED, gfx::Point(10, 20), 1); 509 EXPECT_EQ(1, GetInternalTouchPointsCount()); 510 511 SendTouchEventToInternalHud(ui::ET_TOUCH_RELEASED, gfx::Point(10, 20), 1); 512 EXPECT_EQ(0, GetInternalTouchPointsCount()); 513 514 // Disabling projection touch HUD shoud remove it without crashing. 515 DisableTouchHudProjection(); 516 EXPECT_EQ(NULL, GetInternalTouchHudProjection()); 517 } 518 519 // Checks projection touch HUD with a sequence of touch-pressed, touch-moved, 520 // and touch-cancelled events. 521 TEST_F(TouchHudProjectionTest, TouchMoveCancel) { 522 SetupSingleDisplay(); 523 EXPECT_EQ(NULL, GetInternalTouchHudProjection()); 524 525 EnableTouchHudProjection(); 526 EXPECT_NE(static_cast<internal::TouchHudProjection*>(NULL), 527 GetInternalTouchHudProjection()); 528 EXPECT_EQ(0, GetInternalTouchPointsCount()); 529 530 SendTouchEventToInternalHud(ui::ET_TOUCH_PRESSED, gfx::Point(10, 10), 1); 531 EXPECT_EQ(1, GetInternalTouchPointsCount()); 532 533 SendTouchEventToInternalHud(ui::ET_TOUCH_MOVED, gfx::Point(10, 20), 1); 534 EXPECT_EQ(1, GetInternalTouchPointsCount()); 535 536 SendTouchEventToInternalHud(ui::ET_TOUCH_CANCELLED, gfx::Point(10, 20), 1); 537 EXPECT_EQ(0, GetInternalTouchPointsCount()); 538 539 // Disabling projection touch HUD shoud remove it without crashing. 540 DisableTouchHudProjection(); 541 EXPECT_EQ(NULL, GetInternalTouchHudProjection()); 542 } 543 544 // Checks projection touch HUD with two simultaneous touches. 545 TEST_F(TouchHudProjectionTest, DoubleTouch) { 546 SetupSingleDisplay(); 547 EXPECT_EQ(NULL, GetInternalTouchHudProjection()); 548 549 EnableTouchHudProjection(); 550 EXPECT_NE(static_cast<internal::TouchHudProjection*>(NULL), 551 GetInternalTouchHudProjection()); 552 EXPECT_EQ(0, GetInternalTouchPointsCount()); 553 554 SendTouchEventToInternalHud(ui::ET_TOUCH_PRESSED, gfx::Point(10, 10), 1); 555 EXPECT_EQ(1, GetInternalTouchPointsCount()); 556 557 SendTouchEventToInternalHud(ui::ET_TOUCH_PRESSED, gfx::Point(20, 10), 2); 558 EXPECT_EQ(2, GetInternalTouchPointsCount()); 559 560 SendTouchEventToInternalHud(ui::ET_TOUCH_MOVED, gfx::Point(10, 20), 1); 561 EXPECT_EQ(2, GetInternalTouchPointsCount()); 562 563 SendTouchEventToInternalHud(ui::ET_TOUCH_MOVED, gfx::Point(20, 20), 2); 564 EXPECT_EQ(2, GetInternalTouchPointsCount()); 565 566 SendTouchEventToInternalHud(ui::ET_TOUCH_RELEASED, gfx::Point(10, 20), 1); 567 EXPECT_EQ(1, GetInternalTouchPointsCount()); 568 569 SendTouchEventToInternalHud(ui::ET_TOUCH_RELEASED, gfx::Point(20, 20), 2); 570 EXPECT_EQ(0, GetInternalTouchPointsCount()); 571 572 // Disabling projection touch HUD shoud remove it without crashing. 573 DisableTouchHudProjection(); 574 EXPECT_EQ(NULL, GetInternalTouchHudProjection()); 575 } 576 577 // Checks if turning off touch HUD projection while touching the screen is 578 // handled correctly. 579 TEST_F(TouchHudProjectionTest, DisableWhileTouching) { 580 SetupSingleDisplay(); 581 EXPECT_EQ(NULL, GetInternalTouchHudProjection()); 582 583 EnableTouchHudProjection(); 584 EXPECT_NE(static_cast<internal::TouchHudProjection*>(NULL), 585 GetInternalTouchHudProjection()); 586 EXPECT_EQ(0, GetInternalTouchPointsCount()); 587 588 SendTouchEventToInternalHud(ui::ET_TOUCH_PRESSED, gfx::Point(10, 10), 1); 589 EXPECT_EQ(1, GetInternalTouchPointsCount()); 590 591 // Disabling projection touch HUD shoud remove it without crashing. 592 DisableTouchHudProjection(); 593 EXPECT_EQ(NULL, GetInternalTouchHudProjection()); 594 } 595 596 } // namespace internal 597 } // namespace ash 598