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