1 // Copyright 2015 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 <memory>
6
7 #include "ash/public/cpp/shell_window_ids.h"
8 #include "ash/session/session_controller_impl.h"
9 #include "ash/session/test_pref_service_provider.h"
10 #include "ash/session/test_session_controller_client.h"
11 #include "ash/shell.h"
12 #include "ash/test/ash_test_base.h"
13 #include "ash/test/ash_test_helper.h"
14 #include "ash/window_factory.h"
15 #include "ash/wm/desks/desks_util.h"
16 #include "ash/wm/lock_state_controller.h"
17 #include "ash/wm/window_state.h"
18 #include "ash/wm/window_util.h"
19 #include "ui/aura/client/aura_constants.h"
20 #include "ui/aura/client/window_parenting_client.h"
21 #include "ui/base/ui_base_types.h"
22 #include "ui/views/test/widget_test.h"
23 #include "ui/views/view.h"
24 #include "ui/views/widget/widget.h"
25 #include "ui/wm/core/window_util.h"
26
27 namespace ash {
28
29 namespace {
30
31 // Defines a |SessionControllerClient| that is used to create and destroy the
32 // test lock screen widget.
33 class LockScreenSessionControllerClient : public TestSessionControllerClient {
34 public:
LockScreenSessionControllerClient(SessionControllerImpl * controller,TestPrefServiceProvider * prefs_provider)35 LockScreenSessionControllerClient(SessionControllerImpl* controller,
36 TestPrefServiceProvider* prefs_provider)
37 : TestSessionControllerClient(controller, prefs_provider) {
38 InitializeAndSetClient();
39 CreatePredefinedUserSessions(1);
40 }
41 ~LockScreenSessionControllerClient() override = default;
42
43 // TestSessionControllerClient:
RequestLockScreen()44 void RequestLockScreen() override {
45 TestSessionControllerClient::RequestLockScreen();
46 CreateLockScreen();
47 Shell::Get()->UpdateShelfVisibility();
48 }
49
UnlockScreen()50 void UnlockScreen() override {
51 TestSessionControllerClient::UnlockScreen();
52 if (lock_screen_widget_.get()) {
53 lock_screen_widget_->Close();
54 lock_screen_widget_.reset(nullptr);
55 }
56
57 Shell::Get()->UpdateShelfVisibility();
58 }
59
60 private:
CreateLockScreen()61 void CreateLockScreen() {
62 auto lock_view = std::make_unique<views::View>();
63 lock_screen_widget_.reset(new views::Widget);
64 views::Widget::InitParams params(
65 views::Widget::InitParams::TYPE_WINDOW_FRAMELESS);
66 gfx::Size ps = lock_view->GetPreferredSize();
67
68 gfx::Size root_window_size = Shell::GetPrimaryRootWindow()->bounds().size();
69 params.bounds = gfx::Rect((root_window_size.width() - ps.width()) / 2,
70 (root_window_size.height() - ps.height()) / 2,
71 ps.width(), ps.height());
72 params.parent = Shell::GetContainer(Shell::GetPrimaryRootWindow(),
73 kShellWindowId_LockScreenContainer);
74 params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
75 lock_screen_widget_->Init(std::move(params));
76 lock_screen_widget_->SetContentsView(std::move(lock_view));
77 lock_screen_widget_->Show();
78 lock_screen_widget_->GetNativeView()->SetName("LockView");
79 lock_screen_widget_->GetNativeView()->Focus();
80 }
81
82 std::unique_ptr<views::Widget> lock_screen_widget_;
83
84 DISALLOW_COPY_AND_ASSIGN(LockScreenSessionControllerClient);
85 };
86
87 ////////////////////////////////////////////////////////////////////////////////
88
89 // Defines a class that will be used to test the correct behavior of
90 // |AshFocusRules| when locking and unlocking the screen.
91 class LockScreenAshFocusRulesTest : public AshTestBase {
92 public:
93 LockScreenAshFocusRulesTest() = default;
94 ~LockScreenAshFocusRulesTest() override = default;
95
SetUp()96 void SetUp() override {
97 AshTestBase::SetUp();
98 ash_test_helper()->set_test_session_controller_client(
99 std::make_unique<LockScreenSessionControllerClient>(
100 Shell::Get()->session_controller(),
101 ash_test_helper()->prefs_provider()));
102 }
103
CreateWindowInActiveDesk()104 aura::Window* CreateWindowInActiveDesk() {
105 return CreateWindowInContainer(desks_util::GetActiveDeskContainerId());
106 }
107
CreateWindowInAppListContainer()108 aura::Window* CreateWindowInAppListContainer() {
109 return CreateWindowInContainer(kShellWindowId_AppListContainer);
110 }
111
CreateWindowInAlwaysOnTopContainer()112 aura::Window* CreateWindowInAlwaysOnTopContainer() {
113 aura::Window* window =
114 CreateWindowInContainer(kShellWindowId_AlwaysOnTopContainer);
115 window->SetProperty(aura::client::kZOrderingKey,
116 ui::ZOrderLevel::kFloatingWindow);
117 return window;
118 }
119
CreateWindowInLockContainer()120 aura::Window* CreateWindowInLockContainer() {
121 return CreateWindowInContainer(kShellWindowId_LockScreenContainer);
122 }
123
CreateWindowInShelfContainer()124 aura::Window* CreateWindowInShelfContainer() {
125 return CreateWindowInContainer(kShellWindowId_ShelfContainer);
126 }
127
CreateWindowInLockSystemModalContainer()128 aura::Window* CreateWindowInLockSystemModalContainer() {
129 aura::Window* window =
130 CreateWindowInContainer(kShellWindowId_LockSystemModalContainer);
131 window->SetProperty(aura::client::kModalKey, ui::MODAL_TYPE_SYSTEM);
132 return window;
133 }
134
CreateWindowInSystemModalContainer()135 aura::Window* CreateWindowInSystemModalContainer() {
136 aura::Window* window =
137 CreateWindowInContainer(kShellWindowId_SystemModalContainer);
138 window->SetProperty(aura::client::kModalKey, ui::MODAL_TYPE_SYSTEM);
139 return window;
140 }
141
142 private:
CreateWindowInContainer(int container_id)143 aura::Window* CreateWindowInContainer(int container_id) {
144 aura::Window* root_window = Shell::GetPrimaryRootWindow();
145 aura::Window* container = Shell::GetContainer(root_window, container_id);
146 aura::Window* window = window_factory::NewWindow().release();
147 window->set_id(0);
148 window->SetType(aura::client::WINDOW_TYPE_NORMAL);
149 window->Init(ui::LAYER_TEXTURED);
150 window->Show();
151 window->SetProperty(aura::client::kResizeBehaviorKey,
152 aura::client::kResizeBehaviorCanMaximize |
153 aura::client::kResizeBehaviorCanMinimize |
154 aura::client::kResizeBehaviorCanResize);
155 container->AddChild(window);
156 return window;
157 }
158
159 std::unique_ptr<LockScreenSessionControllerClient> session_controller_client_;
160
161 DISALLOW_COPY_AND_ASSIGN(LockScreenAshFocusRulesTest);
162 };
163
164 } // namespace
165
166 // Verifies focus is returned (after unlocking the screen) to the most recent
167 // window that had it before locking the screen.
TEST_F(LockScreenAshFocusRulesTest,RegainFocusAfterUnlock)168 TEST_F(LockScreenAshFocusRulesTest, RegainFocusAfterUnlock) {
169 std::unique_ptr<aura::Window> normal_window(CreateWindowInActiveDesk());
170 std::unique_ptr<aura::Window> always_on_top_window(
171 CreateWindowInAlwaysOnTopContainer());
172
173 wm::ActivateWindow(always_on_top_window.get());
174 wm::ActivateWindow(normal_window.get());
175
176 EXPECT_TRUE(wm::IsActiveWindow(normal_window.get()));
177 EXPECT_TRUE(normal_window->IsVisible());
178 EXPECT_TRUE(always_on_top_window->IsVisible());
179 EXPECT_TRUE(normal_window->HasFocus());
180 EXPECT_FALSE(always_on_top_window->HasFocus());
181
182 WindowState* normal_window_state = WindowState::Get(normal_window.get());
183 WindowState* always_on_top_window_state =
184 WindowState::Get(always_on_top_window.get());
185
186 EXPECT_TRUE(normal_window_state->CanActivate());
187 EXPECT_TRUE(always_on_top_window_state->CanActivate());
188
189 BlockUserSession(BLOCKED_BY_LOCK_SCREEN);
190
191 EXPECT_TRUE(Shell::Get()->session_controller()->IsScreenLocked());
192 EXPECT_FALSE(normal_window->HasFocus());
193 EXPECT_FALSE(always_on_top_window->HasFocus());
194 EXPECT_FALSE(normal_window_state->IsMinimized());
195 EXPECT_FALSE(always_on_top_window_state->IsMinimized());
196 EXPECT_FALSE(normal_window_state->CanActivate());
197 EXPECT_FALSE(always_on_top_window_state->CanActivate());
198
199 UnblockUserSession();
200
201 EXPECT_FALSE(Shell::Get()->session_controller()->IsScreenLocked());
202 EXPECT_FALSE(normal_window_state->IsMinimized());
203 EXPECT_FALSE(always_on_top_window_state->IsMinimized());
204 EXPECT_TRUE(normal_window_state->CanActivate());
205 EXPECT_TRUE(always_on_top_window_state->CanActivate());
206 EXPECT_FALSE(always_on_top_window->HasFocus());
207 EXPECT_TRUE(normal_window->HasFocus());
208 }
209
210 // Tests that if a widget has a view which should be initially focused, this
211 // view doesn't get focused if the widget shows behind the lock screen.
TEST_F(LockScreenAshFocusRulesTest,PreventFocusChangeWithLockScreenPresent)212 TEST_F(LockScreenAshFocusRulesTest, PreventFocusChangeWithLockScreenPresent) {
213 BlockUserSession(BLOCKED_BY_LOCK_SCREEN);
214 EXPECT_TRUE(Shell::Get()->session_controller()->IsScreenLocked());
215
216 views::test::TestInitialFocusWidgetDelegate delegate(GetContext());
217 EXPECT_FALSE(delegate.view()->HasFocus());
218 delegate.GetWidget()->Show();
219 EXPECT_FALSE(delegate.GetWidget()->IsActive());
220 EXPECT_FALSE(delegate.view()->HasFocus());
221
222 UnblockUserSession();
223 EXPECT_FALSE(Shell::Get()->session_controller()->IsScreenLocked());
224 EXPECT_TRUE(delegate.GetWidget()->IsActive());
225 EXPECT_TRUE(delegate.view()->HasFocus());
226 }
227
228 // Verifies that a window in lock container cannot be activated if a lock
229 // system modal window is shown.
TEST_F(LockScreenAshFocusRulesTest,PreventLockScreenActivationUnderLockSystemModalWindow)230 TEST_F(LockScreenAshFocusRulesTest,
231 PreventLockScreenActivationUnderLockSystemModalWindow) {
232 // System modal window - given that it's not lock system modal, it should
233 // have no impact on activation of windows while user session is locked.
234 std::unique_ptr<aura::Window> system_modal_window(
235 CreateWindowInSystemModalContainer());
236 EXPECT_TRUE(wm::IsActiveWindow(system_modal_window.get()));
237
238 BlockUserSession(BLOCKED_BY_LOCK_SCREEN);
239 EXPECT_TRUE(Shell::Get()->session_controller()->IsScreenLocked());
240
241 std::unique_ptr<aura::Window> lock_window(CreateWindowInLockContainer());
242 std::unique_ptr<aura::Window> lock_system_modal_window(
243 CreateWindowInLockSystemModalContainer());
244
245 EXPECT_TRUE(wm::IsActiveWindow(lock_system_modal_window.get()));
246
247 // Try to activate a lock container window - it should not succeed if a lock
248 // system modal dialog is present.
249 wm::ActivateWindow(lock_window.get());
250 EXPECT_TRUE(wm::IsActiveWindow(lock_system_modal_window.get()));
251
252 lock_system_modal_window.reset();
253
254 // Activating lock window should succeed after system modal widnow is closed.
255 wm::ActivateWindow(lock_window.get());
256 EXPECT_TRUE(wm::IsActiveWindow(lock_window.get()));
257
258 lock_window.reset();
259 EXPECT_FALSE(wm::IsActiveWindow(system_modal_window.get()));
260
261 UnblockUserSession();
262
263 // Upon unlocking the session, the system modal window should be reactivated.
264 EXPECT_TRUE(wm::IsActiveWindow(system_modal_window.get()));
265 }
266
267 // Verifies that the shelf can be activated in login/lock screen even if there
268 // is a lock system modal present.
TEST_F(LockScreenAshFocusRulesTest,AllowShelfActivationWithLockSystemModalWindow)269 TEST_F(LockScreenAshFocusRulesTest,
270 AllowShelfActivationWithLockSystemModalWindow) {
271 BlockUserSession(BLOCKED_BY_LOCK_SCREEN);
272 EXPECT_TRUE(Shell::Get()->session_controller()->IsScreenLocked());
273
274 std::unique_ptr<aura::Window> lock_window(CreateWindowInLockContainer());
275 std::unique_ptr<aura::Window> lock_shelf_window(
276 CreateWindowInShelfContainer());
277 std::unique_ptr<aura::Window> lock_system_modal_window(
278 CreateWindowInLockSystemModalContainer());
279 EXPECT_TRUE(wm::IsActiveWindow(lock_system_modal_window.get()));
280
281 wm::ActivateWindow(lock_shelf_window.get());
282 EXPECT_TRUE(wm::IsActiveWindow(lock_shelf_window.get()));
283 }
284
285 // Simulates a transient child dialog of the applist when it gets closed and
286 // loses focus, the focus should be returned to the applist transient parent,
287 // not to another window in the MRU list. https://crbug.com/950469.
TEST_F(LockScreenAshFocusRulesTest,TransientChildLosingFocus)288 TEST_F(LockScreenAshFocusRulesTest, TransientChildLosingFocus) {
289 std::unique_ptr<aura::Window> normal_window(CreateWindowInActiveDesk());
290 std::unique_ptr<aura::Window> transient_parent(
291 CreateWindowInAppListContainer());
292 std::unique_ptr<aura::Window> transient_child(
293 CreateWindowInAppListContainer());
294 ::wm::AddTransientChild(transient_parent.get(), transient_child.get());
295 wm::ActivateWindow(transient_child.get());
296 EXPECT_TRUE(wm::IsActiveWindow(transient_child.get()));
297
298 transient_child->Hide();
299 EXPECT_TRUE(wm::IsActiveWindow(transient_parent.get()));
300 }
301
302 } // namespace ash
303