| // Copyright 2020 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/display_alignment_controller.h" |
| |
| #include "ash/display/display_alignment_indicator.h" |
| #include "ash/public/cpp/ash_features.h" |
| #include "ash/shell.h" |
| #include "ash/test/ash_test_base.h" |
| #include "base/test/scoped_feature_list.h" |
| #include "base/timer/mock_timer.h" |
| #include "ui/display/display_layout_builder.h" |
| #include "ui/display/manager/display_layout_store.h" |
| #include "ui/display/manager/display_manager.h" |
| #include "ui/display/test/display_manager_test_api.h" |
| #include "ui/views/widget/widget.h" |
| |
| namespace ash { |
| |
| namespace { |
| |
| enum class EdgeType { kTop, kRight, kBottom, kLeft }; |
| |
| DisplayAlignmentController* display_alignment_controller() { |
| return Shell::Get()->display_alignment_controller(); |
| } |
| |
| void TriggerIndicator(const display::Display& display, EdgeType edge) { |
| WindowTreeHostManager* window_tree_host_manager = |
| Shell::Get()->window_tree_host_manager(); |
| aura::Window* primary_root = |
| window_tree_host_manager->GetRootWindowForDisplayId(display.id()); |
| |
| ui::test::EventGenerator primary_generator(primary_root); |
| |
| const gfx::Rect display_bounds = primary_root->GetBoundsInRootWindow(); |
| |
| gfx::Point point_on_edge; |
| if (edge == EdgeType::kTop) |
| point_on_edge = display_bounds.top_center(); |
| else if (edge == EdgeType::kRight) |
| point_on_edge = display_bounds.right_center(); |
| else if (edge == EdgeType::kBottom) |
| point_on_edge = display_bounds.bottom_center(); |
| else |
| point_on_edge = display_bounds.left_center(); |
| |
| primary_generator.MoveMouseToInHost(point_on_edge); |
| primary_generator.MoveMouseToInHost(display_bounds.CenterPoint()); |
| primary_generator.MoveMouseToInHost(point_on_edge); |
| } |
| |
| } // namespace |
| |
| class DisplayAlignmentControllerTest : public AshTestBase { |
| public: |
| DisplayAlignmentControllerTest() = default; |
| ~DisplayAlignmentControllerTest() override = default; |
| |
| protected: |
| void LockScreen() { GetSessionControllerClient()->LockScreen(); } |
| void UnlockScreen() { GetSessionControllerClient()->UnlockScreen(); } |
| |
| // AshTestBase: |
| void SetUp() override { |
| scoped_feature_list_.InitAndEnableFeature(features::kDisplayAlignAssist); |
| |
| AshTestBase::SetUp(); |
| |
| std::unique_ptr<base::MockOneShotTimer> mock_timer = |
| std::make_unique<base::MockOneShotTimer>(); |
| |
| mock_timer_ptr_ = mock_timer.get(); |
| |
| display_alignment_controller()->SetTimerForTesting(std::move(mock_timer)); |
| } |
| |
| bool NoIndicatorsExist() { |
| return display_alignment_controller() |
| ->GetActiveIndicatorsForTesting() |
| .empty(); |
| } |
| |
| void CheckIndicatorShown(size_t num_indicators, |
| const display::Display& src_display) { |
| const auto& active_indicators = |
| display_alignment_controller()->GetActiveIndicatorsForTesting(); |
| |
| WindowTreeHostManager* window_tree_host_manager = |
| Shell::Get()->window_tree_host_manager(); |
| aura::Window* primary_root = |
| window_tree_host_manager->GetRootWindowForDisplayId(src_display.id()); |
| |
| EXPECT_EQ(num_indicators, active_indicators.size()); |
| |
| for (const auto& indicator : active_indicators) { |
| ASSERT_TRUE(indicator); |
| |
| EXPECT_TRUE(indicator->indicator_widget_.IsVisible()); |
| |
| aura::Window* current_root = |
| indicator->indicator_widget_.GetNativeWindow()->GetRootWindow(); |
| if (current_root == primary_root) { |
| ASSERT_TRUE(indicator->pill_widget_); |
| EXPECT_TRUE(indicator->pill_widget_->IsVisible()); |
| } else { |
| EXPECT_FALSE(indicator->pill_widget_); |
| } |
| } |
| } |
| |
| base::MockOneShotTimer* mock_timer_ptr_ = nullptr; |
| |
| private: |
| base::test::ScopedFeatureList scoped_feature_list_; |
| }; |
| |
| TEST_F(DisplayAlignmentControllerTest, SingleDisplayNoIndicators) { |
| UpdateDisplay("1920x1080"); |
| |
| EXPECT_TRUE(NoIndicatorsExist()); |
| } |
| |
| TEST_F(DisplayAlignmentControllerTest, TriggerIndicatorPrimary) { |
| UpdateDisplay("1920x1080,1366x768"); |
| |
| const auto& display = display_manager()->GetDisplayAt(0); |
| |
| aura::Window* root_window = |
| Shell::Get()->window_tree_host_manager()->GetRootWindowForDisplayId( |
| display.id()); |
| |
| ui::test::EventGenerator generator(root_window); |
| |
| // Move mouse on to an edge. |
| generator.MoveMouseToInHost(gfx::Point(0, 0)); |
| EXPECT_TRUE(NoIndicatorsExist()); |
| |
| // Move mouse off the edge. |
| generator.MoveMouseToInHost(gfx::Point(20, 50)); |
| EXPECT_TRUE(NoIndicatorsExist()); |
| |
| // Move mouse on to an edge for the second time. |
| generator.MoveMouseToInHost(gfx::Point(0, 0)); |
| |
| CheckIndicatorShown(2, display); |
| |
| // Finish displaying indicators. |
| mock_timer_ptr_->Fire(); |
| EXPECT_TRUE(NoIndicatorsExist()); |
| } |
| |
| TEST_F(DisplayAlignmentControllerTest, RetriggerIndicatorPrimary) { |
| UpdateDisplay("1920x1080,1366x768"); |
| |
| const auto& display = display_manager()->GetDisplayAt(0); |
| |
| EXPECT_TRUE(NoIndicatorsExist()); |
| |
| TriggerIndicator(display, EdgeType::kTop); |
| |
| CheckIndicatorShown(2, display); |
| |
| // Finish displaying indicators. |
| mock_timer_ptr_->Fire(); |
| |
| EXPECT_TRUE(NoIndicatorsExist()); |
| |
| // Re-trigger indicators. |
| TriggerIndicator(display, EdgeType::kTop); |
| |
| CheckIndicatorShown(2, display); |
| } |
| |
| TEST_F(DisplayAlignmentControllerTest, OnlyTriggerNeighboringIndicators) { |
| UpdateDisplay("1920x1080,1366x768,800x600"); |
| |
| const auto& display = display_manager()->GetDisplayAt(0); |
| |
| TriggerIndicator(display, EdgeType::kTop); |
| |
| CheckIndicatorShown(2, display); |
| } |
| |
| TEST_F(DisplayAlignmentControllerTest, TriggerSecondaryDisplay) { |
| UpdateDisplay("1920x1080,1366x768,800x600"); |
| |
| const auto& display = display_manager()->GetDisplayAt(1); |
| |
| TriggerIndicator(display, EdgeType::kTop); |
| |
| CheckIndicatorShown(4, display); |
| } |
| |
| TEST_F(DisplayAlignmentControllerTest, TriggerTwoDisplayOnSameEdge) { |
| // |
| // +---------+---------+ |
| // | 1 | 2 | |
| // | | | |
| // | | | |
| // | | | |
| // +-+-------+---------+-+ |
| // | P | |
| // | | |
| // | | |
| // | | |
| // +-------------------+ |
| // |
| |
| int64_t primary_id = display::Screen::GetScreen()->GetPrimaryDisplay().id(); |
| display::DisplayIdList list = |
| display::test::CreateDisplayIdListN(primary_id, 3); |
| display::DisplayLayoutBuilder builder(primary_id); |
| builder.AddDisplayPlacement(list[1], primary_id, |
| display::DisplayPlacement::TOP, -110); |
| builder.AddDisplayPlacement(list[2], primary_id, |
| display::DisplayPlacement::TOP, 490); |
| display_manager()->layout_store()->RegisterLayoutForDisplayIdList( |
| list, builder.Build()); |
| |
| UpdateDisplay("1200x500,600x500,600x500"); |
| |
| const auto& display = display_manager()->GetDisplayAt(1); |
| |
| TriggerIndicator(display, EdgeType::kTop); |
| |
| CheckIndicatorShown(4, display); |
| } |
| |
| TEST_F(DisplayAlignmentControllerTest, DontTriggerIndicator) { |
| UpdateDisplay("1920x1080,1366x768"); |
| |
| const auto& display = display_manager()->GetDisplayAt(0); |
| |
| aura::Window* root_window = |
| Shell::Get()->window_tree_host_manager()->GetRootWindowForDisplayId( |
| display.id()); |
| |
| ui::test::EventGenerator generator(root_window); |
| |
| // Move the mouse on to the edge once. |
| generator.MoveMouseToInHost(gfx::Point(0, 0)); |
| generator.MoveMouseToInHost(gfx::Point(20, 50)); |
| |
| EXPECT_TRUE(NoIndicatorsExist()); |
| mock_timer_ptr_->Fire(); |
| EXPECT_TRUE(NoIndicatorsExist()); |
| } |
| |
| TEST_F(DisplayAlignmentControllerTest, DontTriggerIndicatorDifferentDisplays) { |
| UpdateDisplay("1920x1080,1366x768"); |
| |
| const auto& primary_display = display_manager()->GetDisplayAt(0); |
| const auto& secondary_display = display_manager()->GetDisplayAt(1); |
| |
| WindowTreeHostManager* window_tree_host_manager = |
| Shell::Get()->window_tree_host_manager(); |
| |
| aura::Window* primary_root = |
| window_tree_host_manager->GetRootWindowForDisplayId(primary_display.id()); |
| aura::Window* secondary_root = |
| window_tree_host_manager->GetRootWindowForDisplayId( |
| secondary_display.id()); |
| |
| ui::test::EventGenerator primary_generator(primary_root); |
| ui::test::EventGenerator secondary_generator(secondary_root); |
| |
| // Simulate hitting the edge of the first display. |
| primary_generator.MoveMouseToInHost(gfx::Point(0, 0)); |
| primary_generator.MoveMouseToInHost(gfx::Point(20, 20)); |
| |
| // Hitting the edge of the second display should not trigger alignment |
| // indicators. |
| secondary_generator.MoveMouseToInHost(gfx::Point(1365, 0)); |
| |
| EXPECT_TRUE(NoIndicatorsExist()); |
| } |
| |
| TEST_F(DisplayAlignmentControllerTest, RemoveDisplay) { |
| UpdateDisplay("1920x1080,1366x768"); |
| |
| const auto& primary_display = display_manager()->GetDisplayAt(0); |
| |
| TriggerIndicator(primary_display, EdgeType::kLeft); |
| |
| CheckIndicatorShown(2, primary_display); |
| |
| UpdateDisplay("1920x1080"); |
| |
| EXPECT_TRUE(NoIndicatorsExist()); |
| |
| TriggerIndicator(primary_display, EdgeType::kTop); |
| |
| EXPECT_TRUE(NoIndicatorsExist()); |
| } |
| |
| TEST_F(DisplayAlignmentControllerTest, LockScreen) { |
| UpdateDisplay("1920x1080,1366x768"); |
| |
| const auto& primary_display = display_manager()->GetDisplayAt(0); |
| |
| TriggerIndicator(primary_display, EdgeType::kBottom); |
| |
| CheckIndicatorShown(2, primary_display); |
| |
| LockScreen(); |
| |
| EXPECT_TRUE(NoIndicatorsExist()); |
| |
| TriggerIndicator(primary_display, EdgeType::kTop); |
| |
| EXPECT_TRUE(NoIndicatorsExist()); |
| |
| UnlockScreen(); |
| |
| TriggerIndicator(primary_display, EdgeType::kTop); |
| |
| CheckIndicatorShown(2, primary_display); |
| } |
| |
| TEST_F(DisplayAlignmentControllerTest, ChangeResolution) { |
| UpdateDisplay("1920x1080,1366x768"); |
| |
| const auto& primary_display = display_manager()->GetDisplayAt(0); |
| |
| TriggerIndicator(primary_display, EdgeType::kTop); |
| |
| CheckIndicatorShown(2, primary_display); |
| |
| UpdateDisplay("2560x1440,1366x768"); |
| |
| // Resolution change immediately hides the indicator. |
| EXPECT_TRUE(NoIndicatorsExist()); |
| |
| TriggerIndicator(primary_display, EdgeType::kRight); |
| |
| CheckIndicatorShown(2, primary_display); |
| } |
| |
| TEST_F(DisplayAlignmentControllerTest, AllowOffByOnes) { |
| UpdateDisplay("1920x1080,1366x768"); |
| |
| const auto& primary_display = display_manager()->GetDisplayAt(0); |
| |
| WindowTreeHostManager* window_tree_host_manager = |
| Shell::Get()->window_tree_host_manager(); |
| |
| aura::Window* primary_root = |
| window_tree_host_manager->GetRootWindowForDisplayId(primary_display.id()); |
| |
| ui::test::EventGenerator primary_generator(primary_root); |
| |
| // (1, 1) is one off of both top and left edge. |
| primary_generator.MoveMouseToInHost(gfx::Point(1, 1)); |
| primary_generator.MoveMouseToInHost(gfx::Point(20, 20)); |
| primary_generator.MoveMouseToInHost(gfx::Point(1, 1)); |
| |
| CheckIndicatorShown(2, primary_display); |
| } |
| |
| } // namespace ash |