#include "ash/display/privacy_screen_controller.h"
#include "ash/constants/ash_pref_names.h"
#include "ash/session/session_controller_impl.h"
#include "ash/shell.h"
#include "base/functional/bind.h"
#include "base/memory/raw_ptr.h"
#include "components/prefs/pref_change_registrar.h"
#include "components/prefs/pref_registry_simple.h"
#include "components/prefs/pref_service.h"
#include "ui/display/manager/display_configurator.h"
#include "ui/display/types/display_constants.h"
#include "ui/display/types/display_snapshot.h"
namespace ash {
namespace {
display::DisplaySnapshot* GetSupportedDisplay() {
const auto& cached_displays =
Shell::Get()->display_configurator()->cached_displays();
for (display::DisplaySnapshot* display : cached_displays) {
if (display->type() == display::DISPLAY_CONNECTION_TYPE_INTERNAL &&
display->privacy_screen_state() != display::kNotSupported &&
display->current_mode()) {
return display;
}
}
return nullptr;
}
int64_t GetSupportedDisplayId() {
auto* privacy_screen_display = GetSupportedDisplay();
return privacy_screen_display ? privacy_screen_display->display_id()
: display::kInvalidDisplayId;
}
}
PrivacyScreenController::PrivacyScreenController() {
Shell::Get()->session_controller()->AddObserver(this);
Shell::Get()->display_configurator()->AddObserver(this);
}
PrivacyScreenController::~PrivacyScreenController() {
Shell::Get()->display_configurator()->RemoveObserver(this);
Shell::Get()->session_controller()->RemoveObserver(this);
}
void PrivacyScreenController::RegisterProfilePrefs(
PrefRegistrySimple* registry) {
registry->RegisterBooleanPref(prefs::kDisplayPrivacyScreenEnabled, false);
}
bool PrivacyScreenController::IsSupported() const {
return GetSupportedDisplayId() != display::kInvalidDisplayId;
}
bool PrivacyScreenController::IsManaged() const {
return dlp_enforced_ || (active_user_pref_service_ &&
active_user_pref_service_->IsManagedPreference(
prefs::kDisplayPrivacyScreenEnabled));
}
bool PrivacyScreenController::GetEnabled() const {
return current_status_;
}
void PrivacyScreenController::SetEnabled(bool enabled) {
if (!IsSupported()) {
LOG(ERROR) << "Attempted to set privacy-screen on an unsupported device.";
return;
}
if (IsManaged()) {
const bool currently_enabled = GetEnabled();
for (Observer& observer : observers_)
observer.OnPrivacyScreenSettingChanged(currently_enabled,
true);
return;
}
if (active_user_pref_service_) {
if (GetStateFromActiveUserPreference() == enabled) {
OnStateChanged(false);
} else {
active_user_pref_service_->SetBoolean(prefs::kDisplayPrivacyScreenEnabled,
enabled);
}
}
}
void PrivacyScreenController::AddObserver(Observer* observer) {
observers_.AddObserver(observer);
}
void PrivacyScreenController::RemoveObserver(Observer* observer) {
observers_.RemoveObserver(observer);
}
void PrivacyScreenController::SetEnforced(bool enforced) {
dlp_enforced_ = enforced;
OnStateChanged(false);
}
void PrivacyScreenController::OnActiveUserPrefServiceChanged(
PrefService* pref_service) {
active_user_pref_service_ = pref_service;
InitFromUserPrefs();
}
void PrivacyScreenController::OnSigninScreenPrefServiceInitialized(
PrefService* prefs) {
active_user_pref_service_ = prefs;
applying_login_screen_prefs_ = true;
}
void PrivacyScreenController::OnDisplayConfigurationChanged(
const std::vector<raw_ptr<display::DisplaySnapshot, VectorExperimental>>&
displays) {
if (!applying_login_screen_prefs_)
return;
display::DisplaySnapshot* privacy_screen_display = GetSupportedDisplay();
current_status_ =
privacy_screen_display &&
(privacy_screen_display->privacy_screen_state() == display::kEnabled ||
privacy_screen_display->privacy_screen_state() ==
display::kEnabledLocked);
InitFromUserPrefs();
applying_login_screen_prefs_ = false;
}
bool PrivacyScreenController::CalculateCurrentStatus() const {
if (!active_user_pref_service_)
return dlp_enforced_;
const bool actual_user_pref = GetStateFromActiveUserPreference();
if (active_user_pref_service_->IsManagedPreference(
prefs::kDisplayPrivacyScreenEnabled)) {
return actual_user_pref;
}
return dlp_enforced_ || actual_user_pref;
}
void PrivacyScreenController::OnStateChanged(bool from_user_pref_init) {
const int64_t display_id = GetSupportedDisplayId();
if (display_id == display::kInvalidDisplayId)
return;
const bool enable_screen = CalculateCurrentStatus();
if (enable_screen == current_status_)
return;
Shell::Get()->display_configurator()->SetPrivacyScreen(
display_id, enable_screen,
base::BindOnce(&PrivacyScreenController::OnSetPrivacyScreenComplete,
weak_ptr_factory_.GetWeakPtr(), from_user_pref_init,
enable_screen));
}
void PrivacyScreenController::OnSetPrivacyScreenComplete(
bool from_user_pref_init,
bool requested_config,
bool success) {
if (success) {
current_status_ = requested_config;
} else {
LOG(ERROR) << "Turning privacy screen " << (requested_config ? "ON" : "OFF")
<< " was unsuccessful.";
}
const bool notify_observers = ShouldNotifyObservers(from_user_pref_init);
for (Observer& observer : observers_)
observer.OnPrivacyScreenSettingChanged(current_status_, notify_observers);
}
void PrivacyScreenController::InitFromUserPrefs() {
DCHECK(active_user_pref_service_);
pref_change_registrar_ = std::make_unique<PrefChangeRegistrar>();
pref_change_registrar_->Init(active_user_pref_service_);
pref_change_registrar_->Add(
prefs::kDisplayPrivacyScreenEnabled,
base::BindRepeating(&PrivacyScreenController::OnStateChanged,
weak_ptr_factory_.GetWeakPtr(),
false));
OnStateChanged(true);
}
bool PrivacyScreenController::GetStateFromActiveUserPreference() const {
return active_user_pref_service_ && active_user_pref_service_->GetBoolean(
prefs::kDisplayPrivacyScreenEnabled);
}
bool PrivacyScreenController::ShouldNotifyObservers(
bool from_user_pref_init) const {
return !from_user_pref_init;
}
}