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