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_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" 20 #include "ui/views/widget/widget.h" 21 22 namespace ash { 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 ScreenUtil::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 RootWindowController* GetInternalRootController() { 167 aura::Window* root = GetInternalRootWindow(); 168 return GetRootWindowController(root); 169 } 170 171 RootWindowController* GetExternalRootController() { 172 aura::Window* root = GetExternalRootWindow(); 173 return GetRootWindowController(root); 174 } 175 176 RootWindowController* GetPrimaryRootController() { 177 aura::Window* root = GetPrimaryRootWindow(); 178 return GetRootWindowController(root); 179 } 180 181 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(TouchObserverHUD* hud) { 193 return hud->root_window_; 194 } 195 196 views::Widget* GetWidgetForTouchHud(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<TouchObserverHUD*>(NULL), GetInternalTouchHudDebug()); 228 EXPECT_EQ(internal_display_id(), GetInternalTouchHudDebug()->display_id()); 229 EXPECT_EQ(GetInternalRootWindow(), 230 GetRootWindowForTouchHud(GetInternalTouchHudDebug())); 231 EXPECT_EQ(GetInternalRootWindow(), 232 GetWidgetForTouchHud(GetInternalTouchHudDebug())-> 233 GetNativeView()->GetRootWindow()); 234 EXPECT_EQ(GetInternalDisplay().size(), 235 GetWidgetForTouchHud(GetInternalTouchHudDebug())-> 236 GetWindowBoundsInScreen().size()); 237 } 238 239 void CheckExternalDisplay() { 240 EXPECT_NE(static_cast<TouchHudDebug*>(NULL), GetExternalTouchHudDebug()); 241 EXPECT_EQ(external_display_id(), GetExternalTouchHudDebug()->display_id()); 242 EXPECT_EQ(GetExternalRootWindow(), 243 GetRootWindowForTouchHud(GetExternalTouchHudDebug())); 244 EXPECT_EQ(GetExternalRootWindow(), 245 GetWidgetForTouchHud(GetExternalTouchHudDebug())-> 246 GetNativeView()->GetRootWindow()); 247 EXPECT_EQ(GetExternalDisplay().size(), 248 GetWidgetForTouchHud(GetExternalTouchHudDebug())-> 249 GetWindowBoundsInScreen().size()); 250 } 251 252 private: 253 TouchHudDebug* GetInternalTouchHudDebug() { 254 return GetInternalRootController()->touch_hud_debug(); 255 } 256 257 TouchHudDebug* GetExternalTouchHudDebug() { 258 return GetExternalRootController()->touch_hud_debug(); 259 } 260 261 TouchHudDebug* GetPrimaryTouchHudDebug() { 262 return GetPrimaryRootController()->touch_hud_debug(); 263 } 264 265 TouchHudDebug* GetSecondaryTouchHudDebug() { 266 return GetSecondaryRootController()->touch_hud_debug(); 267 } 268 269 DISALLOW_COPY_AND_ASSIGN(TouchHudDebugTest); 270 }; 271 272 class TouchHudProjectionTest : public TouchHudTestBase { 273 public: 274 TouchHudProjectionTest() {} 275 virtual ~TouchHudProjectionTest() {} 276 277 void EnableTouchHudProjection() { 278 Shell::GetInstance()->SetTouchHudProjectionEnabled(true); 279 } 280 281 void DisableTouchHudProjection() { 282 Shell::GetInstance()->SetTouchHudProjectionEnabled(false); 283 } 284 285 TouchHudProjection* GetInternalTouchHudProjection() { 286 return GetInternalRootController()->touch_hud_projection(); 287 } 288 289 int GetInternalTouchPointsCount() { 290 return GetInternalTouchHudProjection()->points_.size(); 291 } 292 293 void SendTouchEventToInternalHud(ui::EventType type, 294 const gfx::Point& location, 295 int touch_id) { 296 ui::TouchEvent event(type, location, touch_id, event_time); 297 GetInternalTouchHudProjection()->OnTouchEvent(&event); 298 299 // Advance time for next event. 300 event_time += base::TimeDelta::FromMilliseconds(100); 301 } 302 303 private: 304 base::TimeDelta event_time; 305 306 DISALLOW_COPY_AND_ASSIGN(TouchHudProjectionTest); 307 }; 308 309 // Checks if debug touch HUD is correctly initialized for a single display. 310 TEST_F(TouchHudDebugTest, SingleDisplay) { 311 // Setup a single display setting. 312 SetupSingleDisplay(); 313 314 // Check if touch HUD is set correctly and associated with appropriate 315 // display. 316 CheckInternalDisplay(); 317 } 318 319 // Checks if debug touch HUDs are correctly initialized for two displays. 320 TEST_F(TouchHudDebugTest, DualDisplays) { 321 if (!SupportsMultipleDisplays()) 322 return; 323 324 // Setup a dual display setting. 325 SetupDualDisplays(); 326 327 // Check if touch HUDs are set correctly and associated with appropriate 328 // displays. 329 CheckInternalDisplay(); 330 CheckExternalDisplay(); 331 } 332 333 // Checks if debug touch HUDs are correctly handled when primary display is 334 // changed. 335 TEST_F(TouchHudDebugTest, SwapPrimaryDisplay) { 336 if (!SupportsMultipleDisplays()) 337 return; 338 339 // Setup a dual display setting. 340 SetupDualDisplays(); 341 342 // Set the primary display to the external one. 343 SetExternalAsPrimary(); 344 345 // Check if displays' touch HUDs are not swapped as root windows are. 346 EXPECT_EQ(external_display_id(), GetPrimaryDisplay().id()); 347 EXPECT_EQ(internal_display_id(), GetSecondaryDisplay().id()); 348 CheckInternalDisplay(); 349 CheckExternalDisplay(); 350 351 // Set the primary display back to the internal one. 352 SetInternalAsPrimary(); 353 354 // Check if displays' touch HUDs are not swapped back as root windows are. 355 EXPECT_EQ(internal_display_id(), GetPrimaryDisplay().id()); 356 EXPECT_EQ(external_display_id(), GetSecondaryDisplay().id()); 357 CheckInternalDisplay(); 358 CheckExternalDisplay(); 359 } 360 361 // Checks if debug touch HUDs are correctly handled when displays are mirrored. 362 TEST_F(TouchHudDebugTest, MirrorDisplays) { 363 if (!SupportsMultipleDisplays()) 364 return; 365 366 // Setup a dual display setting. 367 SetupDualDisplays(); 368 369 // Mirror displays. 370 MirrorDisplays(); 371 372 // Check if the internal display is intact. 373 EXPECT_EQ(internal_display_id(), GetPrimaryDisplay().id()); 374 CheckInternalDisplay(); 375 376 // Unmirror displays. 377 UnmirrorDisplays(); 378 379 // Check if external display is added back correctly. 380 EXPECT_EQ(internal_display_id(), GetPrimaryDisplay().id()); 381 EXPECT_EQ(external_display_id(), GetSecondaryDisplay().id()); 382 CheckInternalDisplay(); 383 CheckExternalDisplay(); 384 } 385 386 // Checks if debug touch HUDs are correctly handled when displays are mirrored 387 // after setting the external display as the primary one. 388 TEST_F(TouchHudDebugTest, SwapPrimaryThenMirrorDisplays) { 389 if (!SupportsMultipleDisplays()) 390 return; 391 392 // Setup a dual display setting. 393 SetupDualDisplays(); 394 395 // Set the primary display to the external one. 396 SetExternalAsPrimary(); 397 398 // Mirror displays. 399 MirrorDisplays(); 400 401 // Check if the internal display is set as the primary one. 402 EXPECT_EQ(internal_display_id(), GetPrimaryDisplay().id()); 403 CheckInternalDisplay(); 404 405 // Unmirror displays. 406 UnmirrorDisplays(); 407 408 // Check if the external display is added back as the primary display and 409 // touch HUDs are set correctly. 410 EXPECT_EQ(external_display_id(), GetPrimaryDisplay().id()); 411 EXPECT_EQ(internal_display_id(), GetSecondaryDisplay().id()); 412 CheckInternalDisplay(); 413 CheckExternalDisplay(); 414 } 415 416 // Checks if debug touch HUDs are correctly handled when the external display, 417 // which is the secondary one, is removed. 418 TEST_F(TouchHudDebugTest, RemoveSecondaryDisplay) { 419 if (!SupportsMultipleDisplays()) 420 return; 421 422 // Setup a dual display setting. 423 SetupDualDisplays(); 424 425 // Remove external display which is the secondary one. 426 RemoveExternalDisplay(); 427 428 // Check if the internal display is intact. 429 EXPECT_EQ(internal_display_id(), GetPrimaryDisplay().id()); 430 CheckInternalDisplay(); 431 432 // Add external display back. 433 AddExternalDisplay(); 434 435 // Check if displays' touch HUDs are set correctly. 436 EXPECT_EQ(internal_display_id(), GetPrimaryDisplay().id()); 437 EXPECT_EQ(external_display_id(), GetSecondaryDisplay().id()); 438 CheckInternalDisplay(); 439 CheckExternalDisplay(); 440 } 441 442 // Checks if debug touch HUDs are correctly handled when the external display, 443 // which is set as the primary display, is removed. 444 TEST_F(TouchHudDebugTest, RemovePrimaryDisplay) { 445 if (!SupportsMultipleDisplays()) 446 return; 447 448 // Setup a dual display setting. 449 SetupDualDisplays(); 450 451 // Set the primary display to the external one. 452 SetExternalAsPrimary(); 453 454 // Remove the external display which is the primary display. 455 RemoveExternalDisplay(); 456 457 // Check if the internal display is set as the primary one. 458 EXPECT_EQ(internal_display_id(), GetPrimaryDisplay().id()); 459 CheckInternalDisplay(); 460 461 // Add the external display back. 462 AddExternalDisplay(); 463 464 // Check if the external display is set as primary and touch HUDs are set 465 // correctly. 466 EXPECT_EQ(external_display_id(), GetPrimaryDisplay().id()); 467 EXPECT_EQ(internal_display_id(), GetSecondaryDisplay().id()); 468 CheckInternalDisplay(); 469 CheckExternalDisplay(); 470 } 471 472 // Checks if debug touch HUDs are correctly handled when all displays are 473 // removed. 474 TEST_F(TouchHudDebugTest, Headless) { 475 if (!SupportsMultipleDisplays()) 476 return; 477 478 // Setup a single display setting. 479 SetupSingleDisplay(); 480 481 // Remove the only display which is the internal one. 482 RemoveInternalDisplay(); 483 484 // Add the internal display back. 485 AddInternalDisplay(); 486 487 // Check if the display's touch HUD is set correctly. 488 EXPECT_EQ(internal_display_id(), GetPrimaryDisplay().id()); 489 CheckInternalDisplay(); 490 } 491 492 // Checks projection touch HUD with a sequence of touch-pressed, touch-moved, 493 // and touch-released events. 494 TEST_F(TouchHudProjectionTest, TouchMoveRelease) { 495 SetupSingleDisplay(); 496 EXPECT_EQ(NULL, GetInternalTouchHudProjection()); 497 498 EnableTouchHudProjection(); 499 EXPECT_NE(static_cast<TouchHudProjection*>(NULL), 500 GetInternalTouchHudProjection()); 501 EXPECT_EQ(0, GetInternalTouchPointsCount()); 502 503 SendTouchEventToInternalHud(ui::ET_TOUCH_PRESSED, gfx::Point(10, 10), 1); 504 EXPECT_EQ(1, GetInternalTouchPointsCount()); 505 506 SendTouchEventToInternalHud(ui::ET_TOUCH_MOVED, gfx::Point(10, 20), 1); 507 EXPECT_EQ(1, GetInternalTouchPointsCount()); 508 509 SendTouchEventToInternalHud(ui::ET_TOUCH_RELEASED, gfx::Point(10, 20), 1); 510 EXPECT_EQ(0, GetInternalTouchPointsCount()); 511 512 // Disabling projection touch HUD shoud remove it without crashing. 513 DisableTouchHudProjection(); 514 EXPECT_EQ(NULL, GetInternalTouchHudProjection()); 515 } 516 517 // Checks projection touch HUD with a sequence of touch-pressed, touch-moved, 518 // and touch-cancelled events. 519 TEST_F(TouchHudProjectionTest, TouchMoveCancel) { 520 SetupSingleDisplay(); 521 EXPECT_EQ(NULL, GetInternalTouchHudProjection()); 522 523 EnableTouchHudProjection(); 524 EXPECT_NE(static_cast<TouchHudProjection*>(NULL), 525 GetInternalTouchHudProjection()); 526 EXPECT_EQ(0, GetInternalTouchPointsCount()); 527 528 SendTouchEventToInternalHud(ui::ET_TOUCH_PRESSED, gfx::Point(10, 10), 1); 529 EXPECT_EQ(1, GetInternalTouchPointsCount()); 530 531 SendTouchEventToInternalHud(ui::ET_TOUCH_MOVED, gfx::Point(10, 20), 1); 532 EXPECT_EQ(1, GetInternalTouchPointsCount()); 533 534 SendTouchEventToInternalHud(ui::ET_TOUCH_CANCELLED, gfx::Point(10, 20), 1); 535 EXPECT_EQ(0, GetInternalTouchPointsCount()); 536 537 // Disabling projection touch HUD shoud remove it without crashing. 538 DisableTouchHudProjection(); 539 EXPECT_EQ(NULL, GetInternalTouchHudProjection()); 540 } 541 542 // Checks projection touch HUD with two simultaneous touches. 543 TEST_F(TouchHudProjectionTest, DoubleTouch) { 544 SetupSingleDisplay(); 545 EXPECT_EQ(NULL, GetInternalTouchHudProjection()); 546 547 EnableTouchHudProjection(); 548 EXPECT_NE(static_cast<TouchHudProjection*>(NULL), 549 GetInternalTouchHudProjection()); 550 EXPECT_EQ(0, GetInternalTouchPointsCount()); 551 552 SendTouchEventToInternalHud(ui::ET_TOUCH_PRESSED, gfx::Point(10, 10), 1); 553 EXPECT_EQ(1, GetInternalTouchPointsCount()); 554 555 SendTouchEventToInternalHud(ui::ET_TOUCH_PRESSED, gfx::Point(20, 10), 2); 556 EXPECT_EQ(2, GetInternalTouchPointsCount()); 557 558 SendTouchEventToInternalHud(ui::ET_TOUCH_MOVED, gfx::Point(10, 20), 1); 559 EXPECT_EQ(2, GetInternalTouchPointsCount()); 560 561 SendTouchEventToInternalHud(ui::ET_TOUCH_MOVED, gfx::Point(20, 20), 2); 562 EXPECT_EQ(2, GetInternalTouchPointsCount()); 563 564 SendTouchEventToInternalHud(ui::ET_TOUCH_RELEASED, gfx::Point(10, 20), 1); 565 EXPECT_EQ(1, GetInternalTouchPointsCount()); 566 567 SendTouchEventToInternalHud(ui::ET_TOUCH_RELEASED, gfx::Point(20, 20), 2); 568 EXPECT_EQ(0, GetInternalTouchPointsCount()); 569 570 // Disabling projection touch HUD shoud remove it without crashing. 571 DisableTouchHudProjection(); 572 EXPECT_EQ(NULL, GetInternalTouchHudProjection()); 573 } 574 575 // Checks if turning off touch HUD projection while touching the screen is 576 // handled correctly. 577 TEST_F(TouchHudProjectionTest, DisableWhileTouching) { 578 SetupSingleDisplay(); 579 EXPECT_EQ(NULL, GetInternalTouchHudProjection()); 580 581 EnableTouchHudProjection(); 582 EXPECT_NE(static_cast<TouchHudProjection*>(NULL), 583 GetInternalTouchHudProjection()); 584 EXPECT_EQ(0, GetInternalTouchPointsCount()); 585 586 SendTouchEventToInternalHud(ui::ET_TOUCH_PRESSED, gfx::Point(10, 10), 1); 587 EXPECT_EQ(1, GetInternalTouchPointsCount()); 588 589 // Disabling projection touch HUD shoud remove it without crashing. 590 DisableTouchHudProjection(); 591 EXPECT_EQ(NULL, GetInternalTouchHudProjection()); 592 } 593 594 } // namespace ash 595