ambient_controller.cc 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917
  1. // Copyright 2019 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "ash/ambient/ambient_controller.h"
  5. #include <memory>
  6. #include <string>
  7. #include <utility>
  8. #include <vector>
  9. #include "ash/ambient/ambient_weather_controller.h"
  10. #include "ash/ambient/metrics/ambient_multi_screen_metrics_recorder.h"
  11. #include "ash/ambient/model/ambient_animation_photo_config.h"
  12. #include "ash/ambient/model/ambient_backend_model_observer.h"
  13. #include "ash/ambient/model/ambient_slideshow_photo_config.h"
  14. #include "ash/ambient/model/ambient_topic_queue_animation_delegate.h"
  15. #include "ash/ambient/model/ambient_topic_queue_slideshow_delegate.h"
  16. #include "ash/ambient/resources/ambient_animation_static_resources.h"
  17. #include "ash/ambient/ui/ambient_animation_progress_tracker.h"
  18. #include "ash/ambient/ui/ambient_container_view.h"
  19. #include "ash/ambient/ui/ambient_view_delegate.h"
  20. #include "ash/ambient/util/ambient_util.h"
  21. #include "ash/assistant/model/assistant_interaction_model.h"
  22. #include "ash/constants/ash_features.h"
  23. #include "ash/login/ui/lock_screen.h"
  24. #include "ash/public/cpp/ambient/ambient_backend_controller.h"
  25. #include "ash/public/cpp/ambient/ambient_client.h"
  26. #include "ash/public/cpp/ambient/ambient_metrics.h"
  27. #include "ash/public/cpp/ambient/ambient_prefs.h"
  28. #include "ash/public/cpp/ambient/ambient_ui_model.h"
  29. #include "ash/public/cpp/ambient/common/ambient_settings.h"
  30. #include "ash/public/cpp/ambient/fake_ambient_backend_controller_impl.h"
  31. #include "ash/public/cpp/assistant/controller/assistant_interaction_controller.h"
  32. #include "ash/public/cpp/shell_window_ids.h"
  33. #include "ash/root_window_controller.h"
  34. #include "ash/session/session_controller_impl.h"
  35. #include "ash/shell.h"
  36. #include "ash/strings/grit/ash_strings.h"
  37. #include "ash/system/power/power_status.h"
  38. #include "base/bind.h"
  39. #include "base/callback_helpers.h"
  40. #include "base/check.h"
  41. #include "base/feature_list.h"
  42. #include "base/memory/weak_ptr.h"
  43. #include "base/time/time.h"
  44. #include "base/timer/timer.h"
  45. #include "build/buildflag.h"
  46. #include "cc/paint/skottie_wrapper.h"
  47. #include "chromeos/ash/components/assistant/buildflags.h"
  48. #include "chromeos/ash/services/assistant/public/cpp/assistant_service.h"
  49. #include "chromeos/dbus/power/power_manager_client.h"
  50. #include "chromeos/dbus/power_manager/backlight.pb.h"
  51. #include "chromeos/dbus/power_manager/idle.pb.h"
  52. #include "components/prefs/pref_change_registrar.h"
  53. #include "components/prefs/pref_registry_simple.h"
  54. #include "components/prefs/pref_service.h"
  55. #include "ui/aura/client/aura_constants.h"
  56. #include "ui/base/l10n/l10n_util.h"
  57. #include "ui/base/ui_base_types.h"
  58. #include "ui/base/user_activity/user_activity_detector.h"
  59. #include "ui/views/accessibility/view_accessibility.h"
  60. #include "ui/views/view.h"
  61. #include "ui/views/widget/widget.h"
  62. #include "ui/views/widget/widget_delegate.h"
  63. #include "ui/wm/core/cursor_manager.h"
  64. #include "ui/wm/core/visibility_controller.h"
  65. #include "ui/wm/core/window_animations.h"
  66. #if BUILDFLAG(ENABLE_CROS_AMBIENT_MODE_BACKEND)
  67. #include "ash/ambient/backdrop/ambient_backend_controller_impl.h"
  68. #endif // BUILDFLAG(ENABLE_CROS_AMBIENT_MODE_BACKEND)
  69. namespace ash {
  70. namespace {
  71. // Used by wake lock APIs.
  72. constexpr char kWakeLockReason[] = "AmbientMode";
  73. std::unique_ptr<AmbientBackendController> CreateAmbientBackendController() {
  74. #if BUILDFLAG(ENABLE_CROS_AMBIENT_MODE_BACKEND)
  75. return std::make_unique<AmbientBackendControllerImpl>();
  76. #else
  77. return std::make_unique<FakeAmbientBackendControllerImpl>();
  78. #endif // BUILDFLAG(ENABLE_CROS_AMBIENT_MODE_BACKEND)
  79. }
  80. // Returns the name of the ambient widget.
  81. std::string GetWidgetName() {
  82. if (ambient::util::IsShowing(LockScreen::ScreenType::kLock))
  83. return "LockScreenAmbientModeContainer";
  84. return "InSessionAmbientModeContainer";
  85. }
  86. // Returns true if the device is currently connected to a charger.
  87. bool IsChargerConnected() {
  88. DCHECK(PowerStatus::IsInitialized());
  89. auto* power_status = PowerStatus::Get();
  90. if (power_status->IsBatteryPresent()) {
  91. // If battery is full or battery is charging, that implies power is
  92. // connected. Also return true if a power source is connected and
  93. // battery is not discharging.
  94. return power_status->IsBatteryCharging() ||
  95. (power_status->IsLinePowerConnected() &&
  96. power_status->GetBatteryPercent() > 95.f);
  97. } else {
  98. // Chromeboxes have no battery.
  99. return power_status->IsLinePowerConnected();
  100. }
  101. }
  102. bool IsUiHidden(AmbientUiVisibility visibility) {
  103. return visibility == AmbientUiVisibility::kHidden;
  104. }
  105. PrefService* GetPrimaryUserPrefService() {
  106. return Shell::Get()->session_controller()->GetPrimaryUserPrefService();
  107. }
  108. bool IsAmbientModeEnabled() {
  109. if (!AmbientClient::Get()->IsAmbientModeAllowed())
  110. return false;
  111. auto* pref_service = GetPrimaryUserPrefService();
  112. return pref_service &&
  113. pref_service->GetBoolean(ambient::prefs::kAmbientModeEnabled);
  114. }
  115. class AmbientWidgetDelegate : public views::WidgetDelegate {
  116. public:
  117. AmbientWidgetDelegate() {
  118. SetCanMaximize(true);
  119. SetOwnedByWidget(true);
  120. }
  121. };
  122. } // namespace
  123. // static
  124. void AmbientController::RegisterProfilePrefs(PrefRegistrySimple* registry) {
  125. if (chromeos::features::IsAmbientModeEnabled()) {
  126. registry->RegisterStringPref(ash::ambient::prefs::kAmbientBackdropClientId,
  127. std::string());
  128. // Do not sync across devices to allow different usages for different
  129. // devices.
  130. registry->RegisterBooleanPref(ash::ambient::prefs::kAmbientModeEnabled,
  131. false);
  132. // Used to upload usage metrics. Derived from |AmbientSettings| when
  133. // settings are successfully saved by the user. This pref is not displayed
  134. // to the user.
  135. registry->RegisterIntegerPref(
  136. ash::ambient::prefs::kAmbientModePhotoSourcePref,
  137. static_cast<int>(ash::ambient::AmbientModePhotoSource::kUnset));
  138. // Used to control the number of seconds of inactivity on lock screen before
  139. // showing Ambient mode. This pref is not displayed to the user. Registered
  140. // as integer rather than TimeDelta to work with prefs_util.
  141. registry->RegisterIntegerPref(
  142. ambient::prefs::kAmbientModeLockScreenInactivityTimeoutSeconds,
  143. kLockScreenInactivityTimeout.InSeconds());
  144. // Used to control the number of seconds to lock the session after starting
  145. // Ambient mode. This pref is not displayed to the user. Registered as
  146. // integer rather than TimeDelta to work with prefs_util.
  147. registry->RegisterIntegerPref(
  148. ambient::prefs::kAmbientModeLockScreenBackgroundTimeoutSeconds,
  149. kLockScreenBackgroundTimeout.InSeconds());
  150. // Used to control the photo refresh interval in Ambient mode. This pref is
  151. // not displayed to the user. Registered as integer rather than TimeDelta to
  152. // work with prefs_util.
  153. registry->RegisterIntegerPref(
  154. ambient::prefs::kAmbientModePhotoRefreshIntervalSeconds,
  155. kPhotoRefreshInterval.InSeconds());
  156. registry->RegisterIntegerPref(
  157. ambient::prefs::kAmbientAnimationTheme,
  158. static_cast<int>(kDefaultAmbientAnimationTheme));
  159. registry->RegisterDoublePref(
  160. ambient::prefs::kAmbientModeAnimationPlaybackSpeed,
  161. kAnimationPlaybackSpeed);
  162. }
  163. }
  164. AmbientController::AmbientController(
  165. mojo::PendingRemote<device::mojom::Fingerprint> fingerprint)
  166. : ambient_weather_controller_(std::make_unique<AmbientWeatherController>()),
  167. fingerprint_(std::move(fingerprint)) {
  168. ambient_backend_controller_ = CreateAmbientBackendController();
  169. // |SessionController| is initialized before |this| in Shell. Necessary to
  170. // bind observer here to monitor |OnActiveUserPrefServiceChanged|.
  171. session_observer_.Observe(Shell::Get()->session_controller());
  172. }
  173. AmbientController::~AmbientController() {
  174. CloseAllWidgets(/*immediately=*/true);
  175. CloseUi();
  176. }
  177. void AmbientController::OnAmbientUiVisibilityChanged(
  178. AmbientUiVisibility visibility) {
  179. switch (visibility) {
  180. case AmbientUiVisibility::kShown:
  181. // Record metrics on ambient mode usage.
  182. ambient::RecordAmbientModeActivation(
  183. /*ui_mode=*/LockScreen::HasInstance() ? AmbientUiMode::kLockScreenUi
  184. : AmbientUiMode::kInSessionUi,
  185. /*tablet_mode=*/Shell::Get()->IsInTabletMode());
  186. DCHECK(!start_time_);
  187. start_time_ = base::Time::Now();
  188. multi_screen_metrics_recorder_ =
  189. std::make_unique<AmbientMultiScreenMetricsRecorder>(
  190. GetCurrentTheme());
  191. // Cancels the timer upon shown.
  192. inactivity_timer_.Stop();
  193. if (IsChargerConnected()) {
  194. // Requires wake lock to prevent display from sleeping.
  195. AcquireWakeLock();
  196. }
  197. // Observes the |PowerStatus| on the battery charging status change for
  198. // the current ambient session.
  199. if (!power_status_observer_.IsObserving())
  200. power_status_observer_.Observe(PowerStatus::Get());
  201. if (!user_activity_observer_.IsObserving())
  202. user_activity_observer_.Observe(ui::UserActivityDetector::Get());
  203. // Add observer for assistant interaction model
  204. AssistantInteractionController::Get()->GetModel()->AddObserver(this);
  205. Shell::Get()->AddPreTargetHandler(this);
  206. StartRefreshingImages();
  207. break;
  208. case AmbientUiVisibility::kHidden:
  209. case AmbientUiVisibility::kClosed: {
  210. bool ambient_ui_was_rendering =
  211. Shell::GetPrimaryRootWindowController()->HasAmbientWidget();
  212. CloseAllWidgets(/*immediately=*/false);
  213. // TODO(wutao): This will clear the image cache currently. It will not
  214. // work with `kHidden` if the token has expired and ambient mode is shown
  215. // again.
  216. StopRefreshingImages();
  217. // Should do nothing if the wake lock has already been released.
  218. ReleaseWakeLock();
  219. Shell::Get()->RemovePreTargetHandler(this);
  220. // Should stop observing AssistantInteractionModel when ambient screen is
  221. // not shown.
  222. AssistantInteractionController::Get()->GetModel()->RemoveObserver(this);
  223. multi_screen_metrics_recorder_.reset();
  224. // |start_time_| may be empty in case of |AmbientUiVisibility::kHidden| if
  225. // ambient mode has just started.
  226. if (start_time_) {
  227. auto elapsed = base::Time::Now() - start_time_.value();
  228. AmbientAnimationTheme theme = GetCurrentTheme();
  229. DVLOG(2) << "Exit ambient mode. Elapsed time: " << elapsed;
  230. ambient::RecordAmbientModeTimeElapsed(
  231. elapsed, Shell::Get()->IsInTabletMode(), theme);
  232. if (!ambient_ui_was_rendering &&
  233. elapsed >= ambient::kMetricsStartupTimeMax) {
  234. LOG(ERROR) << "Ambient UI completely failed to start";
  235. ambient::RecordAmbientModeStartupTime(elapsed, theme);
  236. }
  237. start_time_.reset();
  238. }
  239. if (visibility == AmbientUiVisibility::kHidden) {
  240. if (LockScreen::HasInstance()) {
  241. // Add observer for user activity.
  242. if (!user_activity_observer_.IsObserving())
  243. user_activity_observer_.Observe(ui::UserActivityDetector::Get());
  244. // Start timer to show ambient mode.
  245. inactivity_timer_.Start(
  246. FROM_HERE, ambient_ui_model_.lock_screen_inactivity_timeout(),
  247. base::BindOnce(&AmbientController::OnAutoShowTimeOut,
  248. weak_ptr_factory_.GetWeakPtr()));
  249. }
  250. } else {
  251. DCHECK(visibility == AmbientUiVisibility::kClosed);
  252. inactivity_timer_.Stop();
  253. user_activity_observer_.Reset();
  254. power_status_observer_.Reset();
  255. }
  256. break;
  257. }
  258. }
  259. }
  260. void AmbientController::OnAutoShowTimeOut() {
  261. DCHECK(IsUiHidden(ambient_ui_model_.ui_visibility()));
  262. // Show ambient screen after time out.
  263. ShowUi();
  264. }
  265. void AmbientController::OnLockStateChanged(bool locked) {
  266. if (!locked) {
  267. // Ambient screen will be destroyed along with the lock screen when user
  268. // logs in.
  269. CloseUi();
  270. return;
  271. }
  272. if (!IsAmbientModeEnabled()) {
  273. VLOG(1) << "Ambient mode is not allowed.";
  274. return;
  275. }
  276. // Reset image failures to allow retrying ambient mode after lock state
  277. // changes.
  278. GetAmbientBackendModel()->ResetImageFailures();
  279. // We have 3 options to manage the token for lock screen. Here use option 1.
  280. // 1. Request only one time after entering lock screen. We will use it once
  281. // to request all the image links and no more requests.
  282. // 2. Request one time before entering lock screen. This will introduce
  283. // extra latency.
  284. // 3. Request and refresh the token in the background (even the ambient mode
  285. // is not started) with extra buffer time to use. When entering
  286. // lock screen, it will be most likely to have the token already and
  287. // enough time to use. More specifically,
  288. // 3a. We will leave enough buffer time (e.g. 10 mins before expire) to
  289. // start to refresh the token.
  290. // 3b. When lock screen is triggered, most likely we will have >10 mins
  291. // of token which can be used on lock screen.
  292. // 3c. There is a corner case that we may not have the token fetched when
  293. // locking screen, we probably can use PrepareForLock(callback) when
  294. // locking screen. We can add the refresh token into it. If the token
  295. // has already been fetched, then there is not additional time to
  296. // wait.
  297. RequestAccessToken(base::DoNothing(), /*may_refresh_token_on_lock=*/true);
  298. if (!IsShown()) {
  299. // When lock screen starts, we don't immediately show the UI. The Ui is
  300. // hidden and will show after a delay.
  301. ShowHiddenUi();
  302. }
  303. }
  304. void AmbientController::OnActiveUserPrefServiceChanged(
  305. PrefService* pref_service) {
  306. if (!AmbientClient::Get()->IsAmbientModeAllowed() ||
  307. GetPrimaryUserPrefService() != pref_service) {
  308. return;
  309. }
  310. // Do not continue if pref_change_registrar has already been set up. This
  311. // prevents re-binding observers when secondary profiles are activated.
  312. if (pref_change_registrar_)
  313. return;
  314. pref_change_registrar_ = std::make_unique<PrefChangeRegistrar>();
  315. pref_change_registrar_->Init(pref_service);
  316. pref_change_registrar_->Add(
  317. ambient::prefs::kAmbientModeEnabled,
  318. base::BindRepeating(&AmbientController::OnEnabledPrefChanged,
  319. weak_ptr_factory_.GetWeakPtr()));
  320. OnEnabledPrefChanged();
  321. }
  322. void AmbientController::OnPowerStatusChanged() {
  323. if (ambient_ui_model_.ui_visibility() != AmbientUiVisibility::kShown) {
  324. // No action needed if ambient screen is not shown.
  325. return;
  326. }
  327. if (IsChargerConnected()) {
  328. AcquireWakeLock();
  329. } else {
  330. ReleaseWakeLock();
  331. }
  332. }
  333. void AmbientController::ScreenIdleStateChanged(
  334. const power_manager::ScreenIdleState& idle_state) {
  335. DVLOG(1) << "ScreenIdleStateChanged: dimmed(" << idle_state.dimmed()
  336. << ") off(" << idle_state.off() << ")";
  337. if (!IsAmbientModeEnabled())
  338. return;
  339. is_screen_off_ = idle_state.off();
  340. if (idle_state.off()) {
  341. DVLOG(1) << "Screen is off, close ambient mode.";
  342. CloseAllWidgets(/*immediately=*/true);
  343. CloseUi();
  344. return;
  345. }
  346. if (idle_state.dimmed()) {
  347. // Do not show the UI if lockscreen is active. The inactivity monitor should
  348. // have activated ambient mode.
  349. if (LockScreen::HasInstance())
  350. return;
  351. // Do not show UI if loading images was unsuccessful.
  352. if (GetAmbientBackendModel()->ImageLoadingFailed()) {
  353. VLOG(1) << "Skipping ambient mode activation due to prior failure";
  354. GetAmbientBackendModel()->ResetImageFailures();
  355. return;
  356. }
  357. ShowUi();
  358. return;
  359. }
  360. if (LockScreen::HasInstance() &&
  361. ambient_ui_model_.ui_visibility() == AmbientUiVisibility::kClosed) {
  362. // Restart hidden ui if the screen is back on and lockscreen is shown.
  363. ShowHiddenUi();
  364. }
  365. }
  366. void AmbientController::SuspendImminent(
  367. power_manager::SuspendImminent::Reason reason) {
  368. // If about to suspend, turn everything off. This covers:
  369. // 1. Clicking power button.
  370. // 2. Close lid.
  371. // Need to specially close the widget immediately here to be able to close
  372. // the UI before device goes to suspend. Otherwise when opening lid after
  373. // lid closed, there may be a flash of the old window before previous
  374. // closing finished.
  375. CloseAllWidgets(/*immediately=*/true);
  376. CloseUi();
  377. is_suspend_imminent_ = true;
  378. }
  379. void AmbientController::SuspendDone(base::TimeDelta sleep_duration) {
  380. is_suspend_imminent_ = false;
  381. // |DismissUI| will restart the lock screen timer if lock screen is active and
  382. // if Ambient mode is enabled, so call it when resuming from suspend to
  383. // restart Ambient mode if applicable.
  384. DismissUI();
  385. }
  386. void AmbientController::OnAuthScanDone(
  387. const device::mojom::FingerprintMessagePtr msg,
  388. const base::flat_map<std::string, std::vector<std::string>>& matches) {
  389. DismissUI();
  390. }
  391. void AmbientController::OnUserActivity(const ui::Event* event) {
  392. DismissUI();
  393. }
  394. void AmbientController::OnKeyEvent(ui::KeyEvent* event) {
  395. // Prevent dispatching key press event to the login UI.
  396. event->StopPropagation();
  397. DismissUI();
  398. }
  399. void AmbientController::OnInteractionStateChanged(
  400. InteractionState interaction_state) {
  401. if (interaction_state == InteractionState::kActive) {
  402. // Assistant is active.
  403. DismissUI();
  404. }
  405. }
  406. void AmbientController::ShowUi() {
  407. DVLOG(1) << __func__;
  408. // TODO(meilinw): move the eligibility check to the idle entry point once
  409. // implemented: b/149246117.
  410. if (!IsAmbientModeEnabled()) {
  411. LOG(WARNING) << "Ambient mode is not allowed.";
  412. return;
  413. }
  414. if (is_suspend_imminent_) {
  415. VLOG(1) << "Do not show UI when suspend imminent";
  416. return;
  417. }
  418. ambient_ui_model_.SetUiVisibility(AmbientUiVisibility::kShown);
  419. }
  420. void AmbientController::ShowHiddenUi() {
  421. DVLOG(1) << __func__;
  422. if (!IsAmbientModeEnabled()) {
  423. LOG(WARNING) << "Ambient mode is not allowed.";
  424. return;
  425. }
  426. if (is_suspend_imminent_) {
  427. VLOG(1) << "Do not start hidden UI when suspend imminent";
  428. return;
  429. }
  430. if (is_screen_off_) {
  431. VLOG(1) << "Do not start hidden UI when screen is off";
  432. return;
  433. }
  434. ambient_ui_model_.SetUiVisibility(AmbientUiVisibility::kHidden);
  435. }
  436. void AmbientController::CloseUi() {
  437. DVLOG(1) << __func__;
  438. ambient_ui_model_.SetUiVisibility(AmbientUiVisibility::kClosed);
  439. }
  440. void AmbientController::ToggleInSessionUi() {
  441. if (ambient_ui_model_.ui_visibility() == AmbientUiVisibility::kClosed)
  442. ShowUi();
  443. else
  444. CloseUi();
  445. }
  446. bool AmbientController::IsShown() const {
  447. return ambient_ui_model_.ui_visibility() == AmbientUiVisibility::kShown;
  448. }
  449. void AmbientController::AcquireWakeLock() {
  450. if (!wake_lock_) {
  451. mojo::Remote<device::mojom::WakeLockProvider> provider;
  452. AmbientClient::Get()->RequestWakeLockProvider(
  453. provider.BindNewPipeAndPassReceiver());
  454. provider->GetWakeLockWithoutContext(
  455. device::mojom::WakeLockType::kPreventDisplaySleep,
  456. device::mojom::WakeLockReason::kOther, kWakeLockReason,
  457. wake_lock_.BindNewPipeAndPassReceiver());
  458. }
  459. DCHECK(wake_lock_);
  460. wake_lock_->RequestWakeLock();
  461. VLOG(1) << "Acquired wake lock";
  462. auto* session_controller = Shell::Get()->session_controller();
  463. if (session_controller->CanLockScreen() &&
  464. session_controller->ShouldLockScreenAutomatically()) {
  465. if (!session_controller->IsScreenLocked() &&
  466. !delayed_lock_timer_.IsRunning()) {
  467. delayed_lock_timer_.Start(
  468. FROM_HERE, ambient_ui_model_.background_lock_screen_timeout(),
  469. base::BindOnce(
  470. []() { Shell::Get()->session_controller()->LockScreen(); }));
  471. }
  472. }
  473. }
  474. void AmbientController::ReleaseWakeLock() {
  475. if (!wake_lock_)
  476. return;
  477. wake_lock_->CancelWakeLock();
  478. VLOG(1) << "Released wake lock";
  479. delayed_lock_timer_.Stop();
  480. }
  481. void AmbientController::CloseAllWidgets(bool immediately) {
  482. for (auto* root_window_controller :
  483. RootWindowController::root_window_controllers()) {
  484. root_window_controller->CloseAmbientWidget(immediately);
  485. }
  486. }
  487. void AmbientController::OnEnabledPrefChanged() {
  488. if (IsAmbientModeEnabled()) {
  489. DVLOG(1) << "Ambient mode enabled";
  490. pref_change_registrar_->Add(
  491. ambient::prefs::kAmbientModeLockScreenInactivityTimeoutSeconds,
  492. base::BindRepeating(
  493. &AmbientController::OnLockScreenInactivityTimeoutPrefChanged,
  494. weak_ptr_factory_.GetWeakPtr()));
  495. pref_change_registrar_->Add(
  496. ambient::prefs::kAmbientModeLockScreenBackgroundTimeoutSeconds,
  497. base::BindRepeating(
  498. &AmbientController::OnLockScreenBackgroundTimeoutPrefChanged,
  499. weak_ptr_factory_.GetWeakPtr()));
  500. pref_change_registrar_->Add(
  501. ambient::prefs::kAmbientModePhotoRefreshIntervalSeconds,
  502. base::BindRepeating(
  503. &AmbientController::OnPhotoRefreshIntervalPrefChanged,
  504. weak_ptr_factory_.GetWeakPtr()));
  505. pref_change_registrar_->Add(
  506. ambient::prefs::kAmbientAnimationTheme,
  507. base::BindRepeating(&AmbientController::OnAnimationThemePrefChanged,
  508. weak_ptr_factory_.GetWeakPtr()));
  509. pref_change_registrar_->Add(
  510. ambient::prefs::kAmbientModeAnimationPlaybackSpeed,
  511. base::BindRepeating(&AmbientController::OnAnimationPlaybackSpeedChanged,
  512. weak_ptr_factory_.GetWeakPtr()));
  513. // Trigger the callbacks manually the first time to init AmbientUiModel.
  514. OnLockScreenInactivityTimeoutPrefChanged();
  515. OnLockScreenBackgroundTimeoutPrefChanged();
  516. OnPhotoRefreshIntervalPrefChanged();
  517. OnAnimationThemePrefChanged();
  518. OnAnimationPlaybackSpeedChanged();
  519. DCHECK(AmbientClient::Get());
  520. ambient_photo_controller_ = std::make_unique<AmbientPhotoController>(
  521. *AmbientClient::Get(), access_token_controller_, delegate_,
  522. // The type of photo config specified here is actually irrelevant as it
  523. // always gets reset with the correct configuration anyways in
  524. // StartRefreshingImages() before ambient mode starts.
  525. CreateAmbientSlideshowPhotoConfig());
  526. ambient_ui_model_observer_.Observe(&ambient_ui_model_);
  527. ambient_backend_model_observer_.Observe(GetAmbientBackendModel());
  528. auto* power_manager_client = chromeos::PowerManagerClient::Get();
  529. DCHECK(power_manager_client);
  530. power_manager_client_observer_.Observe(power_manager_client);
  531. fingerprint_->AddFingerprintObserver(
  532. fingerprint_observer_receiver_.BindNewPipeAndPassRemote());
  533. ambient_animation_progress_tracker_ =
  534. std::make_unique<AmbientAnimationProgressTracker>();
  535. } else {
  536. DVLOG(1) << "Ambient mode disabled";
  537. CloseUi();
  538. ambient_animation_progress_tracker_.reset();
  539. for (const auto* pref_name :
  540. {ambient::prefs::kAmbientModeLockScreenBackgroundTimeoutSeconds,
  541. ambient::prefs::kAmbientModeLockScreenInactivityTimeoutSeconds,
  542. ambient::prefs::kAmbientModePhotoRefreshIntervalSeconds,
  543. ambient::prefs::kAmbientAnimationTheme,
  544. ambient::prefs::kAmbientModeAnimationPlaybackSpeed}) {
  545. if (pref_change_registrar_->IsObserved(pref_name))
  546. pref_change_registrar_->Remove(pref_name);
  547. }
  548. ambient_ui_model_observer_.Reset();
  549. ambient_backend_model_observer_.Reset();
  550. power_manager_client_observer_.Reset();
  551. if (fingerprint_observer_receiver_.is_bound())
  552. fingerprint_observer_receiver_.reset();
  553. ambient_photo_controller_.reset();
  554. current_theme_from_pref_.reset();
  555. }
  556. }
  557. void AmbientController::OnLockScreenInactivityTimeoutPrefChanged() {
  558. auto* pref_service = GetPrimaryUserPrefService();
  559. if (!pref_service)
  560. return;
  561. ambient_ui_model_.SetLockScreenInactivityTimeout(
  562. base::Seconds(pref_service->GetInteger(
  563. ambient::prefs::kAmbientModeLockScreenInactivityTimeoutSeconds)));
  564. }
  565. void AmbientController::OnLockScreenBackgroundTimeoutPrefChanged() {
  566. auto* pref_service = GetPrimaryUserPrefService();
  567. if (!pref_service)
  568. return;
  569. ambient_ui_model_.SetBackgroundLockScreenTimeout(
  570. base::Seconds(pref_service->GetInteger(
  571. ambient::prefs::kAmbientModeLockScreenBackgroundTimeoutSeconds)));
  572. }
  573. void AmbientController::OnPhotoRefreshIntervalPrefChanged() {
  574. auto* pref_service = GetPrimaryUserPrefService();
  575. if (!pref_service)
  576. return;
  577. ambient_ui_model_.SetPhotoRefreshInterval(
  578. base::Seconds(pref_service->GetInteger(
  579. ambient::prefs::kAmbientModePhotoRefreshIntervalSeconds)));
  580. }
  581. void AmbientController::OnAnimationThemePrefChanged() {
  582. absl::optional<AmbientAnimationTheme> previous_theme_from_pref =
  583. current_theme_from_pref_;
  584. DCHECK(GetPrimaryUserPrefService());
  585. int current_theme_as_int = GetPrimaryUserPrefService()->GetInteger(
  586. ambient::prefs::kAmbientAnimationTheme);
  587. // Gracefully handle pref having invalid value in case pref storage is
  588. // corrupted somehow.
  589. if (current_theme_as_int < 0 ||
  590. current_theme_as_int >
  591. static_cast<int>(AmbientAnimationTheme::kMaxValue)) {
  592. LOG(WARNING) << "Loaded invalid ambient theme from pref storage: "
  593. << current_theme_as_int << ". Default to "
  594. << ToString(kDefaultAmbientAnimationTheme);
  595. current_theme_as_int = static_cast<int>(kDefaultAmbientAnimationTheme);
  596. }
  597. current_theme_from_pref_ =
  598. static_cast<AmbientAnimationTheme>(current_theme_as_int);
  599. if (previous_theme_from_pref.has_value()) {
  600. DVLOG(4) << "AmbientAnimationTheme changed from "
  601. << ToString(*previous_theme_from_pref) << " to "
  602. << ToString(*current_theme_from_pref_);
  603. // For a given topic category, the topics downloaded from IMAX and saved to
  604. // cache differ from theme to theme:
  605. // 1) Slideshow mode keeps primary/related photos paired within a topic,
  606. // whereas animated themes split the photos into 2 separate topics.
  607. // 2) The resolution of the photos downloaded from FIFE may differ between
  608. // themes, depending on the image assets' sizes in the animation file.
  609. // For this reason, it is better to not re-use the cache when switching
  610. // between themes.
  611. //
  612. // There are corner cases here where the theme may change and the program
  613. // crashes before the cache gets cleared below. This is intentionally not
  614. // accounted for because it's not worth the added complexity. If this
  615. // should happen, re-using the cache will still work without fatal behavior.
  616. // The UI may just not be optimal. Furthermore, the cache gradually gets
  617. // overwritten with topics reflecting the new theme anyways, so ambient mode
  618. // should not be stuck with a mismatched cache indefinitely.
  619. DCHECK(ambient_photo_controller_);
  620. ambient_photo_controller_->ClearCache();
  621. } else {
  622. DVLOG(4) << "AmbientAnimationTheme initialized to "
  623. << ToString(*current_theme_from_pref_);
  624. }
  625. }
  626. void AmbientController::OnAnimationPlaybackSpeedChanged() {
  627. DCHECK(GetPrimaryUserPrefService());
  628. ambient_ui_model_.set_animation_playback_speed(
  629. GetPrimaryUserPrefService()->GetDouble(
  630. ambient::prefs::kAmbientModeAnimationPlaybackSpeed));
  631. }
  632. void AmbientController::RequestAccessToken(
  633. AmbientAccessTokenController::AccessTokenCallback callback,
  634. bool may_refresh_token_on_lock) {
  635. access_token_controller_.RequestAccessToken(std::move(callback),
  636. may_refresh_token_on_lock);
  637. }
  638. void AmbientController::DismissUI() {
  639. if (!IsAmbientModeEnabled()) {
  640. CloseUi();
  641. return;
  642. }
  643. if (ambient_ui_model_.ui_visibility() == AmbientUiVisibility::kHidden) {
  644. inactivity_timer_.Reset();
  645. return;
  646. }
  647. if (LockScreen::HasInstance()) {
  648. ShowHiddenUi();
  649. return;
  650. }
  651. CloseUi();
  652. }
  653. AmbientBackendModel* AmbientController::GetAmbientBackendModel() {
  654. DCHECK(ambient_photo_controller_);
  655. return ambient_photo_controller_->ambient_backend_model();
  656. }
  657. AmbientWeatherModel* AmbientController::GetAmbientWeatherModel() {
  658. return ambient_weather_controller_->weather_model();
  659. }
  660. void AmbientController::OnImagesReady() {
  661. CreateAndShowWidgets();
  662. }
  663. void AmbientController::OnImagesFailed() {
  664. LOG(ERROR) << "Ambient mode failed to start";
  665. CloseUi();
  666. }
  667. std::unique_ptr<views::Widget> AmbientController::CreateWidget(
  668. aura::Window* container) {
  669. AmbientAnimationTheme current_theme = GetCurrentTheme();
  670. auto container_view = std::make_unique<AmbientContainerView>(
  671. &delegate_, ambient_animation_progress_tracker_.get(),
  672. AmbientAnimationStaticResources::Create(current_theme,
  673. /*serializable=*/true),
  674. multi_screen_metrics_recorder_.get());
  675. auto* widget_delegate = new AmbientWidgetDelegate();
  676. widget_delegate->SetInitiallyFocusedView(container_view.get());
  677. views::Widget::InitParams params;
  678. params.type = views::Widget::InitParams::TYPE_WINDOW_FRAMELESS;
  679. params.name = GetWidgetName();
  680. params.show_state = ui::SHOW_STATE_FULLSCREEN;
  681. params.parent = container;
  682. params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
  683. params.delegate = widget_delegate;
  684. params.visible_on_all_workspaces = true;
  685. // Do not change the video wake lock.
  686. params.opacity = views::Widget::InitParams::WindowOpacity::kTranslucent;
  687. auto widget = std::make_unique<views::Widget>();
  688. widget->Init(std::move(params));
  689. auto* contents_view = widget->SetContentsView(std::move(container_view));
  690. widget->SetVisibilityAnimationTransition(
  691. views::Widget::VisibilityTransition::ANIMATE_BOTH);
  692. ::wm::SetWindowVisibilityAnimationType(
  693. widget->GetNativeWindow(), ::wm::WINDOW_VISIBILITY_ANIMATION_TYPE_FADE);
  694. ::wm::SetWindowVisibilityChangesAnimated(widget->GetNativeWindow());
  695. widget->Show();
  696. DCHECK(start_time_);
  697. ambient::RecordAmbientModeStartupTime(base::Time::Now() - *start_time_,
  698. current_theme);
  699. // Only announce for the primary window.
  700. if (Shell::GetPrimaryRootWindow() == container->GetRootWindow()) {
  701. contents_view->GetViewAccessibility().AnnounceText(
  702. l10n_util::GetStringUTF16(IDS_ASH_SCREENSAVER_STARTS));
  703. }
  704. return widget;
  705. }
  706. void AmbientController::CreateAndShowWidgets() {
  707. // Hide cursor.
  708. Shell::Get()->cursor_manager()->HideCursor();
  709. for (auto* root_window_controller :
  710. RootWindowController::root_window_controllers()) {
  711. root_window_controller->CreateAmbientWidget();
  712. }
  713. }
  714. void AmbientController::StartRefreshingImages() {
  715. DCHECK(ambient_photo_controller_);
  716. // There is no use case for switching themes "on-the-fly" while ambient mode
  717. // is rendering. Thus, it's sufficient to just reinitialize the
  718. // model/controller with the appropriate config each time before calling
  719. // StartScreenUpdate().
  720. DCHECK(!ambient_photo_controller_->IsScreenUpdateActive());
  721. AmbientAnimationTheme current_theme = GetCurrentTheme();
  722. DVLOG(4) << "Loaded ambient theme " << ToString(current_theme);
  723. AmbientPhotoConfig photo_config;
  724. std::unique_ptr<AmbientTopicQueue::Delegate> topic_queue_delegate;
  725. if (current_theme == AmbientAnimationTheme::kSlideshow) {
  726. photo_config = CreateAmbientSlideshowPhotoConfig();
  727. topic_queue_delegate =
  728. std::make_unique<AmbientTopicQueueSlideshowDelegate>();
  729. } else {
  730. scoped_refptr<cc::SkottieWrapper> animation =
  731. AmbientAnimationStaticResources::Create(current_theme,
  732. /*serializable=*/false)
  733. ->GetSkottieWrapper();
  734. photo_config =
  735. CreateAmbientAnimationPhotoConfig(animation->GetImageAssetMetadata());
  736. topic_queue_delegate = std::make_unique<AmbientTopicQueueAnimationDelegate>(
  737. animation->GetImageAssetMetadata());
  738. }
  739. ambient_photo_controller_->ambient_backend_model()->SetPhotoConfig(
  740. std::move(photo_config));
  741. ambient_photo_controller_->StartScreenUpdate(std::move(topic_queue_delegate));
  742. }
  743. void AmbientController::StopRefreshingImages() {
  744. DCHECK(ambient_photo_controller_);
  745. ambient_photo_controller_->StopScreenUpdate();
  746. }
  747. AmbientAnimationTheme AmbientController::GetCurrentTheme() const {
  748. AmbientAnimationTheme current_theme = kDefaultAmbientAnimationTheme;
  749. absl::optional<bool> animation_experiment_enabled =
  750. base::FeatureList::GetStateIfOverridden(
  751. features::kAmbientModeAnimationFeature);
  752. if (animation_experiment_enabled.has_value()) {
  753. // Allows developers to enable the animation without having to depend on
  754. // personalization hub by overriding the dedicated animation experiment.
  755. current_theme = animation_experiment_enabled.value()
  756. ? features::kAmbientModeAnimationThemeParam.Get()
  757. : kDefaultAmbientAnimationTheme;
  758. } else if (features::IsAmbientModeAnimationEnabled()) {
  759. DCHECK(current_theme_from_pref_);
  760. current_theme = *current_theme_from_pref_;
  761. }
  762. return current_theme;
  763. }
  764. void AmbientController::set_backend_controller_for_testing(
  765. std::unique_ptr<AmbientBackendController> backend_controller) {
  766. ambient_backend_controller_ = std::move(backend_controller);
  767. }
  768. } // namespace ash