123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794 |
- // 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 "components/exo/ui_lock_controller.h"
- #include "ash/constants/ash_features.h"
- #include "ash/shell.h"
- #include "ash/wm/window_state.h"
- #include "base/feature_list.h"
- #include "base/test/power_monitor_test.h"
- #include "base/test/scoped_feature_list.h"
- #include "chromeos/dbus/power/fake_power_manager_client.h"
- #include "chromeos/dbus/power/power_manager_client.h"
- #include "chromeos/dbus/power_manager/backlight.pb.h"
- #include "chromeos/ui/base/window_properties.h"
- #include "components/exo/buffer.h"
- #include "components/exo/display.h"
- #include "components/exo/pointer.h"
- #include "components/exo/pointer_constraint_delegate.h"
- #include "components/exo/pointer_delegate.h"
- #include "components/exo/shell_surface.h"
- #include "components/exo/surface.h"
- #include "components/exo/test/exo_test_base.h"
- #include "components/exo/test/exo_test_helper.h"
- #include "components/exo/test/shell_surface_builder.h"
- #include "components/exo/wm_helper.h"
- #include "components/fullscreen_control/fullscreen_control_popup.h"
- #include "testing/gmock/include/gmock/gmock.h"
- #include "testing/gtest/include/gtest/gtest.h"
- #include "ui/base/class_property.h"
- #include "ui/gfx/animation/animation_test_api.h"
- #include "ui/wm/core/window_util.h"
- namespace exo {
- namespace {
- constexpr char kNoEscHoldAppId[] = "no-esc-hold";
- constexpr char kOverviewToExitAppId[] = "overview-to-exit";
- aura::Window* GetTopLevelWindow(
- const std::unique_ptr<ShellSurface>& shell_surface) {
- auto* top_level_widget = views::Widget::GetTopLevelWidgetForNativeView(
- shell_surface->host_window());
- assert(top_level_widget);
- return top_level_widget->GetNativeWindow();
- }
- ash::WindowState* GetTopLevelWindowState(
- const std::unique_ptr<ShellSurface>& shell_surface) {
- return ash::WindowState::Get(GetTopLevelWindow(shell_surface));
- }
- class MockPointerDelegate : public PointerDelegate {
- public:
- MockPointerDelegate() {
- EXPECT_CALL(*this, CanAcceptPointerEventsForSurface(testing::_))
- .WillRepeatedly(testing::Return(true));
- }
- // Overridden from PointerDelegate:
- MOCK_METHOD1(OnPointerDestroying, void(Pointer*));
- MOCK_CONST_METHOD1(CanAcceptPointerEventsForSurface, bool(Surface*));
- MOCK_METHOD3(OnPointerEnter, void(Surface*, const gfx::PointF&, int));
- MOCK_METHOD1(OnPointerLeave, void(Surface*));
- MOCK_METHOD2(OnPointerMotion, void(base::TimeTicks, const gfx::PointF&));
- MOCK_METHOD3(OnPointerButton, void(base::TimeTicks, int, bool));
- MOCK_METHOD3(OnPointerScroll,
- void(base::TimeTicks, const gfx::Vector2dF&, bool));
- MOCK_METHOD1(OnPointerScrollStop, void(base::TimeTicks));
- MOCK_METHOD0(OnPointerFrame, void());
- };
- class MockPointerConstraintDelegate : public PointerConstraintDelegate {
- public:
- MockPointerConstraintDelegate(Pointer* pointer, Surface* surface)
- : pointer_(pointer) {
- EXPECT_CALL(*this, GetConstrainedSurface())
- .WillRepeatedly(testing::Return(surface));
- ON_CALL(*this, OnConstraintActivated).WillByDefault([this]() {
- activated_count++;
- });
- ON_CALL(*this, OnConstraintBroken).WillByDefault([this]() {
- broken_count++;
- });
- }
- ~MockPointerConstraintDelegate() {
- // Notifying destruction here removes some boilerplate from tests.
- pointer_->OnPointerConstraintDelegateDestroying(this);
- }
- // Overridden from PointerConstraintDelegate:
- MOCK_METHOD0(OnConstraintActivated, void());
- MOCK_METHOD0(OnAlreadyConstrained, void());
- MOCK_METHOD0(OnConstraintBroken, void());
- MOCK_METHOD0(IsPersistent, bool());
- MOCK_METHOD0(GetConstrainedSurface, Surface*());
- MOCK_METHOD0(OnDefunct, void());
- raw_ptr<Pointer> pointer_;
- int activated_count = 0;
- int broken_count = 0;
- };
- class UILockControllerTest : public test::ExoTestBase {
- public:
- UILockControllerTest()
- : test::ExoTestBase(base::test::TaskEnvironment::TimeSource::MOCK_TIME) {}
- ~UILockControllerTest() override = default;
- UILockControllerTest(const UILockControllerTest&) = delete;
- UILockControllerTest& operator=(const UILockControllerTest&) = delete;
- protected:
- class TestPropertyResolver : public exo::WMHelper::AppPropertyResolver {
- public:
- TestPropertyResolver() = default;
- ~TestPropertyResolver() override = default;
- void PopulateProperties(
- const Params& params,
- ui::PropertyHandler& out_properties_container) override {
- out_properties_container.SetProperty(
- chromeos::kEscHoldToExitFullscreen,
- params.app_id != kNoEscHoldAppId &&
- params.app_id != kOverviewToExitAppId);
- out_properties_container.SetProperty(
- chromeos::kUseOverviewToExitFullscreen,
- params.app_id == kOverviewToExitAppId);
- out_properties_container.SetProperty(
- chromeos::kUseOverviewToExitPointerLock,
- params.app_id == kOverviewToExitAppId);
- }
- };
- // test::ExoTestBase:
- void SetUp() override {
- test::ExoTestBase::SetUp();
- seat_ = std::make_unique<Seat>();
- scoped_feature_list_.InitWithFeatures(
- {chromeos::features::kExoLockNotification}, {});
- WMHelper::GetInstance()->RegisterAppPropertyResolver(
- std::make_unique<TestPropertyResolver>());
- }
- void TearDown() override {
- seat_.reset();
- test::ExoTestBase::TearDown();
- }
- std::unique_ptr<ShellSurface> BuildSurface(gfx::Point origin, int w, int h) {
- test::ShellSurfaceBuilder builder({w, h});
- builder.SetOrigin(origin);
- return builder.BuildShellSurface();
- }
- std::unique_ptr<ShellSurface> BuildSurface(int w, int h) {
- return BuildSurface(gfx::Point(0, 0), w, h);
- }
- views::Widget* GetEscNotification(
- const std::unique_ptr<ShellSurface>& surface) {
- return seat_->GetUILockControllerForTesting()->GetEscNotificationForTesting(
- GetTopLevelWindow(surface));
- }
- views::Widget* GetPointerCaptureNotification(
- const std::unique_ptr<ShellSurface>& surface) {
- return seat_->GetUILockControllerForTesting()
- ->GetPointerCaptureNotificationForTesting(GetTopLevelWindow(surface));
- }
- bool IsExitPopupVisible(aura::Window* window) {
- FullscreenControlPopup* popup =
- seat_->GetUILockControllerForTesting()->GetExitPopupForTesting(window);
- if (popup && popup->IsAnimating()) {
- gfx::AnimationTestApi animation_api(popup->GetAnimationForTesting());
- base::TimeTicks now = base::TimeTicks::Now();
- animation_api.SetStartTime(now);
- animation_api.Step(now + base::Milliseconds(500));
- }
- return popup && popup->IsVisible();
- }
- std::unique_ptr<Seat> seat_;
- base::test::ScopedFeatureList scoped_feature_list_;
- };
- TEST_F(UILockControllerTest, HoldingEscapeExitsFullscreen) {
- std::unique_ptr<ShellSurface> test_surface = BuildSurface(1024, 768);
- test_surface->SetUseImmersiveForFullscreen(false);
- test_surface->SetFullscreen(true);
- test_surface->surface_for_testing()->Commit();
- auto* window_state = GetTopLevelWindowState(test_surface);
- EXPECT_TRUE(window_state->IsFullscreen());
- GetEventGenerator()->PressKey(ui::VKEY_ESCAPE, ui::EF_NONE);
- task_environment()->FastForwardBy(base::Seconds(1));
- EXPECT_TRUE(window_state->IsFullscreen()); // no change yet
- task_environment()->FastForwardBy(base::Seconds(1));
- EXPECT_FALSE(window_state->IsFullscreen());
- EXPECT_TRUE(window_state->IsNormalStateType());
- }
- TEST_F(UILockControllerTest, HoldingCtrlEscapeDoesNotExitFullscreen) {
- std::unique_ptr<ShellSurface> test_surface = BuildSurface(1024, 768);
- test_surface->SetUseImmersiveForFullscreen(false);
- test_surface->SetFullscreen(true);
- test_surface->surface_for_testing()->Commit();
- auto* window_state = GetTopLevelWindowState(test_surface);
- EXPECT_TRUE(window_state->IsFullscreen());
- GetEventGenerator()->PressKey(ui::VKEY_ESCAPE, ui::EF_CONTROL_DOWN);
- task_environment()->FastForwardBy(base::Seconds(2));
- EXPECT_TRUE(window_state->IsFullscreen());
- }
- TEST_F(UILockControllerTest,
- HoldingEscapeOnlyExitsFullscreenIfWindowPropertySet) {
- std::unique_ptr<ShellSurface> test_surface = BuildSurface(1024, 768);
- // Do not set chromeos::kEscHoldToExitFullscreen on TopLevelWindow.
- test_surface->SetApplicationId(kNoEscHoldAppId);
- test_surface->SetUseImmersiveForFullscreen(false);
- test_surface->SetFullscreen(true);
- test_surface->surface_for_testing()->Commit();
- auto* window_state = GetTopLevelWindowState(test_surface);
- EXPECT_TRUE(window_state->IsFullscreen());
- GetEventGenerator()->PressKey(ui::VKEY_ESCAPE, ui::EF_NONE);
- task_environment()->FastForwardBy(base::Seconds(2));
- EXPECT_TRUE(window_state->IsFullscreen());
- }
- TEST_F(UILockControllerTest, HoldingEscapeOnlyExitsFocusedFullscreen) {
- std::unique_ptr<ShellSurface> test_surface1 = BuildSurface(1024, 768);
- test_surface1->SetUseImmersiveForFullscreen(false);
- test_surface1->SetFullscreen(true);
- test_surface1->surface_for_testing()->Commit();
- std::unique_ptr<ShellSurface> test_surface2 = BuildSurface(1024, 768);
- test_surface2->SetUseImmersiveForFullscreen(false);
- test_surface2->SetFullscreen(true);
- test_surface2->surface_for_testing()->Commit();
- GetEventGenerator()->PressKey(ui::VKEY_ESCAPE, ui::EF_NONE);
- task_environment()->FastForwardBy(base::Seconds(2));
- EXPECT_TRUE(GetTopLevelWindowState(test_surface1)->IsFullscreen());
- EXPECT_FALSE(GetTopLevelWindowState(test_surface2)->IsFullscreen());
- }
- TEST_F(UILockControllerTest, DestroyingWindowCancels) {
- std::unique_ptr<ShellSurface> test_surface = BuildSurface(1024, 768);
- test_surface->SetUseImmersiveForFullscreen(false);
- test_surface->SetFullscreen(true);
- test_surface->surface_for_testing()->Commit();
- auto* window_state = GetTopLevelWindowState(test_surface);
- EXPECT_TRUE(window_state->IsFullscreen());
- GetEventGenerator()->PressKey(ui::VKEY_ESCAPE, ui::EF_NONE);
- task_environment()->FastForwardBy(base::Seconds(1));
- test_surface.reset(); // Destroying the Surface destroys the Window
- task_environment()->FastForwardBy(base::Seconds(3));
- // The implicit assertion is that the code doesn't crash.
- }
- TEST_F(UILockControllerTest, FocusChangeCancels) {
- // Arrange: two windows, one is fullscreen and focused
- std::unique_ptr<ShellSurface> other_surface = BuildSurface(1024, 768);
- other_surface->surface_for_testing()->Commit();
- std::unique_ptr<ShellSurface> fullscreen_surface = BuildSurface(1024, 768);
- fullscreen_surface->SetUseImmersiveForFullscreen(false);
- fullscreen_surface->SetFullscreen(true);
- fullscreen_surface->surface_for_testing()->Commit();
- EXPECT_EQ(fullscreen_surface->surface_for_testing(),
- seat_->GetFocusedSurface());
- EXPECT_FALSE(GetTopLevelWindowState(fullscreen_surface)->IsMinimized());
- // Act: Press escape, then toggle focus back and forth
- GetEventGenerator()->PressKey(ui::VKEY_ESCAPE, ui::EF_NONE);
- task_environment()->FastForwardBy(base::Seconds(1));
- wm::ActivateWindow(other_surface->surface_for_testing()->window());
- wm::ActivateWindow(fullscreen_surface->surface_for_testing()->window());
- task_environment()->FastForwardBy(base::Seconds(2));
- // Assert: Fullscreen window was not minimized, despite regaining focus.
- EXPECT_FALSE(GetTopLevelWindowState(fullscreen_surface)->IsMinimized());
- EXPECT_EQ(fullscreen_surface->surface_for_testing(),
- seat_->GetFocusedSurface());
- }
- TEST_F(UILockControllerTest, ShortHoldEscapeDoesNotExitFullscreen) {
- std::unique_ptr<ShellSurface> test_surface = BuildSurface(1024, 768);
- test_surface->SetUseImmersiveForFullscreen(false);
- test_surface->SetFullscreen(true);
- test_surface->surface_for_testing()->Commit();
- auto* window_state = GetTopLevelWindowState(test_surface);
- GetEventGenerator()->PressKey(ui::VKEY_ESCAPE, ui::EF_NONE);
- task_environment()->FastForwardBy(base::Seconds(1));
- GetEventGenerator()->ReleaseKey(ui::VKEY_ESCAPE, ui::EF_NONE);
- task_environment()->FastForwardBy(base::Seconds(2));
- EXPECT_TRUE(window_state->IsFullscreen());
- }
- TEST_F(UILockControllerTest, FullScreenShowsEscNotification) {
- std::unique_ptr<ShellSurface> test_surface = BuildSurface(1024, 768);
- test_surface->SetUseImmersiveForFullscreen(false);
- test_surface->SetFullscreen(true);
- test_surface->surface_for_testing()->Commit();
- EXPECT_TRUE(GetTopLevelWindowState(test_surface)->IsFullscreen());
- EXPECT_TRUE(GetEscNotification(test_surface));
- }
- TEST_F(UILockControllerTest, EscNotificationClosesAfterDuration) {
- std::unique_ptr<ShellSurface> test_surface = BuildSurface(1024, 768);
- test_surface->SetUseImmersiveForFullscreen(false);
- test_surface->SetFullscreen(true);
- test_surface->surface_for_testing()->Commit();
- EXPECT_TRUE(GetEscNotification(test_surface));
- task_environment()->FastForwardBy(base::Seconds(5));
- EXPECT_FALSE(GetEscNotification(test_surface));
- }
- TEST_F(UILockControllerTest, HoldingEscapeHidesNotification) {
- std::unique_ptr<ShellSurface> test_surface = BuildSurface(1024, 768);
- test_surface->SetUseImmersiveForFullscreen(false);
- test_surface->SetFullscreen(true);
- test_surface->surface_for_testing()->Commit();
- EXPECT_TRUE(GetTopLevelWindowState(test_surface)->IsFullscreen());
- EXPECT_TRUE(GetEscNotification(test_surface));
- GetEventGenerator()->PressKey(ui::VKEY_ESCAPE, ui::EF_NONE);
- task_environment()->FastForwardBy(base::Seconds(3));
- EXPECT_FALSE(GetTopLevelWindowState(test_surface)->IsFullscreen());
- EXPECT_FALSE(GetEscNotification(test_surface));
- }
- TEST_F(UILockControllerTest, LosingFullscreenHidesNotification) {
- std::unique_ptr<ShellSurface> test_surface = BuildSurface(1024, 768);
- test_surface->SetUseImmersiveForFullscreen(false);
- test_surface->SetFullscreen(true);
- test_surface->surface_for_testing()->Commit();
- EXPECT_TRUE(GetTopLevelWindowState(test_surface)->IsFullscreen());
- EXPECT_TRUE(GetEscNotification(test_surface));
- // Have surface loose fullscreen, notification should now be hidden.
- test_surface->Minimize();
- test_surface->SetFullscreen(false);
- test_surface->surface_for_testing()->Commit();
- EXPECT_FALSE(GetTopLevelWindowState(test_surface)->IsFullscreen());
- EXPECT_FALSE(
- seat_->GetUILockControllerForTesting()->GetEscNotificationForTesting(
- GetTopLevelWindow(test_surface)));
- }
- TEST_F(UILockControllerTest, EscNotificationIsReshownIfInterrupted) {
- std::unique_ptr<ShellSurface> test_surface = BuildSurface(1024, 768);
- test_surface->SetUseImmersiveForFullscreen(false);
- test_surface->SetFullscreen(true);
- test_surface->surface_for_testing()->Commit();
- EXPECT_TRUE(GetEscNotification(test_surface));
- // Stop fullscreen.
- test_surface->SetFullscreen(false);
- EXPECT_FALSE(
- seat_->GetUILockControllerForTesting()->GetEscNotificationForTesting(
- GetTopLevelWindow(test_surface)));
- // Fullscreen should show notification since it did not stay visible for
- // duration.
- test_surface->SetFullscreen(true);
- EXPECT_TRUE(GetEscNotification(test_surface));
- // After duration, notification should be removed.
- task_environment()->FastForwardBy(base::Seconds(5));
- EXPECT_FALSE(GetEscNotification(test_surface));
- // Notification is shown after fullscreen toggle.
- test_surface->SetFullscreen(false);
- test_surface->SetFullscreen(true);
- EXPECT_TRUE(GetEscNotification(test_surface));
- }
- TEST_F(UILockControllerTest, EscNotificationIsReshownAfterUnlock) {
- // Arrange: Go fullscreen and time out the notification.
- std::unique_ptr<ShellSurface> test_surface = BuildSurface(1024, 768);
- test_surface->SetUseImmersiveForFullscreen(false);
- test_surface->SetFullscreen(true);
- test_surface->surface_for_testing()->Commit();
- task_environment()->FastForwardBy(base::Seconds(10));
- // Ensure the notification did time out; if not, we can't trust the test
- // result.
- EXPECT_FALSE(GetEscNotification(test_surface));
- // Act: Simulate locking and unlocking.
- GetSessionControllerClient()->LockScreen();
- GetSessionControllerClient()->UnlockScreen();
- // Assert: Notification shown again.
- EXPECT_TRUE(GetEscNotification(test_surface));
- }
- TEST_F(UILockControllerTest, EscNotificationReshownWhenScreenTurnedOn) {
- // Arrange: Set up a pointer capture notification, then let it expire.
- std::unique_ptr<ShellSurface> test_surface = BuildSurface(1024, 768);
- test_surface->SetUseImmersiveForFullscreen(false);
- test_surface->SetFullscreen(true);
- test_surface->surface_for_testing()->Commit();
- task_environment()->FastForwardBy(base::Seconds(10));
- // Ensure the notification did time out; if not, we can't trust the test
- // result.
- EXPECT_FALSE(GetEscNotification(test_surface));
- // Act: Simulate turning the backlight off and on again.
- power_manager::SetBacklightBrightnessRequest request;
- request.set_percent(0);
- chromeos::FakePowerManagerClient::Get()->SetScreenBrightness(request);
- base::RunLoop().RunUntilIdle();
- request.set_percent(100);
- chromeos::FakePowerManagerClient::Get()->SetScreenBrightness(request);
- base::RunLoop().RunUntilIdle();
- // Assert: Notification shown again.
- EXPECT_TRUE(GetEscNotification(test_surface));
- }
- TEST_F(UILockControllerTest, EscNotificationReshownWhenLidReopened) {
- // Arrange: Set up a pointer capture notification, then let it expire.
- std::unique_ptr<ShellSurface> test_surface = BuildSurface(1024, 768);
- test_surface->SetUseImmersiveForFullscreen(false);
- test_surface->SetFullscreen(true);
- test_surface->surface_for_testing()->Commit();
- task_environment()->FastForwardBy(base::Seconds(10));
- // Ensure the notification did time out; if not, we can't trust the test
- // result.
- EXPECT_FALSE(GetEscNotification(test_surface));
- // Act: Simulate closing and reopening the lid.
- chromeos::FakePowerManagerClient::Get()->SetLidState(
- chromeos::PowerManagerClient::LidState::CLOSED, base::TimeTicks::Now());
- chromeos::FakePowerManagerClient::Get()->SetLidState(
- chromeos::PowerManagerClient::LidState::OPEN, base::TimeTicks::Now());
- // Assert: Notification shown again.
- EXPECT_TRUE(GetEscNotification(test_surface));
- }
- TEST_F(UILockControllerTest, EscNotificationShowsOnSecondaryDisplay) {
- // Create surface on secondary display.
- UpdateDisplay("900x800,70x600");
- std::unique_ptr<ShellSurface> test_surface =
- BuildSurface(gfx::Point(900, 100), 200, 200);
- test_surface->SetUseImmersiveForFullscreen(false);
- test_surface->SetFullscreen(true);
- test_surface->surface_for_testing()->Commit();
- // Esc notification should be in secondary display.
- views::Widget* esc_notification = GetEscNotification(test_surface);
- EXPECT_TRUE(GetSecondaryDisplay().bounds().Contains(
- esc_notification->GetWindowBoundsInScreen()));
- }
- TEST_F(UILockControllerTest, PointerLockShowsNotification) {
- std::unique_ptr<ShellSurface> test_surface = BuildSurface(1024, 768);
- test_surface->SetApplicationId(kOverviewToExitAppId);
- test_surface->surface_for_testing()->Commit();
- testing::NiceMock<MockPointerDelegate> delegate;
- Pointer pointer(&delegate, seat_.get());
- testing::NiceMock<MockPointerConstraintDelegate> constraint(
- &pointer, test_surface->surface_for_testing());
- EXPECT_FALSE(GetPointerCaptureNotification(test_surface));
- EXPECT_TRUE(pointer.ConstrainPointer(&constraint));
- EXPECT_TRUE(GetPointerCaptureNotification(test_surface));
- }
- TEST_F(UILockControllerTest, PointerLockNotificationObeysCooldown) {
- // Arrange: Set up a pointer capture notification.
- std::unique_ptr<ShellSurface> test_surface = BuildSurface(1024, 768);
- test_surface->SetApplicationId(kOverviewToExitAppId);
- test_surface->surface_for_testing()->Commit();
- testing::NiceMock<MockPointerDelegate> delegate;
- Pointer pointer(&delegate, seat_.get());
- testing::NiceMock<MockPointerConstraintDelegate> constraint(
- &pointer, test_surface->surface_for_testing());
- EXPECT_TRUE(pointer.ConstrainPointer(&constraint));
- EXPECT_TRUE(GetPointerCaptureNotification(test_surface));
- // Act: Wait for the notification to timeout.
- task_environment()->FastForwardBy(base::Seconds(5));
- // Assert: Notification has disappeared.
- EXPECT_FALSE(GetPointerCaptureNotification(test_surface));
- // Act: Remove and re-apply the constraint.
- pointer.OnPointerConstraintDelegateDestroying(&constraint);
- EXPECT_TRUE(pointer.ConstrainPointer(&constraint));
- // Assert: Notification not shown due to the cooldown.
- EXPECT_FALSE(GetPointerCaptureNotification(test_surface));
- // Act: Wait for the cooldown, then re-apply again
- pointer.OnPointerConstraintDelegateDestroying(&constraint);
- task_environment()->FastForwardBy(base::Minutes(5));
- EXPECT_TRUE(pointer.ConstrainPointer(&constraint));
- // Assert: Cooldown has expired so notification is shown.
- EXPECT_TRUE(GetPointerCaptureNotification(test_surface));
- }
- TEST_F(UILockControllerTest, PointerLockNotificationReshownOnLidOpen) {
- // Arrange: Set up a pointer capture notification, then let it expire.
- std::unique_ptr<ShellSurface> test_surface = BuildSurface(1024, 768);
- test_surface->SetApplicationId(kOverviewToExitAppId);
- test_surface->surface_for_testing()->Commit();
- testing::NiceMock<MockPointerDelegate> delegate;
- Pointer pointer(&delegate, seat_.get());
- testing::NiceMock<MockPointerConstraintDelegate> constraint(
- &pointer, test_surface->surface_for_testing());
- EXPECT_TRUE(pointer.ConstrainPointer(&constraint));
- EXPECT_TRUE(GetPointerCaptureNotification(test_surface));
- task_environment()->FastForwardBy(base::Seconds(5));
- EXPECT_FALSE(GetPointerCaptureNotification(test_surface));
- // Act: Simulate closing and reopening the lid.
- chromeos::FakePowerManagerClient::Get()->SetLidState(
- chromeos::PowerManagerClient::LidState::CLOSED, base::TimeTicks::Now());
- chromeos::FakePowerManagerClient::Get()->SetLidState(
- chromeos::PowerManagerClient::LidState::OPEN, base::TimeTicks::Now());
- // Assert: Notification shown again.
- EXPECT_TRUE(GetPointerCaptureNotification(test_surface));
- }
- TEST_F(UILockControllerTest, PointerLockNotificationReshownWhenScreenTurnedOn) {
- // Arrange: Set up a pointer capture notification, then let it expire.
- std::unique_ptr<ShellSurface> test_surface = BuildSurface(1024, 768);
- test_surface->SetApplicationId(kOverviewToExitAppId);
- test_surface->surface_for_testing()->Commit();
- testing::NiceMock<MockPointerDelegate> delegate;
- Pointer pointer(&delegate, seat_.get());
- testing::NiceMock<MockPointerConstraintDelegate> constraint(
- &pointer, test_surface->surface_for_testing());
- EXPECT_TRUE(pointer.ConstrainPointer(&constraint));
- EXPECT_TRUE(GetPointerCaptureNotification(test_surface));
- task_environment()->FastForwardBy(base::Seconds(5));
- EXPECT_FALSE(GetPointerCaptureNotification(test_surface));
- // Act: Simulate turning the backlight off and on again.
- power_manager::SetBacklightBrightnessRequest request;
- request.set_percent(0);
- chromeos::FakePowerManagerClient::Get()->SetScreenBrightness(request);
- base::RunLoop().RunUntilIdle();
- request.set_percent(100);
- chromeos::FakePowerManagerClient::Get()->SetScreenBrightness(request);
- base::RunLoop().RunUntilIdle();
- // Assert: Notification shown again.
- EXPECT_TRUE(GetPointerCaptureNotification(test_surface));
- }
- TEST_F(UILockControllerTest, PointerLockNotificationReshownOnUnlock) {
- // Arrange: Set up a pointer capture notification, then let it expire.
- std::unique_ptr<ShellSurface> test_surface = BuildSurface(1024, 768);
- test_surface->SetApplicationId(kOverviewToExitAppId);
- test_surface->surface_for_testing()->Commit();
- testing::NiceMock<MockPointerDelegate> delegate;
- Pointer pointer(&delegate, seat_.get());
- testing::NiceMock<MockPointerConstraintDelegate> constraint(
- &pointer, test_surface->surface_for_testing());
- EXPECT_TRUE(pointer.ConstrainPointer(&constraint));
- task_environment()->FastForwardBy(base::Seconds(5));
- EXPECT_FALSE(GetPointerCaptureNotification(test_surface));
- // Act: Simulate locking and unlocking.
- GetSessionControllerClient()->LockScreen();
- GetSessionControllerClient()->UnlockScreen();
- // Assert: Notification shown again.
- EXPECT_TRUE(GetPointerCaptureNotification(test_surface));
- }
- TEST_F(UILockControllerTest, PointerLockNotificationReshownAfterSuspend) {
- // Arrange: Set up a pointer capture notification, then let it expire.
- std::unique_ptr<ShellSurface> test_surface = BuildSurface(1024, 768);
- test_surface->SetApplicationId(kOverviewToExitAppId);
- test_surface->surface_for_testing()->Commit();
- testing::NiceMock<MockPointerDelegate> delegate;
- Pointer pointer(&delegate, seat_.get());
- testing::NiceMock<MockPointerConstraintDelegate> constraint(
- &pointer, test_surface->surface_for_testing());
- EXPECT_TRUE(pointer.ConstrainPointer(&constraint));
- EXPECT_TRUE(GetPointerCaptureNotification(test_surface));
- task_environment()->FastForwardBy(base::Seconds(5));
- EXPECT_FALSE(GetPointerCaptureNotification(test_surface));
- // Act: Simulate suspend and resume
- chromeos::FakePowerManagerClient::Get()->SendSuspendImminent(
- power_manager::SuspendImminent_Reason_IDLE);
- task_environment()->FastForwardBy(base::Minutes(1));
- chromeos::FakePowerManagerClient::Get()->SendSuspendDone(base::Minutes(1));
- // Assert: Notification shown again.
- EXPECT_TRUE(GetPointerCaptureNotification(test_surface));
- }
- TEST_F(UILockControllerTest, PointerLockNotificationReshownAfterIdle) {
- // Arrange: Set up a pointer capture notification, then let it expire.
- std::unique_ptr<ShellSurface> test_surface = BuildSurface(1024, 768);
- test_surface->SetApplicationId(kOverviewToExitAppId);
- test_surface->surface_for_testing()->Commit();
- testing::NiceMock<MockPointerDelegate> delegate;
- Pointer pointer(&delegate, seat_.get());
- testing::NiceMock<MockPointerConstraintDelegate> constraint(
- &pointer, test_surface->surface_for_testing());
- EXPECT_TRUE(pointer.ConstrainPointer(&constraint));
- EXPECT_TRUE(GetPointerCaptureNotification(test_surface));
- task_environment()->FastForwardBy(base::Seconds(5));
- EXPECT_FALSE(GetPointerCaptureNotification(test_surface));
- // Act: Simulate activity, then go idle.
- seat_->GetUILockControllerForTesting()->OnUserActivity(/*event=*/nullptr);
- task_environment()->FastForwardBy(base::Minutes(10));
- // Assert: Notification not yet shown again.
- EXPECT_FALSE(GetPointerCaptureNotification(test_surface));
- // Act: Simulate activity after being idle.
- seat_->GetUILockControllerForTesting()->OnUserActivity(/*event=*/nullptr);
- // Assert: Notification shown again.
- EXPECT_TRUE(GetPointerCaptureNotification(test_surface));
- }
- TEST_F(UILockControllerTest, PointerLockCooldownResetForAllWindows) {
- // Arrange: Create two surfaces, one with a pointer lock notification.
- std::unique_ptr<ShellSurface> other_surface = BuildSurface(1024, 768);
- other_surface->SetApplicationId(kOverviewToExitAppId);
- other_surface->surface_for_testing()->Commit();
- std::unique_ptr<ShellSurface> test_surface = BuildSurface(1024, 768);
- test_surface->SetApplicationId(kOverviewToExitAppId);
- test_surface->surface_for_testing()->Commit();
- testing::NiceMock<MockPointerDelegate> delegate;
- Pointer pointer(&delegate, seat_.get());
- testing::NiceMock<MockPointerConstraintDelegate> constraint(
- &pointer, test_surface->surface_for_testing());
- EXPECT_TRUE(pointer.ConstrainPointer(&constraint));
- EXPECT_TRUE(GetPointerCaptureNotification(test_surface));
- // Act: Focus the other window, then lock and unlock.
- wm::ActivateWindow(other_surface->surface_for_testing()->window());
- GetSessionControllerClient()->LockScreen();
- GetSessionControllerClient()->UnlockScreen();
- // Assert: Notification shown again.
- EXPECT_TRUE(GetPointerCaptureNotification(test_surface));
- }
- TEST_F(UILockControllerTest, FullscreenNotificationHasPriority) {
- // Arrange: Set up a pointer capture notification.
- std::unique_ptr<ShellSurface> test_surface = BuildSurface(1024, 768);
- test_surface->SetApplicationId(kOverviewToExitAppId);
- test_surface->surface_for_testing()->Commit();
- testing::NiceMock<MockPointerDelegate> delegate;
- Pointer pointer(&delegate, seat_.get());
- testing::NiceMock<MockPointerConstraintDelegate> constraint(
- &pointer, test_surface->surface_for_testing());
- EXPECT_TRUE(pointer.ConstrainPointer(&constraint));
- EXPECT_TRUE(GetPointerCaptureNotification(test_surface));
- // Act: Go fullscreen.
- test_surface->SetUseImmersiveForFullscreen(false);
- test_surface->SetFullscreen(true);
- test_surface->surface_for_testing()->Commit();
- // Assert: Fullscreen notification overrides pointer notification.
- EXPECT_FALSE(GetPointerCaptureNotification(test_surface));
- EXPECT_TRUE(GetEscNotification(test_surface));
- // Act: Exit fullscreen.
- test_surface->SetFullscreen(false);
- test_surface->surface_for_testing()->Commit();
- // Assert: Pointer notification returns, since it was interrupted.
- EXPECT_TRUE(GetPointerCaptureNotification(test_surface));
- EXPECT_FALSE(GetEscNotification(test_surface));
- }
- TEST_F(UILockControllerTest, ExitPopup) {
- std::unique_ptr<ShellSurface> test_surface = BuildSurface(1024, 768);
- test_surface->SetUseImmersiveForFullscreen(false);
- test_surface->SetFullscreen(true);
- test_surface->surface_for_testing()->Commit();
- auto* window_state = GetTopLevelWindowState(test_surface);
- EXPECT_TRUE(window_state->IsFullscreen());
- aura::Window* window = GetTopLevelWindow(test_surface);
- EXPECT_FALSE(IsExitPopupVisible(window));
- EXPECT_TRUE(GetEscNotification(test_surface));
- // Move mouse above y=3 should not show exit popup while notification is
- // visible.
- GetEventGenerator()->MoveMouseTo(0, 2);
- EXPECT_FALSE(IsExitPopupVisible(window));
- // Wait for notification to close, now exit popup should show.
- task_environment()->FastForwardBy(base::Seconds(5));
- EXPECT_FALSE(GetEscNotification(test_surface));
- GetEventGenerator()->MoveMouseTo(1, 2);
- EXPECT_TRUE(IsExitPopupVisible(window));
- // Move mouse below y=150 should hide exit popup.
- GetEventGenerator()->MoveMouseTo(0, 160);
- EXPECT_FALSE(IsExitPopupVisible(window));
- // Move mouse back above y=3 should show exit popup.
- GetEventGenerator()->MoveMouseTo(0, 2);
- EXPECT_TRUE(IsExitPopupVisible(window));
- // Popup should hide after 3s.
- task_environment()->FastForwardBy(base::Seconds(5));
- EXPECT_FALSE(IsExitPopupVisible(window));
- // Moving mouse to y=100, then above y=3 should still have popup hidden.
- GetEventGenerator()->MoveMouseTo(0, 100);
- GetEventGenerator()->MoveMouseTo(0, 2);
- EXPECT_FALSE(IsExitPopupVisible(window));
- // Moving mouse below y=150, then above y=3 should show exit popup.
- GetEventGenerator()->MoveMouseTo(0, 160);
- GetEventGenerator()->MoveMouseTo(0, 2);
- EXPECT_TRUE(IsExitPopupVisible(window));
- // Clicking exit popup should exit fullscreen.
- FullscreenControlPopup* popup =
- seat_->GetUILockControllerForTesting()->GetExitPopupForTesting(window);
- GetEventGenerator()->MoveMouseTo(
- popup->GetPopupWidget()->GetWindowBoundsInScreen().CenterPoint());
- GetEventGenerator()->ClickLeftButton();
- EXPECT_FALSE(window_state->IsFullscreen());
- EXPECT_FALSE(IsExitPopupVisible(window));
- }
- TEST_F(UILockControllerTest, ExitPopupNotShownForOverviewCase) {
- std::unique_ptr<ShellSurface> test_surface = BuildSurface(1024, 768);
- // Set chromeos::kUseOverviewToExitFullscreen on TopLevelWindow.
- test_surface->SetApplicationId(kOverviewToExitAppId);
- test_surface->SetUseImmersiveForFullscreen(false);
- test_surface->SetFullscreen(true);
- test_surface->surface_for_testing()->Commit();
- EXPECT_FALSE(IsExitPopupVisible(GetTopLevelWindow(test_surface)));
- // Move mouse above y=3 should not show exit popup.
- GetEventGenerator()->MoveMouseTo(0, 2);
- EXPECT_FALSE(IsExitPopupVisible(GetTopLevelWindow(test_surface)));
- }
- TEST_F(UILockControllerTest, OnlyShowWhenActive) {
- std::unique_ptr<ShellSurface> test_surface1 = BuildSurface(1024, 768);
- test_surface1->surface_for_testing()->Commit();
- std::unique_ptr<ShellSurface> test_surface2 =
- BuildSurface(gfx::Point(100, 100), 200, 200);
- test_surface2->surface_for_testing()->Commit();
- // Surface2 is active when we make Surface1 fullscreen.
- // Esc notification, and exit popup should not be shown.
- test_surface1->SetFullscreen(true);
- EXPECT_FALSE(GetEscNotification(test_surface1));
- GetEventGenerator()->MoveMouseTo(0, 2);
- EXPECT_FALSE(IsExitPopupVisible(GetTopLevelWindow(test_surface1)));
- }
- } // namespace
- } // namespace exo
|