| // 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/display/mirror_window_controller.h" |
| |
| #include "ash/common/ash_switches.h" |
| #include "ash/display/display_manager.h" |
| #include "ash/display/window_tree_host_manager.h" |
| #include "ash/screen_util.h" |
| #include "ash/shell.h" |
| #include "ash/test/ash_test_base.h" |
| #include "ash/test/cursor_manager_test_api.h" |
| #include "ash/test/display_manager_test_api.h" |
| #include "ash/test/mirror_window_test_api.h" |
| #include "base/command_line.h" |
| #include "base/strings/stringprintf.h" |
| #include "ui/aura/env.h" |
| #include "ui/aura/test/test_window_delegate.h" |
| #include "ui/aura/test/test_windows.h" |
| #include "ui/aura/window.h" |
| #include "ui/aura/window_event_dispatcher.h" |
| #include "ui/base/hit_test.h" |
| #include "ui/events/test/event_generator.h" |
| |
| namespace ash { |
| |
| namespace { |
| DisplayInfo CreateDisplayInfo(int64_t id, const gfx::Rect& bounds) { |
| DisplayInfo info(id, base::StringPrintf("x-%d", static_cast<int>(id)), false); |
| info.SetBounds(bounds); |
| return info; |
| } |
| |
| class MirrorOnBootTest : public test::AshTestBase { |
| public: |
| MirrorOnBootTest() {} |
| ~MirrorOnBootTest() override {} |
| |
| void SetUp() override { |
| base::CommandLine::ForCurrentProcess()->AppendSwitchASCII( |
| switches::kAshHostWindowBounds, "1+1-300x300,1+301-300x300"); |
| base::CommandLine::ForCurrentProcess()->AppendSwitch( |
| switches::kAshEnableSoftwareMirroring); |
| test::AshTestBase::SetUp(); |
| } |
| void TearDown() override { test::AshTestBase::TearDown(); } |
| |
| private: |
| DISALLOW_COPY_AND_ASSIGN(MirrorOnBootTest); |
| }; |
| } |
| |
| typedef test::AshTestBase MirrorWindowControllerTest; |
| |
| #if defined(OS_WIN) |
| // Software mirroring does not work on win. |
| #define MAYBE_MirrorCursorBasic DISABLED_MirrorCursorBasic |
| #define MAYBE_MirrorCursorLocations DISABLED_MirrorCursorLocations |
| #define MAYBE_MirrorCursorMoveOnEnter DISABLED_MirrorCursorMoveOnEnter |
| #define MAYBE_MirrorCursorRotate DISABLED_MirrorCursorRotate |
| #define MAYBE_DockMode DISABLED_DockMode |
| #define MAYBE_MirrorOnBoot DISABLED_MirrorOnBoot |
| #else |
| #define MAYBE_MirrorCursorBasic MirrorCursorBasic |
| #define MAYBE_MirrorCursorLocations MirrorCursorLocations |
| #define MAYBE_MirrorCursorMoveOnEnter MirrorCursorMoveOnEnter |
| #define MAYBE_MirrorCursorRotate MirrorCursorRotate |
| #define MAYBE_DockMode DockMode |
| #define MAYBE_MirrorOnBoot MirrorOnBoot |
| #endif |
| |
| TEST_F(MirrorWindowControllerTest, MAYBE_MirrorCursorBasic) { |
| test::MirrorWindowTestApi test_api; |
| aura::test::TestWindowDelegate test_window_delegate; |
| test_window_delegate.set_window_component(HTTOP); |
| |
| DisplayManager* display_manager = Shell::GetInstance()->display_manager(); |
| display_manager->SetMultiDisplayMode(DisplayManager::MIRRORING); |
| UpdateDisplay("400x400,400x400"); |
| aura::Window* root = Shell::GetInstance()->GetPrimaryRootWindow(); |
| std::unique_ptr<aura::Window> window(aura::test::CreateTestWindowWithDelegate( |
| &test_window_delegate, 0, gfx::Rect(50, 50, 100, 100), root)); |
| window->Show(); |
| window->SetName("foo"); |
| |
| EXPECT_TRUE(test_api.GetCursorWindow()); |
| EXPECT_EQ("50,50 100x100", window->bounds().ToString()); |
| |
| ui::test::EventGenerator generator(root); |
| generator.MoveMouseTo(10, 10); |
| |
| // Test if cursor movement is propertly reflected in mirror window. |
| EXPECT_EQ("4,4", test_api.GetCursorHotPoint().ToString()); |
| EXPECT_EQ("10,10", |
| test_api.GetCursorHotPointLocationInRootWindow().ToString()); |
| EXPECT_EQ(ui::kCursorNull, test_api.GetCurrentCursorType()); |
| EXPECT_TRUE(test_api.GetCursorWindow()->IsVisible()); |
| |
| // Test if cursor type change is propertly reflected in mirror window. |
| generator.MoveMouseTo(100, 100); |
| EXPECT_EQ("100,100", |
| test_api.GetCursorHotPointLocationInRootWindow().ToString()); |
| EXPECT_EQ(ui::kCursorNorthResize, test_api.GetCurrentCursorType()); |
| |
| // Test if visibility change is propertly reflected in mirror window. |
| // A key event hides cursor. |
| generator.PressKey(ui::VKEY_A, 0); |
| generator.ReleaseKey(ui::VKEY_A, 0); |
| EXPECT_FALSE(test_api.GetCursorWindow()->IsVisible()); |
| |
| // Mouse event makes it visible again. |
| generator.MoveMouseTo(300, 300); |
| EXPECT_EQ("300,300", |
| test_api.GetCursorHotPointLocationInRootWindow().ToString()); |
| EXPECT_EQ(ui::kCursorNull, test_api.GetCurrentCursorType()); |
| EXPECT_TRUE(test_api.GetCursorWindow()->IsVisible()); |
| } |
| |
| TEST_F(MirrorWindowControllerTest, MAYBE_MirrorCursorRotate) { |
| test::MirrorWindowTestApi test_api; |
| aura::test::TestWindowDelegate test_window_delegate; |
| test_window_delegate.set_window_component(HTTOP); |
| |
| DisplayManager* display_manager = Shell::GetInstance()->display_manager(); |
| display_manager->SetMultiDisplayMode(DisplayManager::MIRRORING); |
| UpdateDisplay("400x400,400x400"); |
| aura::Window* root = Shell::GetInstance()->GetPrimaryRootWindow(); |
| std::unique_ptr<aura::Window> window(aura::test::CreateTestWindowWithDelegate( |
| &test_window_delegate, 0, gfx::Rect(50, 50, 100, 100), root)); |
| window->Show(); |
| window->SetName("foo"); |
| |
| EXPECT_TRUE(test_api.GetCursorWindow()); |
| EXPECT_EQ("50,50 100x100", window->bounds().ToString()); |
| |
| ui::test::EventGenerator generator(root); |
| generator.MoveMouseToInHost(100, 100); |
| |
| // Test if cursor movement is propertly reflected in mirror window. |
| EXPECT_EQ("11,12", test_api.GetCursorHotPoint().ToString()); |
| EXPECT_EQ("100,100", |
| test_api.GetCursorHotPointLocationInRootWindow().ToString()); |
| EXPECT_EQ(ui::kCursorNorthResize, test_api.GetCurrentCursorType()); |
| |
| UpdateDisplay("400x400/r,400x400"); // 90 degrees. |
| generator.MoveMouseToInHost(300, 100); |
| EXPECT_EQ(ui::kCursorNorthResize, test_api.GetCurrentCursorType()); |
| // The size of cursor image is 25x25, so the rotated hot point must |
| // be (25-12, 11). |
| EXPECT_EQ("13,11", test_api.GetCursorHotPoint().ToString()); |
| EXPECT_EQ("300,100", |
| test_api.GetCursorHotPointLocationInRootWindow().ToString()); |
| |
| UpdateDisplay("400x400/u,400x400"); // 180 degrees. |
| generator.MoveMouseToInHost(300, 300); |
| EXPECT_EQ(ui::kCursorNorthResize, test_api.GetCurrentCursorType()); |
| // Rotated hot point must be (25-11, 25-12). |
| EXPECT_EQ("14,13", test_api.GetCursorHotPoint().ToString()); |
| EXPECT_EQ("300,300", |
| test_api.GetCursorHotPointLocationInRootWindow().ToString()); |
| |
| UpdateDisplay("400x400/l,400x400"); // 270 degrees. |
| generator.MoveMouseToInHost(100, 300); |
| EXPECT_EQ(ui::kCursorNorthResize, test_api.GetCurrentCursorType()); |
| // Rotated hot point must be (12, 25-11). |
| EXPECT_EQ("12,14", test_api.GetCursorHotPoint().ToString()); |
| EXPECT_EQ("100,300", |
| test_api.GetCursorHotPointLocationInRootWindow().ToString()); |
| } |
| |
| // Make sure that the mirror cursor's location is same as |
| // the source display's host location in the mirror root window's |
| // coordinates. |
| TEST_F(MirrorWindowControllerTest, MAYBE_MirrorCursorLocations) { |
| test::MirrorWindowTestApi test_api; |
| DisplayManager* display_manager = Shell::GetInstance()->display_manager(); |
| display_manager->SetMultiDisplayMode(DisplayManager::MIRRORING); |
| |
| // Test with device scale factor. |
| UpdateDisplay("400x600*2,400x600"); |
| |
| aura::Window* root = Shell::GetInstance()->GetPrimaryRootWindow(); |
| ui::test::EventGenerator generator(root); |
| generator.MoveMouseToInHost(10, 20); |
| |
| EXPECT_EQ("7,7", test_api.GetCursorHotPoint().ToString()); |
| EXPECT_EQ("10,20", |
| test_api.GetCursorHotPointLocationInRootWindow().ToString()); |
| |
| // Test with ui scale |
| UpdateDisplay("400x600*0.5,400x600"); |
| generator.MoveMouseToInHost(20, 30); |
| |
| EXPECT_EQ("4,4", test_api.GetCursorHotPoint().ToString()); |
| EXPECT_EQ("20,30", |
| test_api.GetCursorHotPointLocationInRootWindow().ToString()); |
| |
| // Test with rotation |
| UpdateDisplay("400x600/r,400x600"); |
| generator.MoveMouseToInHost(30, 40); |
| |
| EXPECT_EQ("21,4", test_api.GetCursorHotPoint().ToString()); |
| EXPECT_EQ("30,40", |
| test_api.GetCursorHotPointLocationInRootWindow().ToString()); |
| } |
| |
| // Test the behavior of the cursor when entering software mirror mode swaps the |
| // cursor's display. |
| TEST_F(MirrorWindowControllerTest, MAYBE_MirrorCursorMoveOnEnter) { |
| aura::Env* env = aura::Env::GetInstance(); |
| Shell* shell = Shell::GetInstance(); |
| WindowTreeHostManager* window_tree_host_manager = |
| shell->window_tree_host_manager(); |
| |
| UpdateDisplay("400x400*2/r,400x400"); |
| int64_t primary_display_id = window_tree_host_manager->GetPrimaryDisplayId(); |
| int64_t secondary_display_id = ScreenUtil::GetSecondaryDisplay().id(); |
| test::ScopedSetInternalDisplayId set_internal(primary_display_id); |
| |
| // Chrome uses the internal display as the source display for software mirror |
| // mode. Move the cursor to the external display. |
| aura::Window* secondary_root_window = |
| window_tree_host_manager->GetRootWindowForDisplayId(secondary_display_id); |
| secondary_root_window->MoveCursorTo(gfx::Point(100, 200)); |
| EXPECT_EQ("300,200", env->last_mouse_location().ToString()); |
| test::CursorManagerTestApi cursor_test_api(shell->cursor_manager()); |
| EXPECT_EQ(1.0f, cursor_test_api.GetCurrentCursor().device_scale_factor()); |
| EXPECT_EQ(display::Display::ROTATE_0, |
| cursor_test_api.GetCurrentCursorRotation()); |
| |
| shell->display_manager()->SetMultiDisplayMode(DisplayManager::MIRRORING); |
| UpdateDisplay("400x400*2/r,400x400"); |
| |
| // Entering mirror mode should have centered the cursor on the primary display |
| // because the cursor's previous position is out of bounds. |
| // Check real cursor's position and properties. |
| EXPECT_EQ("100,100", env->last_mouse_location().ToString()); |
| EXPECT_EQ(2.0f, cursor_test_api.GetCurrentCursor().device_scale_factor()); |
| EXPECT_EQ(display::Display::ROTATE_90, |
| cursor_test_api.GetCurrentCursorRotation()); |
| |
| // Check mirrored cursor's location. |
| test::MirrorWindowTestApi test_api; |
| // Rotated hot point must be (25-7, 7). |
| EXPECT_EQ("18,7", test_api.GetCursorHotPoint().ToString()); |
| // New coordinates are not (200,200) because (200,200) is not the center of |
| // the display. |
| EXPECT_EQ("199,200", |
| test_api.GetCursorHotPointLocationInRootWindow().ToString()); |
| } |
| |
| // Make sure that the compositor based mirroring can switch |
| // from/to dock mode. |
| TEST_F(MirrorWindowControllerTest, MAYBE_DockMode) { |
| DisplayManager* display_manager = Shell::GetInstance()->display_manager(); |
| const int64_t internal_id = 1; |
| const int64_t external_id = 2; |
| |
| const DisplayInfo internal_display_info = |
| CreateDisplayInfo(internal_id, gfx::Rect(0, 0, 500, 500)); |
| const DisplayInfo external_display_info = |
| CreateDisplayInfo(external_id, gfx::Rect(1, 1, 100, 100)); |
| std::vector<DisplayInfo> display_info_list; |
| |
| display_manager->SetMultiDisplayMode(DisplayManager::MIRRORING); |
| |
| // software mirroring. |
| display_info_list.push_back(internal_display_info); |
| display_info_list.push_back(external_display_info); |
| display_manager->OnNativeDisplaysChanged(display_info_list); |
| const int64_t internal_display_id = |
| test::DisplayManagerTestApi().SetFirstDisplayAsInternalDisplay(); |
| EXPECT_EQ(internal_id, internal_display_id); |
| |
| EXPECT_EQ(1U, display_manager->GetNumDisplays()); |
| EXPECT_TRUE(display_manager->IsInMirrorMode()); |
| EXPECT_EQ(external_id, display_manager->mirroring_display_id()); |
| |
| // dock mode. |
| display_info_list.clear(); |
| display_info_list.push_back(external_display_info); |
| display_manager->SetMultiDisplayMode(DisplayManager::MIRRORING); |
| display_manager->OnNativeDisplaysChanged(display_info_list); |
| EXPECT_EQ(1U, display_manager->GetNumDisplays()); |
| EXPECT_FALSE(display_manager->IsInMirrorMode()); |
| |
| // back to software mirroring. |
| display_info_list.clear(); |
| display_info_list.push_back(internal_display_info); |
| display_info_list.push_back(external_display_info); |
| display_manager->SetMultiDisplayMode(DisplayManager::MIRRORING); |
| display_manager->OnNativeDisplaysChanged(display_info_list); |
| EXPECT_EQ(1U, display_manager->GetNumDisplays()); |
| EXPECT_TRUE(display_manager->IsInMirrorMode()); |
| EXPECT_EQ(external_id, display_manager->mirroring_display_id()); |
| } |
| |
| TEST_F(MirrorOnBootTest, MAYBE_MirrorOnBoot) { |
| DisplayManager* display_manager = Shell::GetInstance()->display_manager(); |
| EXPECT_TRUE(display_manager->IsInMirrorMode()); |
| RunAllPendingInMessageLoop(); |
| test::MirrorWindowTestApi test_api; |
| EXPECT_TRUE(test_api.GetHost()); |
| } |
| |
| } // namespace ash |