| // Copyright 2015 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include <memory> |
| |
| #include "ash/public/cpp/shell_window_ids.h" |
| #include "ash/session/session_controller_impl.h" |
| #include "ash/session/test_pref_service_provider.h" |
| #include "ash/session/test_session_controller_client.h" |
| #include "ash/shelf/shelf.h" |
| #include "ash/shell.h" |
| #include "ash/test/ash_test_base.h" |
| #include "ash/test/ash_test_helper.h" |
| #include "ash/wm/desks/desks_util.h" |
| #include "ash/wm/lock_state_controller.h" |
| #include "ash/wm/window_state.h" |
| #include "ash/wm/window_util.h" |
| #include "chromeos/ash/components/login/auth/auth_events_recorder.h" |
| #include "ui/aura/client/aura_constants.h" |
| #include "ui/aura/client/window_parenting_client.h" |
| #include "ui/aura/window.h" |
| #include "ui/base/mojom/ui_base_types.mojom-shared.h" |
| #include "ui/base/ui_base_types.h" |
| #include "ui/views/test/widget_test.h" |
| #include "ui/views/view.h" |
| #include "ui/views/widget/widget.h" |
| #include "ui/wm/core/window_util.h" |
| |
| namespace ash { |
| |
| namespace { |
| |
| // Defines a class that will be used to test the correct behavior of |
| // |AshFocusRules| when locking and unlocking the screen. |
| class LockScreenAshFocusRulesTest : public AshTestBase { |
| public: |
| LockScreenAshFocusRulesTest() = default; |
| |
| LockScreenAshFocusRulesTest(const LockScreenAshFocusRulesTest&) = delete; |
| LockScreenAshFocusRulesTest& operator=(const LockScreenAshFocusRulesTest&) = |
| delete; |
| |
| ~LockScreenAshFocusRulesTest() override = default; |
| |
| void SetUp() override { |
| AshTestBase::SetUp(); |
| // Showing LockScreen requires auth event recorder. |
| auth_events_recorder_ = AuthEventsRecorder::CreateForTesting(); |
| GetSessionControllerClient()->set_show_lock_screen_views(true); |
| } |
| |
| void TearDown() override { |
| auth_events_recorder_.reset(); |
| AshTestBase::TearDown(); |
| } |
| |
| aura::Window* CreateWindowInActiveDesk() { |
| return CreateWindowInContainer(desks_util::GetActiveDeskContainerId()); |
| } |
| |
| aura::Window* CreateWindowInAppListContainer() { |
| return CreateWindowInContainer(kShellWindowId_AppListContainer); |
| } |
| |
| aura::Window* CreateWindowInAlwaysOnTopContainer() { |
| aura::Window* window = |
| CreateWindowInContainer(kShellWindowId_AlwaysOnTopContainer); |
| window->SetProperty(aura::client::kZOrderingKey, |
| ui::ZOrderLevel::kFloatingWindow); |
| return window; |
| } |
| |
| aura::Window* CreateWindowInLockContainer() { |
| return CreateWindowInContainer(kShellWindowId_LockScreenContainer); |
| } |
| |
| aura::Window* CreateWindowInShelfContainer() { |
| return CreateWindowInContainer(kShellWindowId_ShelfContainer); |
| } |
| |
| aura::Window* CreateWindowInLockSystemModalContainer() { |
| aura::Window* window = |
| CreateWindowInContainer(kShellWindowId_LockSystemModalContainer); |
| window->SetProperty(aura::client::kModalKey, ui::mojom::ModalType::kSystem); |
| return window; |
| } |
| |
| aura::Window* CreateWindowInSystemModalContainer() { |
| aura::Window* window = |
| CreateWindowInContainer(kShellWindowId_SystemModalContainer); |
| window->SetProperty(aura::client::kModalKey, ui::mojom::ModalType::kSystem); |
| return window; |
| } |
| |
| private: |
| aura::Window* CreateWindowInContainer(int container_id) { |
| aura::Window* root_window = Shell::GetPrimaryRootWindow(); |
| aura::Window* container = Shell::GetContainer(root_window, container_id); |
| aura::Window* window = new aura::Window(nullptr); |
| window->SetId(0); |
| window->SetType(aura::client::WINDOW_TYPE_NORMAL); |
| window->Init(ui::LAYER_TEXTURED); |
| window->Show(); |
| window->SetProperty(aura::client::kResizeBehaviorKey, |
| aura::client::kResizeBehaviorCanMaximize | |
| aura::client::kResizeBehaviorCanMinimize | |
| aura::client::kResizeBehaviorCanResize); |
| container->AddChild(window); |
| return window; |
| } |
| |
| std::unique_ptr<AuthEventsRecorder> auth_events_recorder_; |
| }; |
| |
| } // namespace |
| |
| // Verifies focus is returned (after unlocking the screen) to the most recent |
| // window that had it before locking the screen. |
| TEST_F(LockScreenAshFocusRulesTest, RegainFocusAfterUnlock) { |
| std::unique_ptr<aura::Window> normal_window(CreateWindowInActiveDesk()); |
| std::unique_ptr<aura::Window> always_on_top_window( |
| CreateWindowInAlwaysOnTopContainer()); |
| |
| wm::ActivateWindow(always_on_top_window.get()); |
| wm::ActivateWindow(normal_window.get()); |
| |
| EXPECT_TRUE(wm::IsActiveWindow(normal_window.get())); |
| EXPECT_TRUE(normal_window->IsVisible()); |
| EXPECT_TRUE(always_on_top_window->IsVisible()); |
| EXPECT_TRUE(normal_window->HasFocus()); |
| EXPECT_FALSE(always_on_top_window->HasFocus()); |
| |
| WindowState* normal_window_state = WindowState::Get(normal_window.get()); |
| WindowState* always_on_top_window_state = |
| WindowState::Get(always_on_top_window.get()); |
| |
| EXPECT_TRUE(normal_window_state->CanActivate()); |
| EXPECT_TRUE(always_on_top_window_state->CanActivate()); |
| |
| BlockUserSession(BLOCKED_BY_LOCK_SCREEN); |
| |
| EXPECT_TRUE(Shell::Get()->session_controller()->IsScreenLocked()); |
| EXPECT_FALSE(normal_window->HasFocus()); |
| EXPECT_FALSE(always_on_top_window->HasFocus()); |
| EXPECT_FALSE(normal_window_state->IsMinimized()); |
| EXPECT_FALSE(always_on_top_window_state->IsMinimized()); |
| EXPECT_FALSE(normal_window_state->CanActivate()); |
| EXPECT_FALSE(always_on_top_window_state->CanActivate()); |
| |
| UnblockUserSession(); |
| |
| EXPECT_FALSE(Shell::Get()->session_controller()->IsScreenLocked()); |
| EXPECT_FALSE(normal_window_state->IsMinimized()); |
| EXPECT_FALSE(always_on_top_window_state->IsMinimized()); |
| EXPECT_TRUE(normal_window_state->CanActivate()); |
| EXPECT_TRUE(always_on_top_window_state->CanActivate()); |
| EXPECT_FALSE(always_on_top_window->HasFocus()); |
| EXPECT_TRUE(normal_window->HasFocus()); |
| } |
| |
| // Tests that if a widget has a view which should be initially focused, this |
| // view doesn't get focused if the widget shows behind the lock screen. |
| TEST_F(LockScreenAshFocusRulesTest, PreventFocusChangeWithLockScreenPresent) { |
| BlockUserSession(BLOCKED_BY_LOCK_SCREEN); |
| EXPECT_TRUE(Shell::Get()->session_controller()->IsScreenLocked()); |
| |
| views::test::TestInitialFocusWidgetDelegate delegate(GetContext()); |
| EXPECT_FALSE(delegate.view()->HasFocus()); |
| delegate.GetWidget()->Show(); |
| EXPECT_FALSE(delegate.GetWidget()->IsActive()); |
| EXPECT_FALSE(delegate.view()->HasFocus()); |
| |
| UnblockUserSession(); |
| EXPECT_FALSE(Shell::Get()->session_controller()->IsScreenLocked()); |
| EXPECT_TRUE(delegate.GetWidget()->IsActive()); |
| EXPECT_TRUE(delegate.view()->HasFocus()); |
| } |
| |
| // Verifies that a window in lock container cannot be activated if a lock |
| // system modal window is shown. |
| TEST_F(LockScreenAshFocusRulesTest, |
| PreventLockScreenActivationUnderLockSystemModalWindow) { |
| // System modal window - given that it's not lock system modal, it should |
| // have no impact on activation of windows while user session is locked. |
| std::unique_ptr<aura::Window> system_modal_window( |
| CreateWindowInSystemModalContainer()); |
| EXPECT_TRUE(wm::IsActiveWindow(system_modal_window.get())); |
| |
| BlockUserSession(BLOCKED_BY_LOCK_SCREEN); |
| EXPECT_TRUE(Shell::Get()->session_controller()->IsScreenLocked()); |
| |
| std::unique_ptr<aura::Window> lock_window(CreateWindowInLockContainer()); |
| std::unique_ptr<aura::Window> lock_system_modal_window( |
| CreateWindowInLockSystemModalContainer()); |
| |
| EXPECT_TRUE(wm::IsActiveWindow(lock_system_modal_window.get())); |
| |
| // Try to activate a lock container window - it should not succeed if a lock |
| // system modal dialog is present. |
| wm::ActivateWindow(lock_window.get()); |
| EXPECT_TRUE(wm::IsActiveWindow(lock_system_modal_window.get())); |
| |
| lock_system_modal_window.reset(); |
| |
| // Activating lock window should succeed after system modal widnow is closed. |
| wm::ActivateWindow(lock_window.get()); |
| EXPECT_TRUE(wm::IsActiveWindow(lock_window.get())); |
| |
| lock_window.reset(); |
| EXPECT_FALSE(wm::IsActiveWindow(system_modal_window.get())); |
| |
| UnblockUserSession(); |
| |
| // Upon unlocking the session, the system modal window should be reactivated. |
| EXPECT_TRUE(wm::IsActiveWindow(system_modal_window.get())); |
| } |
| |
| // Verifies that the shelf can be activated in login/lock screen even if there |
| // is a lock system modal present. |
| TEST_F(LockScreenAshFocusRulesTest, |
| AllowShelfActivationWithLockSystemModalWindow) { |
| BlockUserSession(BLOCKED_BY_LOCK_SCREEN); |
| EXPECT_TRUE(Shell::Get()->session_controller()->IsScreenLocked()); |
| |
| std::unique_ptr<aura::Window> lock_window(CreateWindowInLockContainer()); |
| std::unique_ptr<aura::Window> lock_shelf_window( |
| CreateWindowInShelfContainer()); |
| std::unique_ptr<aura::Window> lock_system_modal_window( |
| CreateWindowInLockSystemModalContainer()); |
| EXPECT_TRUE(wm::IsActiveWindow(lock_system_modal_window.get())); |
| |
| wm::ActivateWindow(lock_shelf_window.get()); |
| EXPECT_TRUE(wm::IsActiveWindow(lock_shelf_window.get())); |
| } |
| |
| // Simulates a transient child dialog of the applist when it gets closed and |
| // loses focus, the focus should be returned to the applist transient parent, |
| // not to another window in the MRU list. https://crbug.com/950469. |
| TEST_F(LockScreenAshFocusRulesTest, TransientChildLosingFocus) { |
| std::unique_ptr<aura::Window> normal_window(CreateWindowInActiveDesk()); |
| std::unique_ptr<aura::Window> transient_parent( |
| CreateWindowInAppListContainer()); |
| std::unique_ptr<aura::Window> transient_child( |
| CreateWindowInAppListContainer()); |
| ::wm::AddTransientChild(transient_parent.get(), transient_child.get()); |
| wm::ActivateWindow(transient_child.get()); |
| EXPECT_TRUE(wm::IsActiveWindow(transient_child.get())); |
| |
| transient_child->Hide(); |
| EXPECT_TRUE(wm::IsActiveWindow(transient_parent.get())); |
| } |
| |
| } // namespace ash |