1 // Copyright 2018 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/accessibility/accessibility_panel_layout_manager.h"
6 
7 #include <memory>
8 
9 #include "ash/public/cpp/shelf_config.h"
10 #include "ash/shell.h"
11 #include "ash/test/ash_test_base.h"
12 #include "ui/display/display.h"
13 #include "ui/display/screen.h"
14 #include "ui/views/widget/widget.h"
15 
16 namespace ash {
17 namespace {
18 
19 // Shorten the name for better line wrapping.
20 constexpr int kDefaultPanelHeight =
21     AccessibilityPanelLayoutManager::kDefaultPanelHeight;
22 
GetLayoutManager()23 AccessibilityPanelLayoutManager* GetLayoutManager() {
24   aura::Window* container =
25       Shell::GetContainer(Shell::GetPrimaryRootWindow(),
26                           kShellWindowId_AccessibilityPanelContainer);
27   return static_cast<AccessibilityPanelLayoutManager*>(
28       container->layout_manager());
29 }
30 
31 // Simulates Chrome creating the ChromeVoxPanel widget.
CreateChromeVoxPanel()32 std::unique_ptr<views::Widget> CreateChromeVoxPanel() {
33   std::unique_ptr<views::Widget> widget = std::make_unique<views::Widget>();
34   views::Widget::InitParams params(
35       views::Widget::InitParams::TYPE_WINDOW_FRAMELESS);
36   params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
37   aura::Window* root_window = Shell::GetPrimaryRootWindow();
38   params.parent = Shell::GetContainer(
39       root_window, kShellWindowId_AccessibilityPanelContainer);
40   params.activatable = views::Widget::InitParams::ACTIVATABLE_NO;
41   params.bounds = gfx::Rect(0, 0, root_window->bounds().width(),
42                             root_window->bounds().height());
43   widget->Init(std::move(params));
44   return widget;
45 }
46 
47 using AccessibilityPanelLayoutManagerTest = AshTestBase;
48 
TEST_F(AccessibilityPanelLayoutManagerTest,Basics)49 TEST_F(AccessibilityPanelLayoutManagerTest, Basics) {
50   AccessibilityPanelLayoutManager* layout_manager = GetLayoutManager();
51   ASSERT_TRUE(layout_manager);
52 
53   // The layout manager doesn't track anything at startup.
54   EXPECT_FALSE(layout_manager->panel_window_for_test());
55 
56   // Simulate chrome creating the ChromeVox widget. The layout manager starts
57   // managing it.
58   std::unique_ptr<views::Widget> widget = CreateChromeVoxPanel();
59   widget->Show();
60   EXPECT_EQ(widget->GetNativeWindow(), layout_manager->panel_window_for_test());
61 
62   // The layout manager doesn't track anything after the widget closes.
63   widget.reset();
64   EXPECT_FALSE(layout_manager->panel_window_for_test());
65 }
66 
TEST_F(AccessibilityPanelLayoutManagerTest,Shutdown)67 TEST_F(AccessibilityPanelLayoutManagerTest, Shutdown) {
68   // Simulate chrome creating the ChromeVox widget.
69   std::unique_ptr<views::Widget> widget = CreateChromeVoxPanel();
70   widget->Show();
71 
72   // Don't close the window.
73   widget.release();
74 
75   // Ash should not crash if the window is still open at shutdown.
76 }
77 
TEST_F(AccessibilityPanelLayoutManagerTest,PanelFullscreen)78 TEST_F(AccessibilityPanelLayoutManagerTest, PanelFullscreen) {
79   AccessibilityPanelLayoutManager* layout_manager = GetLayoutManager();
80   display::Screen* screen = display::Screen::GetScreen();
81 
82   std::unique_ptr<views::Widget> widget = CreateChromeVoxPanel();
83   widget->Show();
84 
85   layout_manager->SetPanelBounds(gfx::Rect(0, 0, 0, kDefaultPanelHeight),
86                                  AccessibilityPanelState::FULL_WIDTH);
87 
88   gfx::Rect expected_work_area = screen->GetPrimaryDisplay().work_area();
89 
90   // When the panel is fullscreen it fills the display and clears the
91   // work area.
92   layout_manager->SetPanelBounds(gfx::Rect(),
93                                  AccessibilityPanelState::FULLSCREEN);
94   EXPECT_EQ(widget->GetNativeWindow()->bounds(),
95             screen->GetPrimaryDisplay().bounds());
96   EXPECT_EQ(screen->GetPrimaryDisplay().work_area().y(), 0);
97 
98   // Restoring the panel to default size restores the bounds and sets
99   // the work area.
100   layout_manager->SetPanelBounds(gfx::Rect(0, 0, 0, kDefaultPanelHeight),
101                                  AccessibilityPanelState::FULL_WIDTH);
102   gfx::Rect expected_bounds(0, 0, screen->GetPrimaryDisplay().bounds().width(),
103                             kDefaultPanelHeight);
104   EXPECT_EQ(widget->GetNativeWindow()->bounds(), expected_bounds);
105   EXPECT_EQ(screen->GetPrimaryDisplay().work_area(), expected_work_area);
106 }
107 
TEST_F(AccessibilityPanelLayoutManagerTest,SetBounds)108 TEST_F(AccessibilityPanelLayoutManagerTest, SetBounds) {
109   std::unique_ptr<views::Widget> widget = CreateChromeVoxPanel();
110   widget->Show();
111 
112   gfx::Rect bounds(0, 0, 100, 100);
113   GetLayoutManager()->SetPanelBounds(bounds, AccessibilityPanelState::BOUNDED);
114   EXPECT_EQ(widget->GetNativeWindow()->bounds(), bounds);
115 }
116 
TEST_F(AccessibilityPanelLayoutManagerTest,DisplayBoundsChange)117 TEST_F(AccessibilityPanelLayoutManagerTest, DisplayBoundsChange) {
118   std::unique_ptr<views::Widget> widget = CreateChromeVoxPanel();
119   widget->Show();
120   GetLayoutManager()->SetPanelBounds(gfx::Rect(0, 0, 0, kDefaultPanelHeight),
121                                      AccessibilityPanelState::FULL_WIDTH);
122 
123   // When the display resolution changes the panel still sits at the top of the
124   // screen.
125   UpdateDisplay("1234,567");
126   display::Screen* screen = display::Screen::GetScreen();
127   gfx::Rect expected_bounds(0, 0, screen->GetPrimaryDisplay().bounds().width(),
128                             kDefaultPanelHeight);
129   EXPECT_EQ(widget->GetNativeWindow()->bounds(), expected_bounds);
130 
131   gfx::Rect expected_work_area = screen->GetPrimaryDisplay().bounds();
132   expected_work_area.Inset(0, kDefaultPanelHeight, 0,
133                            ShelfConfig::Get()->shelf_size());
134   EXPECT_EQ(screen->GetPrimaryDisplay().work_area(), expected_work_area);
135 }
136 
137 }  // namespace
138 }  // namespace ash
139