| // Copyright (c) 2013 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "ash/touch/touch_observer_hud.h" |
| |
| #include "ash/ash_switches.h" |
| #include "ash/display/display_manager.h" |
| #include "ash/root_window_controller.h" |
| #include "ash/screen_util.h" |
| #include "ash/shell.h" |
| #include "ash/test/ash_test_base.h" |
| #include "ash/test/display_manager_test_api.h" |
| #include "ash/touch/touch_hud_debug.h" |
| #include "ash/touch/touch_hud_projection.h" |
| #include "base/command_line.h" |
| #include "base/format_macros.h" |
| #include "base/strings/stringprintf.h" |
| #include "ui/aura/window.h" |
| #include "ui/views/widget/widget.h" |
| |
| namespace ash { |
| |
| class TouchHudTestBase : public test::AshTestBase { |
| public: |
| TouchHudTestBase() {} |
| virtual ~TouchHudTestBase() {} |
| |
| virtual void SetUp() OVERRIDE { |
| test::AshTestBase::SetUp(); |
| |
| // Initialize display infos. They should be initialized after Ash |
| // environment is set up, i.e., after test::AshTestBase::SetUp(). |
| internal_display_id_ = test::DisplayManagerTestApi(GetDisplayManager()). |
| SetFirstDisplayAsInternalDisplay(); |
| external_display_id_ = 10; |
| mirrored_display_id_ = 11; |
| |
| internal_display_info_ = |
| CreateDisplayInfo(internal_display_id_, gfx::Rect(0, 0, 500, 500)); |
| external_display_info_ = |
| CreateDisplayInfo(external_display_id_, gfx::Rect(1, 1, 100, 100)); |
| mirrored_display_info_ = |
| CreateDisplayInfo(mirrored_display_id_, gfx::Rect(0, 0, 100, 100)); |
| } |
| |
| gfx::Display GetPrimaryDisplay() { |
| return Shell::GetScreen()->GetPrimaryDisplay(); |
| } |
| |
| const gfx::Display& GetSecondaryDisplay() { |
| return ScreenUtil::GetSecondaryDisplay(); |
| } |
| |
| void SetupSingleDisplay() { |
| display_info_list_.clear(); |
| display_info_list_.push_back(internal_display_info_); |
| GetDisplayManager()->OnNativeDisplaysChanged(display_info_list_); |
| } |
| |
| void SetupDualDisplays() { |
| display_info_list_.clear(); |
| display_info_list_.push_back(internal_display_info_); |
| display_info_list_.push_back(external_display_info_); |
| GetDisplayManager()->OnNativeDisplaysChanged(display_info_list_); |
| } |
| |
| void SetInternalAsPrimary() { |
| const gfx::Display& internal_display = |
| GetDisplayManager()->GetDisplayForId(internal_display_id_); |
| GetDisplayController()->SetPrimaryDisplay(internal_display); |
| } |
| |
| void SetExternalAsPrimary() { |
| const gfx::Display& external_display = |
| GetDisplayManager()->GetDisplayForId(external_display_id_); |
| GetDisplayController()->SetPrimaryDisplay(external_display); |
| } |
| |
| void MirrorDisplays() { |
| DCHECK_EQ(2U, display_info_list_.size()); |
| DCHECK_EQ(internal_display_id_, display_info_list_[0].id()); |
| DCHECK_EQ(external_display_id_, display_info_list_[1].id()); |
| display_info_list_[1] = mirrored_display_info_; |
| GetDisplayManager()->OnNativeDisplaysChanged(display_info_list_); |
| } |
| |
| void UnmirrorDisplays() { |
| DCHECK_EQ(2U, display_info_list_.size()); |
| DCHECK_EQ(internal_display_id_, display_info_list_[0].id()); |
| DCHECK_EQ(mirrored_display_id_, display_info_list_[1].id()); |
| display_info_list_[1] = external_display_info_; |
| GetDisplayManager()->OnNativeDisplaysChanged(display_info_list_); |
| } |
| |
| void RemoveInternalDisplay() { |
| DCHECK_LT(0U, display_info_list_.size()); |
| DCHECK_EQ(internal_display_id_, display_info_list_[0].id()); |
| display_info_list_.erase(display_info_list_.begin()); |
| GetDisplayManager()->OnNativeDisplaysChanged(display_info_list_); |
| } |
| |
| void RemoveExternalDisplay() { |
| DCHECK_EQ(2U, display_info_list_.size()); |
| display_info_list_.pop_back(); |
| GetDisplayManager()->OnNativeDisplaysChanged(display_info_list_); |
| } |
| |
| void AddInternalDisplay() { |
| DCHECK_EQ(0U, display_info_list_.size()); |
| display_info_list_.push_back(internal_display_info_); |
| GetDisplayManager()->OnNativeDisplaysChanged(display_info_list_); |
| } |
| |
| void AddExternalDisplay() { |
| DCHECK_EQ(1U, display_info_list_.size()); |
| display_info_list_.push_back(external_display_info_); |
| GetDisplayManager()->OnNativeDisplaysChanged(display_info_list_); |
| } |
| |
| int64 internal_display_id() const { |
| return internal_display_id_; |
| } |
| |
| int64 external_display_id() const { |
| return external_display_id_; |
| } |
| |
| protected: |
| DisplayManager* GetDisplayManager() { |
| return Shell::GetInstance()->display_manager(); |
| } |
| |
| DisplayController* GetDisplayController() { |
| return Shell::GetInstance()->display_controller(); |
| } |
| |
| const gfx::Display& GetInternalDisplay() { |
| return GetDisplayManager()->GetDisplayForId(internal_display_id_); |
| } |
| |
| const gfx::Display& GetExternalDisplay() { |
| return GetDisplayManager()->GetDisplayForId(external_display_id_); |
| } |
| |
| aura::Window* GetInternalRootWindow() { |
| return GetDisplayController()->GetRootWindowForDisplayId( |
| internal_display_id_); |
| } |
| |
| aura::Window* GetExternalRootWindow() { |
| return GetDisplayController()->GetRootWindowForDisplayId( |
| external_display_id_); |
| } |
| |
| aura::Window* GetPrimaryRootWindow() { |
| const gfx::Display& display = GetPrimaryDisplay(); |
| return GetDisplayController()->GetRootWindowForDisplayId(display.id()); |
| } |
| |
| aura::Window* GetSecondaryRootWindow() { |
| const gfx::Display& display = GetSecondaryDisplay(); |
| return GetDisplayController()->GetRootWindowForDisplayId(display.id()); |
| } |
| |
| RootWindowController* GetInternalRootController() { |
| aura::Window* root = GetInternalRootWindow(); |
| return GetRootWindowController(root); |
| } |
| |
| RootWindowController* GetExternalRootController() { |
| aura::Window* root = GetExternalRootWindow(); |
| return GetRootWindowController(root); |
| } |
| |
| RootWindowController* GetPrimaryRootController() { |
| aura::Window* root = GetPrimaryRootWindow(); |
| return GetRootWindowController(root); |
| } |
| |
| RootWindowController* GetSecondaryRootController() { |
| aura::Window* root = GetSecondaryRootWindow(); |
| return GetRootWindowController(root); |
| } |
| |
| DisplayInfo CreateDisplayInfo(int64 id, const gfx::Rect& bounds) { |
| DisplayInfo info(id, base::StringPrintf("x-%" PRId64, id), false); |
| info.SetBounds(bounds); |
| return info; |
| } |
| |
| aura::Window* GetRootWindowForTouchHud(TouchObserverHUD* hud) { |
| return hud->root_window_; |
| } |
| |
| views::Widget* GetWidgetForTouchHud(TouchObserverHUD* hud) { |
| return hud->widget_; |
| } |
| |
| int64 internal_display_id_; |
| int64 external_display_id_; |
| int64 mirrored_display_id_; |
| DisplayInfo internal_display_info_; |
| DisplayInfo external_display_info_; |
| DisplayInfo mirrored_display_info_; |
| |
| std::vector<DisplayInfo> display_info_list_; |
| |
| DISALLOW_COPY_AND_ASSIGN(TouchHudTestBase); |
| }; |
| |
| class TouchHudDebugTest : public TouchHudTestBase { |
| public: |
| TouchHudDebugTest() {} |
| virtual ~TouchHudDebugTest() {} |
| |
| virtual void SetUp() OVERRIDE { |
| // Add ash-touch-hud flag to enable debug touch HUD. This flag should be set |
| // before Ash environment is set up, i.e., before TouchHudTestBase::SetUp(). |
| CommandLine::ForCurrentProcess()->AppendSwitch( |
| ash::switches::kAshTouchHud); |
| |
| TouchHudTestBase::SetUp(); |
| } |
| |
| void CheckInternalDisplay() { |
| EXPECT_NE(static_cast<TouchObserverHUD*>(NULL), GetInternalTouchHudDebug()); |
| EXPECT_EQ(internal_display_id(), GetInternalTouchHudDebug()->display_id()); |
| EXPECT_EQ(GetInternalRootWindow(), |
| GetRootWindowForTouchHud(GetInternalTouchHudDebug())); |
| EXPECT_EQ(GetInternalRootWindow(), |
| GetWidgetForTouchHud(GetInternalTouchHudDebug())-> |
| GetNativeView()->GetRootWindow()); |
| EXPECT_EQ(GetInternalDisplay().size(), |
| GetWidgetForTouchHud(GetInternalTouchHudDebug())-> |
| GetWindowBoundsInScreen().size()); |
| } |
| |
| void CheckExternalDisplay() { |
| EXPECT_NE(static_cast<TouchHudDebug*>(NULL), GetExternalTouchHudDebug()); |
| EXPECT_EQ(external_display_id(), GetExternalTouchHudDebug()->display_id()); |
| EXPECT_EQ(GetExternalRootWindow(), |
| GetRootWindowForTouchHud(GetExternalTouchHudDebug())); |
| EXPECT_EQ(GetExternalRootWindow(), |
| GetWidgetForTouchHud(GetExternalTouchHudDebug())-> |
| GetNativeView()->GetRootWindow()); |
| EXPECT_EQ(GetExternalDisplay().size(), |
| GetWidgetForTouchHud(GetExternalTouchHudDebug())-> |
| GetWindowBoundsInScreen().size()); |
| } |
| |
| private: |
| TouchHudDebug* GetInternalTouchHudDebug() { |
| return GetInternalRootController()->touch_hud_debug(); |
| } |
| |
| TouchHudDebug* GetExternalTouchHudDebug() { |
| return GetExternalRootController()->touch_hud_debug(); |
| } |
| |
| TouchHudDebug* GetPrimaryTouchHudDebug() { |
| return GetPrimaryRootController()->touch_hud_debug(); |
| } |
| |
| TouchHudDebug* GetSecondaryTouchHudDebug() { |
| return GetSecondaryRootController()->touch_hud_debug(); |
| } |
| |
| DISALLOW_COPY_AND_ASSIGN(TouchHudDebugTest); |
| }; |
| |
| class TouchHudProjectionTest : public TouchHudTestBase { |
| public: |
| TouchHudProjectionTest() {} |
| virtual ~TouchHudProjectionTest() {} |
| |
| void EnableTouchHudProjection() { |
| Shell::GetInstance()->SetTouchHudProjectionEnabled(true); |
| } |
| |
| void DisableTouchHudProjection() { |
| Shell::GetInstance()->SetTouchHudProjectionEnabled(false); |
| } |
| |
| TouchHudProjection* GetInternalTouchHudProjection() { |
| return GetInternalRootController()->touch_hud_projection(); |
| } |
| |
| int GetInternalTouchPointsCount() { |
| return GetInternalTouchHudProjection()->points_.size(); |
| } |
| |
| void SendTouchEventToInternalHud(ui::EventType type, |
| const gfx::Point& location, |
| int touch_id) { |
| ui::TouchEvent event(type, location, touch_id, event_time); |
| GetInternalTouchHudProjection()->OnTouchEvent(&event); |
| |
| // Advance time for next event. |
| event_time += base::TimeDelta::FromMilliseconds(100); |
| } |
| |
| private: |
| base::TimeDelta event_time; |
| |
| DISALLOW_COPY_AND_ASSIGN(TouchHudProjectionTest); |
| }; |
| |
| // Checks if debug touch HUD is correctly initialized for a single display. |
| TEST_F(TouchHudDebugTest, SingleDisplay) { |
| // Setup a single display setting. |
| SetupSingleDisplay(); |
| |
| // Check if touch HUD is set correctly and associated with appropriate |
| // display. |
| CheckInternalDisplay(); |
| } |
| |
| // Checks if debug touch HUDs are correctly initialized for two displays. |
| TEST_F(TouchHudDebugTest, DualDisplays) { |
| if (!SupportsMultipleDisplays()) |
| return; |
| |
| // Setup a dual display setting. |
| SetupDualDisplays(); |
| |
| // Check if touch HUDs are set correctly and associated with appropriate |
| // displays. |
| CheckInternalDisplay(); |
| CheckExternalDisplay(); |
| } |
| |
| // Checks if debug touch HUDs are correctly handled when primary display is |
| // changed. |
| TEST_F(TouchHudDebugTest, SwapPrimaryDisplay) { |
| if (!SupportsMultipleDisplays()) |
| return; |
| |
| // Setup a dual display setting. |
| SetupDualDisplays(); |
| |
| // Set the primary display to the external one. |
| SetExternalAsPrimary(); |
| |
| // Check if displays' touch HUDs are not swapped as root windows are. |
| EXPECT_EQ(external_display_id(), GetPrimaryDisplay().id()); |
| EXPECT_EQ(internal_display_id(), GetSecondaryDisplay().id()); |
| CheckInternalDisplay(); |
| CheckExternalDisplay(); |
| |
| // Set the primary display back to the internal one. |
| SetInternalAsPrimary(); |
| |
| // Check if displays' touch HUDs are not swapped back as root windows are. |
| EXPECT_EQ(internal_display_id(), GetPrimaryDisplay().id()); |
| EXPECT_EQ(external_display_id(), GetSecondaryDisplay().id()); |
| CheckInternalDisplay(); |
| CheckExternalDisplay(); |
| } |
| |
| // Checks if debug touch HUDs are correctly handled when displays are mirrored. |
| TEST_F(TouchHudDebugTest, MirrorDisplays) { |
| if (!SupportsMultipleDisplays()) |
| return; |
| |
| // Setup a dual display setting. |
| SetupDualDisplays(); |
| |
| // Mirror displays. |
| MirrorDisplays(); |
| |
| // Check if the internal display is intact. |
| EXPECT_EQ(internal_display_id(), GetPrimaryDisplay().id()); |
| CheckInternalDisplay(); |
| |
| // Unmirror displays. |
| UnmirrorDisplays(); |
| |
| // Check if external display is added back correctly. |
| EXPECT_EQ(internal_display_id(), GetPrimaryDisplay().id()); |
| EXPECT_EQ(external_display_id(), GetSecondaryDisplay().id()); |
| CheckInternalDisplay(); |
| CheckExternalDisplay(); |
| } |
| |
| // Checks if debug touch HUDs are correctly handled when displays are mirrored |
| // after setting the external display as the primary one. |
| TEST_F(TouchHudDebugTest, SwapPrimaryThenMirrorDisplays) { |
| if (!SupportsMultipleDisplays()) |
| return; |
| |
| // Setup a dual display setting. |
| SetupDualDisplays(); |
| |
| // Set the primary display to the external one. |
| SetExternalAsPrimary(); |
| |
| // Mirror displays. |
| MirrorDisplays(); |
| |
| // Check if the internal display is set as the primary one. |
| EXPECT_EQ(internal_display_id(), GetPrimaryDisplay().id()); |
| CheckInternalDisplay(); |
| |
| // Unmirror displays. |
| UnmirrorDisplays(); |
| |
| // Check if the external display is added back as the primary display and |
| // touch HUDs are set correctly. |
| EXPECT_EQ(external_display_id(), GetPrimaryDisplay().id()); |
| EXPECT_EQ(internal_display_id(), GetSecondaryDisplay().id()); |
| CheckInternalDisplay(); |
| CheckExternalDisplay(); |
| } |
| |
| // Checks if debug touch HUDs are correctly handled when the external display, |
| // which is the secondary one, is removed. |
| TEST_F(TouchHudDebugTest, RemoveSecondaryDisplay) { |
| if (!SupportsMultipleDisplays()) |
| return; |
| |
| // Setup a dual display setting. |
| SetupDualDisplays(); |
| |
| // Remove external display which is the secondary one. |
| RemoveExternalDisplay(); |
| |
| // Check if the internal display is intact. |
| EXPECT_EQ(internal_display_id(), GetPrimaryDisplay().id()); |
| CheckInternalDisplay(); |
| |
| // Add external display back. |
| AddExternalDisplay(); |
| |
| // Check if displays' touch HUDs are set correctly. |
| EXPECT_EQ(internal_display_id(), GetPrimaryDisplay().id()); |
| EXPECT_EQ(external_display_id(), GetSecondaryDisplay().id()); |
| CheckInternalDisplay(); |
| CheckExternalDisplay(); |
| } |
| |
| // Checks if debug touch HUDs are correctly handled when the external display, |
| // which is set as the primary display, is removed. |
| TEST_F(TouchHudDebugTest, RemovePrimaryDisplay) { |
| if (!SupportsMultipleDisplays()) |
| return; |
| |
| // Setup a dual display setting. |
| SetupDualDisplays(); |
| |
| // Set the primary display to the external one. |
| SetExternalAsPrimary(); |
| |
| // Remove the external display which is the primary display. |
| RemoveExternalDisplay(); |
| |
| // Check if the internal display is set as the primary one. |
| EXPECT_EQ(internal_display_id(), GetPrimaryDisplay().id()); |
| CheckInternalDisplay(); |
| |
| // Add the external display back. |
| AddExternalDisplay(); |
| |
| // Check if the external display is set as primary and touch HUDs are set |
| // correctly. |
| EXPECT_EQ(external_display_id(), GetPrimaryDisplay().id()); |
| EXPECT_EQ(internal_display_id(), GetSecondaryDisplay().id()); |
| CheckInternalDisplay(); |
| CheckExternalDisplay(); |
| } |
| |
| // Checks if debug touch HUDs are correctly handled when all displays are |
| // removed. |
| TEST_F(TouchHudDebugTest, Headless) { |
| if (!SupportsMultipleDisplays()) |
| return; |
| |
| // Setup a single display setting. |
| SetupSingleDisplay(); |
| |
| // Remove the only display which is the internal one. |
| RemoveInternalDisplay(); |
| |
| // Add the internal display back. |
| AddInternalDisplay(); |
| |
| // Check if the display's touch HUD is set correctly. |
| EXPECT_EQ(internal_display_id(), GetPrimaryDisplay().id()); |
| CheckInternalDisplay(); |
| } |
| |
| // Checks projection touch HUD with a sequence of touch-pressed, touch-moved, |
| // and touch-released events. |
| TEST_F(TouchHudProjectionTest, TouchMoveRelease) { |
| SetupSingleDisplay(); |
| EXPECT_EQ(NULL, GetInternalTouchHudProjection()); |
| |
| EnableTouchHudProjection(); |
| EXPECT_NE(static_cast<TouchHudProjection*>(NULL), |
| GetInternalTouchHudProjection()); |
| EXPECT_EQ(0, GetInternalTouchPointsCount()); |
| |
| SendTouchEventToInternalHud(ui::ET_TOUCH_PRESSED, gfx::Point(10, 10), 1); |
| EXPECT_EQ(1, GetInternalTouchPointsCount()); |
| |
| SendTouchEventToInternalHud(ui::ET_TOUCH_MOVED, gfx::Point(10, 20), 1); |
| EXPECT_EQ(1, GetInternalTouchPointsCount()); |
| |
| SendTouchEventToInternalHud(ui::ET_TOUCH_RELEASED, gfx::Point(10, 20), 1); |
| EXPECT_EQ(0, GetInternalTouchPointsCount()); |
| |
| // Disabling projection touch HUD shoud remove it without crashing. |
| DisableTouchHudProjection(); |
| EXPECT_EQ(NULL, GetInternalTouchHudProjection()); |
| } |
| |
| // Checks projection touch HUD with a sequence of touch-pressed, touch-moved, |
| // and touch-cancelled events. |
| TEST_F(TouchHudProjectionTest, TouchMoveCancel) { |
| SetupSingleDisplay(); |
| EXPECT_EQ(NULL, GetInternalTouchHudProjection()); |
| |
| EnableTouchHudProjection(); |
| EXPECT_NE(static_cast<TouchHudProjection*>(NULL), |
| GetInternalTouchHudProjection()); |
| EXPECT_EQ(0, GetInternalTouchPointsCount()); |
| |
| SendTouchEventToInternalHud(ui::ET_TOUCH_PRESSED, gfx::Point(10, 10), 1); |
| EXPECT_EQ(1, GetInternalTouchPointsCount()); |
| |
| SendTouchEventToInternalHud(ui::ET_TOUCH_MOVED, gfx::Point(10, 20), 1); |
| EXPECT_EQ(1, GetInternalTouchPointsCount()); |
| |
| SendTouchEventToInternalHud(ui::ET_TOUCH_CANCELLED, gfx::Point(10, 20), 1); |
| EXPECT_EQ(0, GetInternalTouchPointsCount()); |
| |
| // Disabling projection touch HUD shoud remove it without crashing. |
| DisableTouchHudProjection(); |
| EXPECT_EQ(NULL, GetInternalTouchHudProjection()); |
| } |
| |
| // Checks projection touch HUD with two simultaneous touches. |
| TEST_F(TouchHudProjectionTest, DoubleTouch) { |
| SetupSingleDisplay(); |
| EXPECT_EQ(NULL, GetInternalTouchHudProjection()); |
| |
| EnableTouchHudProjection(); |
| EXPECT_NE(static_cast<TouchHudProjection*>(NULL), |
| GetInternalTouchHudProjection()); |
| EXPECT_EQ(0, GetInternalTouchPointsCount()); |
| |
| SendTouchEventToInternalHud(ui::ET_TOUCH_PRESSED, gfx::Point(10, 10), 1); |
| EXPECT_EQ(1, GetInternalTouchPointsCount()); |
| |
| SendTouchEventToInternalHud(ui::ET_TOUCH_PRESSED, gfx::Point(20, 10), 2); |
| EXPECT_EQ(2, GetInternalTouchPointsCount()); |
| |
| SendTouchEventToInternalHud(ui::ET_TOUCH_MOVED, gfx::Point(10, 20), 1); |
| EXPECT_EQ(2, GetInternalTouchPointsCount()); |
| |
| SendTouchEventToInternalHud(ui::ET_TOUCH_MOVED, gfx::Point(20, 20), 2); |
| EXPECT_EQ(2, GetInternalTouchPointsCount()); |
| |
| SendTouchEventToInternalHud(ui::ET_TOUCH_RELEASED, gfx::Point(10, 20), 1); |
| EXPECT_EQ(1, GetInternalTouchPointsCount()); |
| |
| SendTouchEventToInternalHud(ui::ET_TOUCH_RELEASED, gfx::Point(20, 20), 2); |
| EXPECT_EQ(0, GetInternalTouchPointsCount()); |
| |
| // Disabling projection touch HUD shoud remove it without crashing. |
| DisableTouchHudProjection(); |
| EXPECT_EQ(NULL, GetInternalTouchHudProjection()); |
| } |
| |
| // Checks if turning off touch HUD projection while touching the screen is |
| // handled correctly. |
| TEST_F(TouchHudProjectionTest, DisableWhileTouching) { |
| SetupSingleDisplay(); |
| EXPECT_EQ(NULL, GetInternalTouchHudProjection()); |
| |
| EnableTouchHudProjection(); |
| EXPECT_NE(static_cast<TouchHudProjection*>(NULL), |
| GetInternalTouchHudProjection()); |
| EXPECT_EQ(0, GetInternalTouchPointsCount()); |
| |
| SendTouchEventToInternalHud(ui::ET_TOUCH_PRESSED, gfx::Point(10, 10), 1); |
| EXPECT_EQ(1, GetInternalTouchPointsCount()); |
| |
| // Disabling projection touch HUD shoud remove it without crashing. |
| DisableTouchHudProjection(); |
| EXPECT_EQ(NULL, GetInternalTouchHudProjection()); |
| } |
| |
| } // namespace ash |