// 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/display/mirror_window_test_api.h" #include "ash/display/window_tree_host_manager.h" #include "ash/shell.h" #include "ash/test/ash_test_base.h" #include "ash/wm/cursor_manager_test_api.h" #include "base/command_line.h" #include "base/run_loop.h" #include "base/strings/stringprintf.h" #include "testing/gtest/include/gtest/gtest.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/display/display_switches.h" #include "ui/display/display_transform.h" #include "ui/display/manager/display_manager.h" #include "ui/display/test/display_manager_test_api.h" #include "ui/display/types/display_constants.h" #include "ui/events/test/event_generator.h" #include "ui/gfx/overlay_transform.h" namespace ash { namespace { display::ManagedDisplayInfo CreateDisplayInfo(int64_t id, const gfx::Rect& bounds, float scale = 1.f) { display::ManagedDisplayInfo info( id, base::StringPrintf("x-%d", static_cast(id)), false); info.SetBounds(bounds); info.set_device_scale_factor(scale); return info; } class MirrorOnBootTest : public AshTestBase { public: MirrorOnBootTest() = default; MirrorOnBootTest(const MirrorOnBootTest&) = delete; MirrorOnBootTest& operator=(const MirrorOnBootTest&) = delete; ~MirrorOnBootTest() override = default; void SetUp() override { base::CommandLine::ForCurrentProcess()->AppendSwitchASCII( ::switches::kHostWindowBounds, "1+1-400x300,1+301-400x300"); base::CommandLine::ForCurrentProcess()->AppendSwitch( ::switches::kEnableSoftwareMirroring); AshTestBase::SetUp(); } }; } // namespace using MirrorWindowControllerTest = AshTestBase; // Make sure that the compositor based mirroring can switch // from/to dock mode. TEST_F(MirrorWindowControllerTest, DockMode) { const int64_t internal_id = 1; const int64_t external_id = 2; const display::ManagedDisplayInfo internal_display_info = CreateDisplayInfo(internal_id, gfx::Rect(0, 0, 400, 500)); const display::ManagedDisplayInfo external_display_info = CreateDisplayInfo(external_id, gfx::Rect(1, 1, 200, 100)); std::vector display_info_list; // 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 = display::test::DisplayManagerTestApi(display_manager()) .SetFirstDisplayAsInternalDisplay(); EXPECT_EQ(internal_id, internal_display_id); display_manager()->SetMirrorMode(display::MirrorMode::kNormal, absl::nullopt); base::RunLoop().RunUntilIdle(); EXPECT_EQ(1U, display_manager()->GetNumDisplays()); EXPECT_TRUE(display_manager()->IsInSoftwareMirrorMode()); EXPECT_EQ(external_id, display_manager()->GetMirroringDestinationDisplayIdList()[0]); // dock mode. display_info_list.clear(); display_info_list.push_back(external_display_info); 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()->OnNativeDisplaysChanged(display_info_list); EXPECT_EQ(1U, display_manager()->GetNumDisplays()); EXPECT_TRUE(display_manager()->IsInMirrorMode()); EXPECT_EQ(external_id, display_manager()->GetMirroringDestinationDisplayIdList()[0]); } TEST_F(MirrorOnBootTest, MirrorOnBoot) { EXPECT_TRUE(display_manager()->IsInMirrorMode()); base::RunLoop().RunUntilIdle(); MirrorWindowTestApi test_api; EXPECT_EQ(1U, test_api.GetHosts().size()); } class MirrorWindowControllerRotationAndPanelOrientationTest : public MirrorWindowControllerTest, public testing::WithParamInterface< std::tuple> {}; // Test that the mirror display matches the size and rotation of the source. TEST_P(MirrorWindowControllerRotationAndPanelOrientationTest, MirrorSize) { const int64_t primary_id = 1; const int64_t mirror_id = 2; const display::Display::Rotation active_rotation = std::get<0>(GetParam()); const display::PanelOrientation panel_orientation = std::get<1>(GetParam()); // Run the test with and without display scaling. int scale_factors[] = {1, 2}; for (int scale : scale_factors) { display::ManagedDisplayInfo primary_display_info = CreateDisplayInfo(primary_id, gfx::Rect(0, 0, 400, 300), scale); primary_display_info.set_panel_orientation(panel_orientation); primary_display_info.SetRotation(active_rotation, display::Display::RotationSource::ACTIVE); const display::ManagedDisplayInfo mirror_display_info = CreateDisplayInfo(mirror_id, gfx::Rect(400, 0, 600, 500), scale); std::vector display_info_list = { primary_display_info, mirror_display_info}; // Start software mirroring. display_manager()->OnNativeDisplaysChanged(display_info_list); display_manager()->SetMirrorMode(display::MirrorMode::kNormal, absl::nullopt); base::RunLoop().RunUntilIdle(); EXPECT_EQ(1U, display_manager()->GetNumDisplays()); EXPECT_TRUE(display_manager()->IsInSoftwareMirrorMode()); // Check the size of the mirror window. const display::Display& primary_display = display_manager()->GetDisplayForId(primary_id); aura::Window* root_window = Shell::GetRootWindowForDisplayId(mirror_id); aura::Window* mirror_window = root_window->children()[0]; EXPECT_EQ(primary_display.GetSizeInPixel(), root_window->bounds().size()); EXPECT_EQ(primary_display.GetSizeInPixel(), mirror_window->bounds().size()); // Mirror should have a display transform hint that matches the active // rotation (excluding the panel orientation) of the source. EXPECT_EQ(display::DisplayRotationToOverlayTransform(active_rotation), root_window->GetHost()->compositor()->display_transform_hint()); } } INSTANTIATE_TEST_SUITE_P( All, MirrorWindowControllerRotationAndPanelOrientationTest, testing::Combine(testing::Values(display::Display::ROTATE_0, display::Display::ROTATE_90, display::Display::ROTATE_180, display::Display::ROTATE_270), testing::Values(display::PanelOrientation::kNormal, display::PanelOrientation::kBottomUp, display::PanelOrientation::kLeftUp, display::PanelOrientation::kRightUp))); } // namespace ash