#include "ash/ambient/ambient_controller.h"
#include <algorithm>
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include "ash/ambient/ambient_animation_ui_launcher.h"
#include "ash/ambient/ambient_constants.h"
#include "ash/ambient/ambient_managed_slideshow_ui_launcher.h"
#include "ash/ambient/ambient_photo_cache.h"
#include "ash/ambient/ambient_photo_cache_settings.h"
#include "ash/ambient/ambient_slideshow_ui_launcher.h"
#include "ash/ambient/ambient_ui_launcher.h"
#include "ash/ambient/ambient_ui_settings.h"
#include "ash/ambient/ambient_video_ui_launcher.h"
#include "ash/ambient/managed/screensaver_images_policy_handler.h"
#include "ash/ambient/metrics/ambient_metrics.h"
#include "ash/ambient/metrics/ambient_session_metrics_recorder.h"
#include "ash/ambient/metrics/managed_screensaver_metrics.h"
#include "ash/ambient/model/ambient_animation_photo_config.h"
#include "ash/ambient/model/ambient_photo_config.h"
#include "ash/ambient/model/ambient_slideshow_photo_config.h"
#include "ash/ambient/model/ambient_topic_queue_animation_delegate.h"
#include "ash/ambient/model/ambient_topic_queue_slideshow_delegate.h"
#include "ash/ambient/resources/ambient_animation_static_resources.h"
#include "ash/ambient/ui/ambient_animation_frame_rate_controller.h"
#include "ash/ambient/ui/ambient_animation_progress_tracker.h"
#include "ash/ambient/ui/ambient_container_view.h"
#include "ash/ambient/ui/ambient_view_delegate.h"
#include "ash/ambient/util/ambient_util.h"
#include "ash/login/ui/lock_screen.h"
#include "ash/public/cpp/ambient/ambient_backend_controller.h"
#include "ash/public/cpp/ambient/ambient_client.h"
#include "ash/public/cpp/ambient/ambient_mode_photo_source.h"
#include "ash/public/cpp/ambient/ambient_prefs.h"
#include "ash/public/cpp/ambient/ambient_ui_model.h"
#include "ash/public/cpp/ambient/common/ambient_settings.h"
#include "ash/public/cpp/ambient/fake_ambient_backend_controller_impl.h"
#include "ash/public/cpp/shell_window_ids.h"
#include "ash/root_window_controller.h"
#include "ash/session/session_controller_impl.h"
#include "ash/shell.h"
#include "ash/strings/grit/ash_strings.h"
#include "ash/system/power/power_status.h"
#include "ash/webui/personalization_app/mojom/personalization_app.mojom-shared.h"
#include "base/check.h"
#include "base/check_deref.h"
#include "base/feature_list.h"
#include "base/functional/bind.h"
#include "base/functional/callback_helpers.h"
#include "base/logging.h"
#include "base/memory/weak_ptr.h"
#include "base/metrics/user_metrics.h"
#include "base/notreached.h"
#include "base/path_service.h"
#include "base/task/thread_pool.h"
#include "base/time/time.h"
#include "base/timer/timer.h"
#include "base/values.h"
#include "build/buildflag.h"
#include "cc/paint/skottie_wrapper.h"
#include "chromeos/ash/components/assistant/buildflags.h"
#include "chromeos/components/kiosk/kiosk_utils.h"
#include "chromeos/dbus/power/power_manager_client.h"
#include "chromeos/dbus/power_manager/backlight.pb.h"
#include "chromeos/dbus/power_manager/idle.pb.h"
#include "components/prefs/pref_change_registrar.h"
#include "components/prefs/pref_registry_simple.h"
#include "components/prefs/pref_service.h"
#include "google_apis/gaia/gaia_id.h"
#include "ui/aura/client/aura_constants.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/mojom/window_show_state.mojom.h"
#include "ui/base/ui_base_types.h"
#include "ui/base/user_activity/user_activity_detector.h"
#include "ui/views/accessibility/view_accessibility.h"
#include "ui/views/view.h"
#include "ui/views/widget/widget.h"
#include "ui/views/widget/widget_delegate.h"
#include "ui/wm/core/cursor_manager.h"
#include "ui/wm/core/visibility_controller.h"
#include "ui/wm/core/window_animations.h"
#if BUILDFLAG(ENABLE_CROS_AMBIENT_MODE_BACKEND)
#include "ash/ambient/backdrop/ambient_backend_controller_impl.h"
#endif
namespace ash {
namespace {
constexpr char kWakeLockReason[] = "AmbientMode";
constexpr int kDurationForever = 0;
std::unique_ptr<AmbientBackendController> CreateAmbientBackendController() {
#if BUILDFLAG(ENABLE_CROS_AMBIENT_MODE_BACKEND)
return std::make_unique<AmbientBackendControllerImpl>();
#else
return std::make_unique<FakeAmbientBackendControllerImpl>();
#endif
}
std::string GetWidgetName() {
if (ambient::util::IsShowing(LockScreen::ScreenType::kLock))
return "LockScreenAmbientModeContainer";
return "InSessionAmbientModeContainer";
}
bool IsChargerConnected() {
DCHECK(PowerStatus::IsInitialized());
auto* power_status = PowerStatus::Get();
if (power_status->IsBatteryPresent()) {
return power_status->IsBatteryCharging() ||
power_status->IsMainsChargerConnected();
} else {
return power_status->IsLinePowerConnected();
}
}
bool IsUiHidden(AmbientUiVisibility visibility) {
return visibility == AmbientUiVisibility::kHidden;
}
PrefService* GetPrimaryUserPrefService() {
return Shell::Get()->session_controller()->GetPrimaryUserPrefService();
}
PrefService* GetSigninPrefService() {
return Shell::Get()->session_controller()->GetSigninScreenPrefService();
}
PrefService* GetActivePrefService() {
if (GetPrimaryUserPrefService()) {
return GetPrimaryUserPrefService();
}
return GetSigninPrefService();
}
bool IsUserAmbientModeEnabled() {
if (!AmbientClient::Get()->IsAmbientModeAllowed()) {
return false;
}
auto* pref_service = GetPrimaryUserPrefService();
return pref_service &&
pref_service->GetBoolean(ambient::prefs::kAmbientModeEnabled);
}
bool IsAmbientModeManagedScreensaverEnabled() {
PrefService* pref_service = GetActivePrefService();
return !chromeos::IsKioskSession() && pref_service &&
pref_service->GetBoolean(
ambient::prefs::kAmbientModeManagedScreensaverEnabled);
}
bool IsAmbientModeEnabled() {
return IsUserAmbientModeEnabled() || IsAmbientModeManagedScreensaverEnabled();
}
void RecordManagedScreensaverEnabledPref() {
if (PrefService* pref_service = GetActivePrefService();
pref_service &&
pref_service->IsManagedPreference(
ambient::prefs::kAmbientModeManagedScreensaverEnabled)) {
RecordManagedScreensaverEnabled(pref_service->GetBoolean(
ambient::prefs::kAmbientModeManagedScreensaverEnabled));
}
}
}
class AmbientWidgetDelegate : public views::WidgetDelegate {
public:
AmbientWidgetDelegate() {
SetCanFullscreen(true);
SetCanMaximize(true);
SetOwnedByWidget(OwnedByWidgetPassKey());
}
};
void AmbientController::RegisterProfilePrefs(PrefRegistrySimple* registry) {
registry->RegisterStringPref(ash::ambient::prefs::kAmbientBackdropClientId,
std::string());
registry->RegisterBooleanPref(ash::ambient::prefs::kAmbientModeEnabled,
false);
registry->RegisterIntegerPref(
ash::ambient::prefs::kAmbientModePhotoSourcePref,
static_cast<int>(ash::ambient::AmbientModePhotoSource::kUnset));
registry->RegisterIntegerPref(
ambient::prefs::kAmbientModeLockScreenInactivityTimeoutSeconds,
kLockScreenInactivityTimeout.InSeconds());
registry->RegisterIntegerPref(
ambient::prefs::kAmbientModeLockScreenBackgroundTimeoutSeconds,
kLockScreenBackgroundTimeout.InSeconds());
registry->RegisterIntegerPref(
ambient::prefs::kAmbientModePhotoRefreshIntervalSeconds,
kPhotoRefreshInterval.InSeconds());
registry->RegisterIntegerPref(ambient::prefs::kAmbientTheme,
static_cast<int>(kDefaultAmbientTheme));
registry->RegisterDictionaryPref(ambient::prefs::kAmbientUiSettings);
registry->RegisterDoublePref(
ambient::prefs::kAmbientModeAnimationPlaybackSpeed,
kAnimationPlaybackSpeed);
registry->RegisterBooleanPref(
ash::ambient::prefs::kAmbientModeManagedScreensaverEnabled, false);
registry->RegisterIntegerPref(
ambient::prefs::kAmbientModeManagedScreensaverIdleTimeoutSeconds,
kManagedScreensaverInactivityTimeout.InSeconds());
registry->RegisterIntegerPref(
ambient::prefs::kAmbientModeManagedScreensaverImageDisplayIntervalSeconds,
kManagedScreensaverImageRefreshInterval.InSeconds());
registry->RegisterIntegerPref(
ambient::prefs::kAmbientModeRunningDurationMinutes, kDurationForever);
}
AmbientController::AmbientController(
mojo::PendingRemote<device::mojom::Fingerprint> fingerprint)
: ambient_weather_controller_(std::make_unique<AmbientWeatherController>(
SystemLocationProvider::GetInstance())),
fingerprint_(std::move(fingerprint)) {
ambient_photo_cache::SetFileTaskRunner(
base::ThreadPool::CreateSequencedTaskRunner(
{base::MayBlock(), base::TaskPriority::BEST_EFFORT,
base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN}));
ambient_backend_controller_ = CreateAmbientBackendController();
session_observer_.Observe(Shell::Get()->session_controller());
backlights_forced_off_observation_.Observe(
Shell::Get()->backlights_forced_off_setter());
}
AmbientController::~AmbientController() {
SetUiVisibilityClosed(true);
}
void AmbientController::OnAmbientUiVisibilityChanged(
AmbientUiVisibility visibility) {
switch (visibility) {
case AmbientUiVisibility::kShouldShow:
inactivity_timer_.Stop();
if (IsChargerConnected()) {
AcquireWakeLock();
StartTimerToReleaseWakeLock();
}
if (!power_status_observer_.IsObserving())
power_status_observer_.Observe(PowerStatus::Get());
MaybeStartScreenSaver();
break;
case AmbientUiVisibility::kPreview: {
MaybeStartScreenSaver();
break;
}
case AmbientUiVisibility::kHidden:
case AmbientUiVisibility::kClosed: {
StopScreensaver();
ReleaseWakeLock();
ClearPreTargetHandler();
if (visibility == AmbientUiVisibility::kHidden) {
if (LockScreen::HasInstance()) {
if (!user_activity_observer_.IsObserving())
user_activity_observer_.Observe(ui::UserActivityDetector::Get());
inactivity_timer_.Start(
FROM_HERE, ambient_ui_model_.lock_screen_inactivity_timeout(),
base::BindOnce(&AmbientController::OnAutoShowTimeOut,
weak_ptr_factory_.GetWeakPtr()));
}
} else {
DCHECK(visibility == AmbientUiVisibility::kClosed);
inactivity_timer_.Stop();
user_activity_observer_.Reset();
power_status_observer_.Reset();
}
break;
}
}
}
void AmbientController::OnAutoShowTimeOut() {
DCHECK(IsUiHidden(ambient_ui_model_.ui_visibility()));
SetUiVisibilityShouldShow();
}
void AmbientController::OnLoginOrLockScreenCreated() {
if (!ambient::util::IsShowing(LockScreen::ScreenType::kLogin)) {
return;
}
OnLoginLockStateChanged(LockScreenState::kLogin);
}
void AmbientController::OnLockStateChanged(bool locked) {
OnLoginLockStateChanged(locked ? LockScreenState::kLocked
: LockScreenState::kUnlocked);
}
void AmbientController::OnLoginLockStateChanged(LockScreenState state) {
if (state == LockScreenState::kUnlocked) {
SetUiVisibilityClosed();
return;
}
if (!IsAmbientModeEnabled()) {
VLOG(1) << "Ambient mode is not allowed.";
return;
}
if (GetAmbientBackendModel()) {
GetAmbientBackendModel()->ResetImageFailures();
}
RequestAccessToken(base::DoNothing(), true);
if (!IsShowing()) {
SetUiVisibilityHidden();
}
}
AmbientController::LockScreenState AmbientController::GetLockScreenState() {
if (!LockScreen::HasInstance()) {
return LockScreenState::kUnlocked;
}
if (ambient::util::IsShowing(LockScreen::ScreenType::kLogin)) {
return LockScreenState::kLogin;
}
return LockScreenState::kLocked;
}
void AmbientController::OnActiveUserPrefServiceChanged(
PrefService* pref_service) {
if (GetPrimaryUserPrefService() != pref_service) {
return;
}
if (pref_change_registrar_)
return;
if (sign_in_pref_change_registrar_) {
sign_in_pref_change_registrar_.reset();
}
bool ambient_mode_allowed = AmbientClient::Get()->IsAmbientModeAllowed();
pref_change_registrar_ = std::make_unique<PrefChangeRegistrar>();
pref_change_registrar_->Init(pref_service);
if (ambient_mode_allowed) {
pref_change_registrar_->Add(
ambient::prefs::kAmbientModeEnabled,
base::BindRepeating(&AmbientController::OnEnabledPrefChanged,
weak_ptr_factory_.GetWeakPtr()));
}
screensaver_images_policy_handler_ =
ScreensaverImagesPolicyHandler::Create(pref_service);
pref_change_registrar_->Add(
ambient::prefs::kAmbientModeManagedScreensaverEnabled,
base::BindRepeating(&AmbientController::OnEnabledPrefChanged,
weak_ptr_factory_.GetWeakPtr()));
OnEnabledPrefChanged();
}
void AmbientController::OnSigninScreenPrefServiceInitialized(
PrefService* pref_service) {
screensaver_images_policy_handler_ =
ScreensaverImagesPolicyHandler::Create(pref_service);
CHECK(!sign_in_pref_change_registrar_);
CHECK(!pref_change_registrar_);
sign_in_pref_change_registrar_ = std::make_unique<PrefChangeRegistrar>();
sign_in_pref_change_registrar_->Init(pref_service);
sign_in_pref_change_registrar_->Add(
ambient::prefs::kAmbientModeManagedScreensaverEnabled,
base::BindRepeating(&AmbientController::OnEnabledPrefChanged,
weak_ptr_factory_.GetWeakPtr()));
OnEnabledPrefChanged();
}
void AmbientController::OnPowerStatusChanged() {
if (ambient_ui_model_.ui_visibility() != AmbientUiVisibility::kShouldShow) {
return;
}
if (!IsChargerConnected()) {
ReleaseWakeLock();
}
}
void AmbientController::ScreenIdleStateChanged(
const power_manager::ScreenIdleState& idle_state) {
DVLOG(1) << "ScreenIdleStateChanged: dimmed(" << idle_state.dimmed()
<< ") off(" << idle_state.off() << ")";
if (!IsAmbientModeEnabled())
return;
is_screen_off_ = idle_state.off();
if (idle_state.off()) {
DVLOG(1) << "Screen is off, close ambient mode.";
SetUiVisibilityClosed(true);
return;
}
if (idle_state.dimmed()) {
if (LockScreen::HasInstance())
return;
if (GetAmbientBackendModel() &&
GetAmbientBackendModel()->ImageLoadingFailed()) {
VLOG(1) << "Skipping ambient mode activation due to prior failure";
GetAmbientBackendModel()->ResetImageFailures();
return;
}
SetUiVisibilityShouldShow();
return;
}
if (LockScreen::HasInstance() &&
ambient_ui_model_.ui_visibility() == AmbientUiVisibility::kClosed) {
SetUiVisibilityHidden();
}
}
void AmbientController::OnBacklightsForcedOffChanged(bool forced_off) {
if (forced_off) {
SetUiVisibilityClosed(true);
}
if (!forced_off && LockScreen::HasInstance() &&
ambient_ui_model_.ui_visibility() == AmbientUiVisibility::kClosed) {
SetUiVisibilityHidden();
}
}
void AmbientController::SuspendImminent(
power_manager::SuspendImminent::Reason reason) {
SetUiVisibilityClosed(true);
is_suspend_imminent_ = true;
}
void AmbientController::SuspendDone(base::TimeDelta sleep_duration) {
is_suspend_imminent_ = false;
DismissUI();
}
void AmbientController::OnAuthScanDone(
const device::mojom::FingerprintMessagePtr msg,
const base::flat_map<std::string, std::vector<std::string>>& matches) {
DismissUI();
}
void AmbientController::OnUserActivity(const ui::Event* event) {
if (is_receiving_pretarget_events_ && event &&
(event->IsMouseEvent() || event->IsTouchEvent() || event->IsKeyEvent() ||
event->IsFlingScrollEvent())) {
return;
}
if (ambient_ui_model_.ui_visibility() == AmbientUiVisibility::kPreview &&
!IsShowing()) {
return;
}
DismissUI();
}
void AmbientController::OnKeyEvent(ui::KeyEvent* event) {
MaybeStopUiEventPropagation(event);
if (event->type() == ui::EventType::kKeyPressed) {
DismissUI();
}
}
void AmbientController::OnMouseEvent(ui::MouseEvent* event) {
if (event->type() == ui::EventType::kMouseMoved) {
MaybeDismissUIOnMouseMove();
last_mouse_event_was_move_ = true;
return;
}
MaybeStopUiEventPropagation(event);
if (event->IsAnyButton()) {
DismissUI();
}
last_mouse_event_was_move_ = false;
}
void AmbientController::OnTouchEvent(ui::TouchEvent* event) {
MaybeStopUiEventPropagation(event);
DismissUI();
}
void AmbientController::SetUiVisibilityShouldShow() {
DVLOG(1) << __func__;
if (!IsAmbientModeEnabled()) {
LOG(WARNING) << "Ambient mode is not allowed.";
return;
}
if (is_suspend_imminent_) {
VLOG(1) << "Do not show UI when suspend imminent";
return;
}
if (ambient_ui_launcher_ && !ambient_ui_launcher_->IsReady()) {
return;
}
ambient_ui_model_.SetUiVisibility(AmbientUiVisibility::kShouldShow);
}
void AmbientController::SetUiVisibilityPreview() {
if (!IsAmbientModeEnabled()) {
LOG(WARNING) << "Ambient mode is not allowed.";
return;
}
ambient_ui_model_.SetUiVisibility(AmbientUiVisibility::kPreview);
base::RecordAction(base::UserMetricsAction(kScreenSaverPreviewUserAction));
}
void AmbientController::SetUiVisibilityHidden() {
DVLOG(1) << __func__;
if (!IsAmbientModeEnabled()) {
LOG(WARNING) << "Ambient mode is not allowed.";
return;
}
if (is_suspend_imminent_) {
VLOG(1) << "Do not start hidden UI when suspend imminent";
return;
}
if (is_screen_off_) {
VLOG(1) << "Do not start hidden UI when screen is off";
return;
}
ambient_ui_model_.SetUiVisibility(AmbientUiVisibility::kHidden);
}
void AmbientController::SetUiVisibilityClosed(bool immediately) {
DVLOG(1) << __func__;
if (ambient_ui_model_.ui_visibility() == AmbientUiVisibility::kClosed) {
return;
}
close_widgets_immediately_ = immediately;
ambient_ui_model_.SetUiVisibility(AmbientUiVisibility::kClosed);
if (!display::Screen::Get()->InTabletMode()) {
Shell::Get()->cursor_manager()->ShowCursor();
}
}
void AmbientController::SetScreenSaverDuration(int minutes) {
auto* pref_service = GetPrimaryUserPrefService();
if (!pref_service) {
return;
}
pref_service->Set(ambient::prefs::kAmbientModeRunningDurationMinutes,
base::Value(minutes));
}
void AmbientController::StartTimerToReleaseWakeLock() {
CHECK(!screensaver_running_timer_.IsRunning());
auto* pref_service = GetPrimaryUserPrefService();
if (!pref_service) {
return;
}
const int session_duration_in_minutes = pref_service->GetInteger(
ambient::prefs::kAmbientModeRunningDurationMinutes);
CHECK(session_duration_in_minutes >= 0);
if (session_duration_in_minutes != kDurationForever) {
const base::TimeDelta delay = base::Minutes(session_duration_in_minutes);
screensaver_running_timer_.Start(FROM_HERE, delay, this,
&AmbientController::ReleaseWakeLock);
}
}
bool AmbientController::ShouldShowAmbientUi() const {
return ambient_ui_model_.ui_visibility() ==
AmbientUiVisibility::kShouldShow ||
ambient_ui_model_.ui_visibility() == AmbientUiVisibility::kPreview;
}
bool AmbientController::IsShowing() const {
const std::vector<RootWindowController*> root_window_controllers =
RootWindowController::root_window_controllers();
const bool has_at_least_one_widget = std::any_of(
root_window_controllers.cbegin(), root_window_controllers.cend(),
[](const RootWindowController* const controller) {
return controller->HasAmbientWidget();
});
#if DCHECK_IS_ON()
if (!ShouldShowAmbientUi()) {
DCHECK(!has_at_least_one_widget);
}
#endif
return has_at_least_one_widget;
}
void AmbientController::AcquireWakeLock() {
if (!wake_lock_) {
mojo::Remote<device::mojom::WakeLockProvider> provider;
AmbientClient::Get()->RequestWakeLockProvider(
provider.BindNewPipeAndPassReceiver());
provider->GetWakeLockWithoutContext(
device::mojom::WakeLockType::kPreventDisplaySleep,
device::mojom::WakeLockReason::kOther, kWakeLockReason,
wake_lock_.BindNewPipeAndPassReceiver());
}
DCHECK(wake_lock_);
wake_lock_->RequestWakeLock();
VLOG(1) << "Acquired wake lock";
auto* session_controller = Shell::Get()->session_controller();
if (session_controller->CanLockScreen() &&
session_controller->ShouldLockScreenAutomatically()) {
if (!session_controller->IsScreenLocked() &&
!delayed_lock_timer_.IsRunning()) {
delayed_lock_timer_.Start(
FROM_HERE, ambient_ui_model_.background_lock_screen_timeout(),
base::BindOnce(
[]() { Shell::Get()->session_controller()->LockScreen(); }));
}
}
}
void AmbientController::ReleaseWakeLock() {
if (!wake_lock_)
return;
wake_lock_->CancelWakeLock();
VLOG(1) << "Released wake lock";
delayed_lock_timer_.Stop();
screensaver_running_timer_.Stop();
}
void AmbientController::CloseAllWidgets(bool immediately) {
for (auto* root_window_controller :
RootWindowController::root_window_controllers()) {
root_window_controller->CloseAmbientWidget(immediately);
}
}
void AmbientController::SetUpPreTargetHandler() {
if (!is_receiving_pretarget_events_) {
Shell::Get()->AddPreTargetHandler(this);
is_receiving_pretarget_events_ = true;
}
}
void AmbientController::ClearPreTargetHandler() {
if (is_receiving_pretarget_events_) {
Shell::Get()->RemovePreTargetHandler(this);
is_receiving_pretarget_events_ = false;
}
}
PrefChangeRegistrar* AmbientController::GetActivePrefChangeRegistrar() {
if (pref_change_registrar_) {
return pref_change_registrar_.get();
}
return sign_in_pref_change_registrar_.get();
}
void AmbientController::AddManagedScreensaverPolicyPrefObservers() {
PrefChangeRegistrar* registrar = GetActivePrefChangeRegistrar();
CHECK(registrar);
registrar->Add(
ambient::prefs::kAmbientModeManagedScreensaverIdleTimeoutSeconds,
base::BindRepeating(
&AmbientController::
OnManagedScreensaverLockScreenIdleTimeoutPrefChanged,
weak_ptr_factory_.GetWeakPtr()));
registrar->Add(
ambient::prefs::kAmbientModeManagedScreensaverImageDisplayIntervalSeconds,
base::BindRepeating(
&AmbientController::
OnManagedScreensaverPhotoRefreshIntervalPrefChanged,
weak_ptr_factory_.GetWeakPtr()));
OnManagedScreensaverLockScreenIdleTimeoutPrefChanged();
OnManagedScreensaverPhotoRefreshIntervalPrefChanged();
}
void AmbientController::RemoveAmbientModeSettingsPrefObservers() {
for (const auto* pref_name :
{ambient::prefs::kAmbientModeLockScreenBackgroundTimeoutSeconds,
ambient::prefs::kAmbientModeLockScreenInactivityTimeoutSeconds,
ambient::prefs::kAmbientModePhotoRefreshIntervalSeconds,
ambient::prefs::kAmbientUiSettings,
ambient::prefs::kAmbientModeAnimationPlaybackSpeed,
ambient::prefs::kAmbientModeManagedScreensaverIdleTimeoutSeconds,
ambient::prefs::
kAmbientModeManagedScreensaverImageDisplayIntervalSeconds}) {
if (pref_change_registrar_ &&
pref_change_registrar_->IsObserved(pref_name)) {
pref_change_registrar_->Remove(pref_name);
}
if (sign_in_pref_change_registrar_ &&
sign_in_pref_change_registrar_->IsObserved(pref_name)) {
sign_in_pref_change_registrar_->Remove(pref_name);
}
}
}
void AmbientController::OnManagedScreensaverLockScreenIdleTimeoutPrefChanged() {
PrefService* pref_service = GetActivePrefService();
CHECK(pref_service);
ambient_ui_model_.SetLockScreenInactivityTimeout(
base::Seconds(pref_service->GetInteger(
ambient::prefs::kAmbientModeManagedScreensaverIdleTimeoutSeconds)));
}
void AmbientController::OnManagedScreensaverPhotoRefreshIntervalPrefChanged() {
PrefService* pref_service = GetActivePrefService();
CHECK(pref_service);
ambient_ui_model_.SetPhotoRefreshInterval(
base::Seconds(pref_service->GetInteger(
ambient::prefs::
kAmbientModeManagedScreensaverImageDisplayIntervalSeconds)));
}
void AmbientController::AddConsumerPrefObservers() {
if (!pref_change_registrar_) {
return;
}
pref_change_registrar_->Add(
ambient::prefs::kAmbientModeLockScreenInactivityTimeoutSeconds,
base::BindRepeating(
&AmbientController::OnLockScreenInactivityTimeoutPrefChanged,
weak_ptr_factory_.GetWeakPtr()));
pref_change_registrar_->Add(
ambient::prefs::kAmbientModeLockScreenBackgroundTimeoutSeconds,
base::BindRepeating(
&AmbientController::OnLockScreenBackgroundTimeoutPrefChanged,
weak_ptr_factory_.GetWeakPtr()));
pref_change_registrar_->Add(
ambient::prefs::kAmbientModePhotoRefreshIntervalSeconds,
base::BindRepeating(&AmbientController::OnPhotoRefreshIntervalPrefChanged,
weak_ptr_factory_.GetWeakPtr()));
pref_change_registrar_->Add(
ambient::prefs::kAmbientUiSettings,
base::BindRepeating(&AmbientController::OnAmbientUiSettingsChanged,
weak_ptr_factory_.GetWeakPtr()));
pref_change_registrar_->Add(
ambient::prefs::kAmbientModeAnimationPlaybackSpeed,
base::BindRepeating(&AmbientController::OnAnimationPlaybackSpeedChanged,
weak_ptr_factory_.GetWeakPtr()));
OnLockScreenInactivityTimeoutPrefChanged();
OnLockScreenBackgroundTimeoutPrefChanged();
OnPhotoRefreshIntervalPrefChanged();
OnAnimationPlaybackSpeedChanged();
}
void AmbientController::OnEnabledPrefChanged() {
RecordManagedScreensaverEnabledPref();
if (!IsAmbientModeEnabled()) {
DVLOG(1) << "Ambient mode disabled";
ResetAmbientControllerResources();
return;
}
DVLOG(1) << "Ambient mode enabled";
if (is_initialized_) {
ResetAmbientControllerResources();
}
is_initialized_ = true;
if (IsAmbientModeManagedScreensaverEnabled()) {
AddManagedScreensaverPolicyPrefObservers();
} else {
AddConsumerPrefObservers();
}
CreateUiLauncher();
ambient_ui_model_observer_.Observe(&ambient_ui_model_);
auto* power_manager_client = chromeos::PowerManagerClient::Get();
DCHECK(power_manager_client);
power_manager_client_observer_.Observe(power_manager_client);
fingerprint_->AddFingerprintObserver(
fingerprint_observer_receiver_.BindNewPipeAndPassRemote());
if (IsAmbientModeManagedScreensaverEnabled()) {
OnLoginLockStateChanged(GetLockScreenState());
}
}
void AmbientController::ResetAmbientControllerResources() {
SetUiVisibilityClosed();
RemoveAmbientModeSettingsPrefObservers();
ambient_ui_model_observer_.Reset();
power_manager_client_observer_.Reset();
DestroyUiLauncher();
if (fingerprint_observer_receiver_.is_bound()) {
fingerprint_observer_receiver_.reset();
}
is_initialized_ = false;
}
void AmbientController::OnLockScreenInactivityTimeoutPrefChanged() {
auto* pref_service = GetPrimaryUserPrefService();
if (!pref_service)
return;
ambient_ui_model_.SetLockScreenInactivityTimeout(
base::Seconds(pref_service->GetInteger(
ambient::prefs::kAmbientModeLockScreenInactivityTimeoutSeconds)));
}
void AmbientController::OnLockScreenBackgroundTimeoutPrefChanged() {
auto* pref_service = GetPrimaryUserPrefService();
if (!pref_service)
return;
ambient_ui_model_.SetBackgroundLockScreenTimeout(
base::Seconds(pref_service->GetInteger(
ambient::prefs::kAmbientModeLockScreenBackgroundTimeoutSeconds)));
}
void AmbientController::OnPhotoRefreshIntervalPrefChanged() {
auto* pref_service = GetPrimaryUserPrefService();
if (!pref_service)
return;
ambient_ui_model_.SetPhotoRefreshInterval(
base::Seconds(pref_service->GetInteger(
ambient::prefs::kAmbientModePhotoRefreshIntervalSeconds)));
}
void AmbientController::OnAmbientUiSettingsChanged() {
DVLOG(4) << "AmbientUiSettings changed to "
<< GetCurrentUiSettings().ToString();
ambient_photo_cache::Clear(ambient_photo_cache::Store::kPrimary);
CreateUiLauncher();
}
void AmbientController::OnAnimationPlaybackSpeedChanged() {
DCHECK(GetPrimaryUserPrefService());
ambient_ui_model_.set_animation_playback_speed(
GetPrimaryUserPrefService()->GetDouble(
ambient::prefs::kAmbientModeAnimationPlaybackSpeed));
}
void AmbientController::RequestAccessToken(
AmbientAccessTokenController::AccessTokenCallback callback,
bool may_refresh_token_on_lock) {
if (IsAmbientModeManagedScreensaverEnabled()) {
std::move(callback).Run(GaiaId(), "");
return;
}
access_token_controller_.RequestAccessToken(std::move(callback),
may_refresh_token_on_lock);
}
void AmbientController::DismissUI() {
ClearPreTargetHandler();
if (!IsAmbientModeEnabled()) {
SetUiVisibilityClosed();
return;
}
if (ambient_ui_model_.ui_visibility() == AmbientUiVisibility::kHidden) {
if (inactivity_timer_.IsRunning()) {
inactivity_timer_.Reset();
}
return;
}
if (LockScreen::HasInstance()) {
SetUiVisibilityHidden();
return;
}
SetUiVisibilityClosed();
}
AmbientBackendModel* AmbientController::GetAmbientBackendModel() {
return ambient_ui_launcher_->GetAmbientBackendModel();
}
AmbientWeatherModel* AmbientController::GetAmbientWeatherModel() {
return ambient_weather_controller_->weather_model();
}
std::unique_ptr<views::Widget> AmbientController::CreateWidget(
aura::Window* container) {
if (ui_launcher_state_ != AmbientUiLauncherState::kRendering) {
return nullptr;
}
CHECK(session_metrics_recorder_);
session_metrics_recorder_->RegisterScreen();
std::unique_ptr<AmbientContainerView> container_view;
container_view = std::make_unique<AmbientContainerView>(
GetCurrentUiSettings(), ambient_ui_launcher_->CreateView());
auto* widget_delegate = new AmbientWidgetDelegate();
widget_delegate->SetInitiallyFocusedView(container_view.get());
views::Widget::InitParams params(
views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET,
views::Widget::InitParams::TYPE_WINDOW_FRAMELESS);
params.name = GetWidgetName();
params.show_state = ui::mojom::WindowShowState::kFullscreen;
params.parent = container;
params.delegate = widget_delegate;
params.visible_on_all_workspaces = true;
params.opacity = views::Widget::InitParams::WindowOpacity::kTranslucent;
auto widget = std::make_unique<views::Widget>();
widget->Init(std::move(params));
auto* contents_view = widget->SetContentsView(std::move(container_view));
widget->SetVisibilityAnimationTransition(
views::Widget::VisibilityTransition::ANIMATE_BOTH);
::wm::SetWindowVisibilityAnimationType(
widget->GetNativeWindow(), ::wm::WINDOW_VISIBILITY_ANIMATION_TYPE_FADE);
::wm::SetWindowVisibilityChangesAnimated(widget->GetNativeWindow());
widget->Show();
if (Shell::GetPrimaryRootWindow() == container->GetRootWindow()) {
contents_view->GetViewAccessibility().AnnounceText(
l10n_util::GetStringUTF16(IDS_ASH_SCREENSAVER_STARTS));
}
return widget;
}
void AmbientController::OnUiLauncherInitialized(bool success) {
CHECK(session_metrics_recorder_);
session_metrics_recorder_->SetInitStatus(success);
if (!success) {
LOG(ERROR) << "AmbientUiLauncher failed to initialize";
SetUiVisibilityClosed();
return;
}
ui_launcher_state_ = AmbientUiLauncherState::kRendering;
CreateAndShowWidgets();
}
void AmbientController::CreateAndShowWidgets() {
if (ambient_ui_model_.ui_visibility() == AmbientUiVisibility::kPreview) {
preview_widget_created_at_ = base::Time::Now();
}
Shell::Get()->cursor_manager()->HideCursor();
for (auto* root_window_controller :
RootWindowController::root_window_controllers()) {
root_window_controller->CreateAmbientWidget();
}
}
void AmbientController::StopScreensaver() {
CloseAllWidgets(close_widgets_immediately_);
session_metrics_recorder_.reset();
ui_launcher_init_callback_.Cancel();
ui_launcher_state_ = AmbientUiLauncherState::kInactive;
ambient_ui_launcher_->Finalize();
}
void AmbientController::MaybeStartScreenSaver() {
if (IsUiLauncherActive()) {
return;
}
if (!user_activity_observer_.IsObserving())
user_activity_observer_.Observe(ui::UserActivityDetector::Get());
session_metrics_recorder_ = std::make_unique<AmbientSessionMetricsRecorder>(
ambient_ui_launcher_->CreateMetricsDelegate(GetCurrentUiSettings()));
SetUpPreTargetHandler();
ui_launcher_init_callback_.Reset(
base::BindOnce(&AmbientController::OnUiLauncherInitialized,
weak_ptr_factory_.GetWeakPtr()));
ui_launcher_state_ = AmbientUiLauncherState::kInitializing;
ambient_ui_launcher_->Initialize(ui_launcher_init_callback_.callback());
}
AmbientUiSettings AmbientController::GetCurrentUiSettings() const {
CHECK(GetActivePrefService());
return AmbientUiSettings::ReadFromPrefService(*GetActivePrefService());
}
void AmbientController::MaybeDismissUIOnMouseMove() {
if (!last_mouse_event_was_move_ || !IsShowing()) {
return;
}
if (ambient_ui_model_.ui_visibility() == AmbientUiVisibility::kPreview) {
auto elapsed = base::Time::Now() - preview_widget_created_at_;
if (elapsed < kDismissPreviewOnMouseMoveDelay) {
return;
}
}
DismissUI();
}
void AmbientController::CreateUiLauncher() {
if (IsUiLauncherActive()) {
LOG(DFATAL) << "Cannot reset the AmbientUiLauncher while it is active";
return;
}
DestroyUiLauncher();
if (IsAmbientModeManagedScreensaverEnabled()) {
ambient_ui_launcher_ = std::make_unique<AmbientManagedSlideshowUiLauncher>(
&delegate_, screensaver_images_policy_handler_.get());
} else {
switch (GetCurrentUiSettings().theme()) {
case personalization_app::mojom::AmbientTheme::kSlideshow:
ambient_ui_launcher_ =
std::make_unique<AmbientSlideshowUiLauncher>(&delegate_);
break;
case personalization_app::mojom::AmbientTheme::kFeelTheBreeze:
case personalization_app::mojom::AmbientTheme::kFloatOnBy:
ambient_ui_launcher_ = std::make_unique<AmbientAnimationUiLauncher>(
GetCurrentUiSettings(), &delegate_);
break;
case personalization_app::mojom::AmbientTheme::kVideo:
ambient_ui_launcher_ = std::make_unique<AmbientVideoUiLauncher>(
GetPrimaryUserPrefService(), &delegate_);
break;
}
}
ambient_ui_launcher_->SetObserver(this);
}
void AmbientController::DestroyUiLauncher() {
ui_launcher_state_ = AmbientUiLauncherState::kInactive;
ambient_ui_launcher_.reset();
}
bool AmbientController::IsUiLauncherActive() const {
return ui_launcher_state_ != AmbientUiLauncherState::kInactive;
}
void AmbientController::OnReadyStateChanged(bool is_ready) {
if (!is_ready) {
SetUiVisibilityClosed();
return;
}
OnLoginLockStateChanged(GetLockScreenState());
}
void AmbientController::MaybeStopUiEventPropagation(ui::Event* event) {
if (IsShowing()) {
event->StopPropagation();
}
}
}