123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489 |
- // 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 "ash/display/privacy_screen_controller.h"
- #include "ash/constants/ash_pref_names.h"
- #include "ash/dbus/privacy_screen_service_provider.h"
- #include "ash/session/session_controller_impl.h"
- #include "ash/shell.h"
- #include "ash/test/ash_test_base.h"
- #include "base/callback_helpers.h"
- #include "chromeos/ash/components/dbus/services/service_provider_test_helper.h"
- #include "components/prefs/pref_service.h"
- #include "dbus/message.h"
- #include "dbus/object_path.h"
- #include "testing/gmock/include/gmock/gmock.h"
- #include "third_party/cros_system_api/dbus/service_constants.h"
- #include "ui/display/fake/fake_display_snapshot.h"
- #include "ui/display/manager/display_change_observer.h"
- #include "ui/display/manager/display_manager.h"
- #include "ui/display/manager/test/action_logger_util.h"
- #include "ui/display/manager/test/test_native_display_delegate.h"
- #include "ui/display/types/display_constants.h"
- namespace ash {
- namespace {
- constexpr char kUser1Email[] = "user1@privacyscreen";
- constexpr char kUser2Email[] = "user2@privacyscreen";
- constexpr gfx::Size kDisplaySize{1024, 768};
- class MockObserver : public PrivacyScreenController::Observer {
- public:
- MockObserver() {}
- ~MockObserver() override = default;
- MOCK_METHOD(void,
- OnPrivacyScreenSettingChanged,
- (bool enabled, bool notify_ui),
- (override));
- };
- class PrivacyScreenControllerTest : public NoSessionAshTestBase {
- public:
- PrivacyScreenControllerTest()
- : logger_(std::make_unique<display::test::ActionLogger>()) {}
- ~PrivacyScreenControllerTest() override = default;
- PrivacyScreenControllerTest(const PrivacyScreenControllerTest&) = delete;
- PrivacyScreenControllerTest& operator=(const PrivacyScreenControllerTest&) =
- delete;
- PrivacyScreenController* controller() {
- return Shell::Get()->privacy_screen_controller();
- }
- PrefService* user1_pref_service() const {
- return Shell::Get()->session_controller()->GetUserPrefServiceForUser(
- AccountId::FromUserEmail(kUser1Email));
- }
- void SetUp() override {
- NoSessionAshTestBase::SetUp();
- // Create user 1 session and simulate its login.
- SimulateUserLogin(kUser1Email);
- // Create user 2 session.
- GetSessionControllerClient()->AddUserSession(kUser2Email);
- native_display_delegate_ =
- new display::test::TestNativeDisplayDelegate(logger_.get());
- display_manager()->configurator()->SetDelegateForTesting(
- std::unique_ptr<display::NativeDisplayDelegate>(
- native_display_delegate_));
- display_change_observer_ =
- std::make_unique<display::DisplayChangeObserver>(display_manager());
- test_api_ = std::make_unique<display::DisplayConfigurator::TestApi>(
- display_manager()->configurator());
- controller()->AddObserver(observer());
- }
- struct TestSnapshotParams {
- int64_t id;
- bool is_internal_display;
- bool supports_privacy_screen;
- };
- void TearDown() override {
- // DisplayChangeObserver access DeviceDataManager in its destructor, so
- // destroy it first.
- display_change_observer_ = nullptr;
- controller()->RemoveObserver(observer());
- AshTestBase::TearDown();
- }
- void SwitchActiveUser(const std::string& email) {
- GetSessionControllerClient()->SwitchActiveUser(
- AccountId::FromUserEmail(email));
- }
- // Builds displays snapshots into |owned_snapshots_| and update the display
- // configurator and display manager with it.
- void BuildAndUpdateDisplaySnapshots(
- const std::vector<TestSnapshotParams>& snapshot_params) {
- owned_snapshots_.clear();
- std::vector<display::DisplaySnapshot*> outputs;
- for (const auto& param : snapshot_params) {
- owned_snapshots_.emplace_back(
- display::FakeDisplaySnapshot::Builder()
- .SetId(param.id)
- .SetNativeMode(kDisplaySize)
- .SetCurrentMode(kDisplaySize)
- .SetType(param.is_internal_display
- ? display::DISPLAY_CONNECTION_TYPE_INTERNAL
- : display::DISPLAY_CONNECTION_TYPE_HDMI)
- .SetPrivacyScreen(param.supports_privacy_screen
- ? display::kDisabled
- : display::kNotSupported)
- .Build());
- outputs.push_back(owned_snapshots_.back().get());
- }
- native_display_delegate_->set_outputs(outputs);
- display_manager()->configurator()->OnConfigurationChanged();
- display_manager()->configurator()->ForceInitialConfigure();
- EXPECT_TRUE(test_api_->TriggerConfigureTimeout());
- display_change_observer_->OnDisplayModeChanged(outputs);
- }
- MockObserver* observer() { return &observer_; }
- private:
- std::unique_ptr<display::test::ActionLogger> logger_;
- display::test::TestNativeDisplayDelegate*
- native_display_delegate_; // Not owned.
- std::unique_ptr<display::DisplayChangeObserver> display_change_observer_;
- std::unique_ptr<display::DisplayConfigurator::TestApi> test_api_;
- std::vector<std::unique_ptr<display::DisplaySnapshot>> owned_snapshots_;
- ::testing::NiceMock<MockObserver> observer_;
- };
- class PrivacyScreenServiceProviderTest : public PrivacyScreenControllerTest {
- public:
- PrivacyScreenServiceProviderTest() = default;
- ~PrivacyScreenServiceProviderTest() override = default;
- PrivacyScreenServiceProviderTest(const PrivacyScreenServiceProviderTest&) =
- delete;
- PrivacyScreenServiceProviderTest& operator=(
- const PrivacyScreenServiceProviderTest&) = delete;
- // PrivacyScreenControllerTest:
- void SetUp() override {
- PrivacyScreenControllerTest::SetUp();
- service_provider_ = std::make_unique<PrivacyScreenServiceProvider>();
- test_helper_.SetUp(
- privacy_screen::kPrivacyScreenServiceName,
- dbus::ObjectPath(privacy_screen::kPrivacyScreenServicePath),
- privacy_screen::kPrivacyScreenServiceInterface,
- privacy_screen::kPrivacyScreenServiceGetPrivacyScreenSettingMethod,
- service_provider_.get());
- }
- void TearDown() override {
- test_helper_.TearDown();
- service_provider_.reset();
- PrivacyScreenControllerTest::TearDown();
- }
- privacy_screen::PrivacyScreenSetting_PrivacyScreenState
- GetPrivacyScreenSettingStateFromDBus() {
- dbus::MethodCall method_call(
- privacy_screen::kPrivacyScreenServiceInterface,
- privacy_screen::kPrivacyScreenServiceGetPrivacyScreenSettingMethod);
- std::unique_ptr<dbus::Response> response =
- test_helper_.CallMethod(&method_call);
- dbus::MessageReader reader(response.get());
- privacy_screen::PrivacyScreenSetting setting;
- EXPECT_TRUE(reader.PopArrayOfBytesAsProto(&setting));
- EXPECT_FALSE(reader.HasMoreData());
- return setting.state();
- }
- void ConnectToPrivacyScreenSettingChangedDBusSignal() {
- test_helper_.SetUpReturnSignal(
- privacy_screen::kPrivacyScreenServiceInterface,
- privacy_screen::kPrivacyScreenServicePrivacyScreenSettingChangedSignal,
- base::BindRepeating(&PrivacyScreenServiceProviderTest::
- OnPrivacyScreenSettingChangedDBusSignal,
- base::Unretained(this)),
- base::DoNothing());
- }
- void OnPrivacyScreenSettingChangedDBusSignal(dbus::Signal* signal) {
- dbus::MessageReader reader(signal);
- privacy_screen::PrivacyScreenSetting setting;
- EXPECT_TRUE(reader.PopArrayOfBytesAsProto(&setting));
- last_signal_state_ = setting.state();
- EXPECT_FALSE(reader.HasMoreData());
- }
- protected:
- privacy_screen::PrivacyScreenSetting_PrivacyScreenState last_signal_state_ =
- privacy_screen::PrivacyScreenSetting_PrivacyScreenState_NOT_SUPPORTED;
- std::unique_ptr<PrivacyScreenServiceProvider> service_provider_;
- ServiceProviderTestHelper test_helper_;
- };
- // Test that user prefs do not get mixed up between user changes on a device
- // with a single supporting display.
- TEST_F(PrivacyScreenControllerTest, TestEnableAndDisable) {
- // Create a single internal display that supports privacy screen.
- BuildAndUpdateDisplaySnapshots({{
- /*id=*/123u,
- /*is_internal_display=*/true,
- /*supports_privacy_screen=*/true,
- }});
- EXPECT_EQ(1u, display_manager()->GetNumDisplays());
- ASSERT_TRUE(controller()->IsSupported());
- // Enable for user 1, and switch to user 2. User 2 should have it disabled.
- EXPECT_CALL(*observer(), OnPrivacyScreenSettingChanged(true, true));
- controller()->SetEnabled(true,
- PrivacyScreenController::kToggleUISurfaceCount);
- EXPECT_TRUE(controller()->GetEnabled());
- // Switching accounts should trigger observers but should not notify ui.
- ::testing::Mock::VerifyAndClear(observer());
- EXPECT_CALL(*observer(), OnPrivacyScreenSettingChanged(false, false));
- SwitchActiveUser(kUser2Email);
- EXPECT_FALSE(controller()->GetEnabled());
- // Switch back to user 1, expect it to be enabled.
- ::testing::Mock::VerifyAndClear(observer());
- EXPECT_CALL(*observer(), OnPrivacyScreenSettingChanged(true, false));
- SwitchActiveUser(kUser1Email);
- EXPECT_TRUE(controller()->GetEnabled());
- }
- // Checks that when the privacy screen is enforced by Data Leak Prevention
- // feature, it's turned on regardless of the user pref state.
- TEST_F(PrivacyScreenControllerTest, TestDlpEnforced) {
- // Create a single internal display that supports privacy screen.
- BuildAndUpdateDisplaySnapshots({{
- /*id=*/123u,
- /*is_internal_display=*/true,
- /*supports_privacy_screen=*/true,
- }});
- EXPECT_EQ(1u, display_manager()->GetNumDisplays());
- ASSERT_TRUE(controller()->IsSupported());
- EXPECT_FALSE(controller()->GetEnabled());
- // Enforce privacy screen and check notification.
- EXPECT_CALL(*observer(), OnPrivacyScreenSettingChanged(true, true));
- controller()->SetEnforced(true);
- EXPECT_TRUE(controller()->GetEnabled());
- // Additionally enable it via pref, no change.
- ::testing::Mock::VerifyAndClear(observer());
- EXPECT_CALL(*observer(), OnPrivacyScreenSettingChanged(true, true));
- controller()->SetEnabled(true,
- PrivacyScreenController::kToggleUISurfaceCount);
- EXPECT_TRUE(controller()->GetEnabled());
- // Shouldn't be turned off when pref is disabled, because already enforced.
- ::testing::Mock::VerifyAndClear(observer());
- EXPECT_CALL(*observer(), OnPrivacyScreenSettingChanged(true, true));
- controller()->SetEnabled(false,
- PrivacyScreenController::kToggleUISurfaceCount);
- EXPECT_TRUE(controller()->GetEnabled());
- // Privacy screen enforced again by DLP, no notification should be shown.
- ::testing::Mock::VerifyAndClear(observer());
- EXPECT_CALL(*observer(),
- OnPrivacyScreenSettingChanged(::testing::_, ::testing::_))
- .Times(0);
- controller()->SetEnforced(true);
- EXPECT_TRUE(controller()->GetEnabled());
- // Remove enforcement, turned off as pref was not changed.
- ::testing::Mock::VerifyAndClear(observer());
- EXPECT_CALL(*observer(), OnPrivacyScreenSettingChanged(false, true));
- controller()->SetEnforced(false);
- EXPECT_FALSE(controller()->GetEnabled());
- // Add pref back.
- ::testing::Mock::VerifyAndClear(observer());
- EXPECT_CALL(*observer(), OnPrivacyScreenSettingChanged(true, true));
- controller()->SetEnabled(true,
- PrivacyScreenController::kToggleUISurfaceCount);
- EXPECT_TRUE(controller()->GetEnabled());
- // Privacy screen enforced again by DLP, no notification should be shown as
- // privacy screen already turned on by the user.
- ::testing::Mock::VerifyAndClear(observer());
- EXPECT_CALL(*observer(),
- OnPrivacyScreenSettingChanged(::testing::_, ::testing::_))
- .Times(0);
- controller()->SetEnforced(true);
- EXPECT_TRUE(controller()->GetEnabled());
- // Remove enforcement, privacy screen should still be on due to pref and no
- // notification.
- ::testing::Mock::VerifyAndClear(observer());
- EXPECT_CALL(*observer(),
- OnPrivacyScreenSettingChanged(::testing::_, ::testing::_))
- .Times(0);
- controller()->SetEnforced(false);
- EXPECT_TRUE(controller()->GetEnabled());
- // Disable via pref, privacy screen is turned off with a notification.
- ::testing::Mock::VerifyAndClear(observer());
- EXPECT_CALL(*observer(), OnPrivacyScreenSettingChanged(false, true));
- controller()->SetEnabled(false,
- PrivacyScreenController::kToggleUISurfaceCount);
- EXPECT_FALSE(controller()->GetEnabled());
- }
- // Tests that updates of the Privacy Screen user prefs from outside the
- // PrivacyScreenController (such as Settings UI) are observed and applied.
- TEST_F(PrivacyScreenControllerTest, TestOutsidePrefsUpdates) {
- BuildAndUpdateDisplaySnapshots({{
- /*id=*/123u,
- /*is_internal_display=*/true,
- /*supports_privacy_screen=*/true,
- }});
- EXPECT_EQ(1u, display_manager()->GetNumDisplays());
- ASSERT_TRUE(controller()->IsSupported());
- EXPECT_CALL(*observer(), OnPrivacyScreenSettingChanged(true, true));
- EXPECT_FALSE(controller()->GetEnabled());
- user1_pref_service()->SetBoolean(prefs::kDisplayPrivacyScreenEnabled, true);
- EXPECT_TRUE(controller()->GetEnabled());
- ::testing::Mock::VerifyAndClear(observer());
- EXPECT_CALL(*observer(), OnPrivacyScreenSettingChanged(false, true));
- user1_pref_service()->SetBoolean(prefs::kDisplayPrivacyScreenEnabled, false);
- EXPECT_FALSE(controller()->GetEnabled());
- }
- TEST_F(PrivacyScreenControllerTest, SupportedOnSingleInternalDisplay) {
- BuildAndUpdateDisplaySnapshots({{
- /*id=*/123u,
- /*is_internal_display=*/true,
- /*supports_privacy_screen=*/true,
- }});
- EXPECT_EQ(1u, display_manager()->GetNumDisplays());
- ASSERT_TRUE(controller()->IsSupported());
- EXPECT_CALL(*observer(), OnPrivacyScreenSettingChanged(true, true));
- controller()->SetEnabled(true,
- PrivacyScreenController::kToggleUISurfaceCount);
- EXPECT_TRUE(controller()->GetEnabled());
- }
- TEST_F(PrivacyScreenControllerTest, NotSupportedOnSingleInternalDisplay) {
- BuildAndUpdateDisplaySnapshots({{
- /*id=*/123u,
- /*is_internal_display=*/true,
- /*supports_privacy_screen=*/false,
- }});
- EXPECT_EQ(1u, display_manager()->GetNumDisplays());
- ASSERT_FALSE(controller()->IsSupported());
- EXPECT_FALSE(controller()->GetEnabled());
- }
- // Test that the privacy screen is not supported when the device is connected
- // to an external display and the lid is closed (a.k.a. docked mode).
- TEST_F(PrivacyScreenControllerTest, NotSupportedOnInternalDisplayWhenDocked) {
- BuildAndUpdateDisplaySnapshots({{
- /*id=*/123u,
- /*is_internal_display=*/true,
- /*supports_privacy_screen=*/true,
- },
- {
- /*id=*/234u,
- /*is_internal_display=*/false,
- /*supports_privacy_screen=*/false,
- }});
- EXPECT_EQ(2u, display_manager()->GetNumDisplays());
- // Turn off the internal display
- display_manager()->configurator()->SetDisplayPower(
- chromeos::DISPLAY_POWER_INTERNAL_OFF_EXTERNAL_ON,
- display::DisplayConfigurator::kSetDisplayPowerNoFlags, base::DoNothing());
- ASSERT_FALSE(controller()->IsSupported());
- EXPECT_FALSE(controller()->GetEnabled());
- }
- TEST_F(PrivacyScreenControllerTest,
- SupportedOnInternalDisplayWithMultipleExternalDisplays) {
- BuildAndUpdateDisplaySnapshots({{
- /*id=*/1234u,
- /*is_internal_display=*/true,
- /*supports_privacy_screen=*/true,
- },
- {
- /*id=*/2341u,
- /*is_internal_display=*/false,
- /*supports_privacy_screen=*/false,
- },
- {
- /*id=*/3412u,
- /*is_internal_display=*/false,
- /*supports_privacy_screen=*/false,
- }});
- EXPECT_EQ(3u, display_manager()->GetNumDisplays());
- ASSERT_TRUE(controller()->IsSupported());
- controller()->SetEnabled(true,
- PrivacyScreenController::kToggleUISurfaceCount);
- EXPECT_TRUE(controller()->GetEnabled());
- }
- TEST_F(PrivacyScreenControllerTest,
- NotSupportedOnInternalDisplayWithMultipleExternalDisplays) {
- BuildAndUpdateDisplaySnapshots({{
- /*id=*/1234u,
- /*is_internal_display=*/true,
- /*supports_privacy_screen=*/false,
- },
- {
- /*id=*/2341u,
- /*is_internal_display=*/false,
- /*supports_privacy_screen=*/false,
- },
- {
- /*id=*/3412u,
- /*is_internal_display=*/false,
- /*supports_privacy_screen=*/false,
- }});
- EXPECT_EQ(3u, display_manager()->GetNumDisplays());
- ASSERT_FALSE(controller()->IsSupported());
- EXPECT_FALSE(controller()->GetEnabled());
- }
- TEST_F(PrivacyScreenServiceProviderTest, PrivacyScreenNotSupported) {
- BuildAndUpdateDisplaySnapshots({{
- /*id=*/123u,
- /*is_internal_display=*/true,
- /*supports_privacy_screen=*/false,
- }});
- ASSERT_EQ(
- GetPrivacyScreenSettingStateFromDBus(),
- privacy_screen::PrivacyScreenSetting_PrivacyScreenState_NOT_SUPPORTED);
- }
- TEST_F(PrivacyScreenServiceProviderTest, PrivacyScreenDisabled) {
- BuildAndUpdateDisplaySnapshots({{
- /*id=*/123u,
- /*is_internal_display=*/true,
- /*supports_privacy_screen=*/true,
- }});
- ASSERT_EQ(GetPrivacyScreenSettingStateFromDBus(),
- privacy_screen::PrivacyScreenSetting_PrivacyScreenState_DISABLED);
- }
- TEST_F(PrivacyScreenServiceProviderTest, PrivacyScreenEnabled) {
- ConnectToPrivacyScreenSettingChangedDBusSignal();
- BuildAndUpdateDisplaySnapshots({{
- /*id=*/123u,
- /*is_internal_display=*/true,
- /*supports_privacy_screen=*/true,
- }});
- controller()->SetEnabled(true,
- PrivacyScreenController::kToggleUISurfaceCount);
- // Expects PrivacyScreenSettingChanged D-Bus signal to be called once.
- ASSERT_EQ(last_signal_state_,
- privacy_screen::PrivacyScreenSetting_PrivacyScreenState_ENABLED);
- ASSERT_EQ(GetPrivacyScreenSettingStateFromDBus(),
- privacy_screen::PrivacyScreenSetting_PrivacyScreenState_ENABLED);
- }
- } // namespace
- } // namespace ash
|