1 // Copyright 2013 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.
5 #include "ash/wm/lock_state_controller.h"
9 #include "ash/accessibility_delegate.h"
10 #include "ash/ash_switches.h"
11 #include "ash/cancel_mode.h"
12 #include "ash/metrics/user_metrics_recorder.h"
13 #include "ash/shell.h"
14 #include "ash/shell_delegate.h"
15 #include "ash/shell_window_ids.h"
16 #include "ash/wm/session_state_animator.h"
17 #include "base/bind_helpers.h"
18 #include "base/command_line.h"
19 #include "base/strings/string_util.h"
20 #include "base/timer/timer.h"
21 #include "ui/aura/window_tree_host.h"
22 #include "ui/compositor/layer_animation_sequence.h"
23 #include "ui/compositor/scoped_layer_animation_settings.h"
24 #include "ui/views/controls/menu/menu_controller.h"
25 #include "ui/wm/core/compound_event_filter.h"
27 #if defined(OS_CHROMEOS)
28 #include "base/sys_info.h"
29 #include "media/audio/sounds/sounds_manager.h"
32 #if defined(OS_CHROMEOS)
33 using media::SoundsManager
;
40 #if defined(OS_CHROMEOS)
41 const int kMaxShutdownSoundDurationMs
= 1500;
44 aura::Window
* GetBackground() {
45 aura::Window
* root_window
= Shell::GetPrimaryRootWindow();
46 return Shell::GetContainer(root_window
,
47 kShellWindowId_DesktopBackgroundContainer
);
50 bool IsBackgroundHidden() {
51 return !GetBackground()->IsVisible();
54 void ShowBackground() {
55 ui::ScopedLayerAnimationSettings
settings(
56 GetBackground()->layer()->GetAnimator());
57 settings
.SetTransitionDuration(base::TimeDelta());
58 GetBackground()->Show();
61 void HideBackground() {
62 ui::ScopedLayerAnimationSettings
settings(
63 GetBackground()->layer()->GetAnimator());
64 settings
.SetTransitionDuration(base::TimeDelta());
65 GetBackground()->Hide();
68 // This observer is intended to use in cases when some action has to be taken
69 // once some animation successfully completes (i.e. it was not aborted).
70 // Observer will count a number of sequences it is attached to, and a number of
71 // finished sequences (either Ended or Aborted). Once these two numbers are
72 // equal, observer will delete itself, calling callback passed to constructor if
73 // there were no aborted animations.
74 // This way it can be either used to wait for some animation to be finished in
75 // multiple layers, to wait once a sequence of animations is finished in one
76 // layer or the mixture of both.
77 class AnimationFinishedObserver
: public ui::LayerAnimationObserver
{
79 explicit AnimationFinishedObserver(base::Closure
&callback
)
80 : callback_(callback
),
81 sequences_attached_(0),
82 sequences_completed_(0),
86 // Pauses observer: no checks will be made while paused. It can be used when
87 // a sequence has some immediate animations in the beginning, and for
88 // animations that can be tested with flag that makes all animations
94 // Unpauses observer. It does a check and calls callback if conditions are
100 if (sequences_completed_
== sequences_attached_
) {
107 virtual ~AnimationFinishedObserver() {
110 // LayerAnimationObserver implementation
111 virtual void OnLayerAnimationEnded(
112 ui::LayerAnimationSequence
* sequence
) OVERRIDE
{
113 sequences_completed_
++;
114 if ((sequences_completed_
== sequences_attached_
) && !paused_
) {
120 virtual void OnLayerAnimationAborted(
121 ui::LayerAnimationSequence
* sequence
) OVERRIDE
{
122 sequences_completed_
++;
123 if ((sequences_completed_
== sequences_attached_
) && !paused_
)
127 virtual void OnLayerAnimationScheduled(
128 ui::LayerAnimationSequence
* sequence
) OVERRIDE
{
131 virtual void OnAttachedToSequence(
132 ui::LayerAnimationSequence
* sequence
) OVERRIDE
{
133 LayerAnimationObserver::OnAttachedToSequence(sequence
);
134 sequences_attached_
++;
137 // Callback to be called.
138 base::Closure callback_
;
140 // Number of sequences this observer was attached to.
141 int sequences_attached_
;
143 // Number of sequences either ended or aborted.
144 int sequences_completed_
;
148 DISALLOW_COPY_AND_ASSIGN(AnimationFinishedObserver
);
153 const int LockStateController::kLockTimeoutMs
= 400;
154 const int LockStateController::kShutdownTimeoutMs
= 400;
155 const int LockStateController::kLockFailTimeoutMs
= 8000;
156 const int LockStateController::kLockToShutdownTimeoutMs
= 150;
157 const int LockStateController::kShutdownRequestDelayMs
= 50;
159 LockStateController::TestApi::TestApi(LockStateController
* controller
)
160 : controller_(controller
) {
163 LockStateController::TestApi::~TestApi() {
166 LockStateController::LockStateController()
167 : animator_(new SessionStateAnimator()),
168 login_status_(user::LOGGED_IN_NONE
),
169 system_is_locked_(false),
170 shutting_down_(false),
171 shutdown_after_lock_(false),
172 animating_lock_(false),
173 can_cancel_lock_animation_(false),
174 weak_ptr_factory_(this) {
175 Shell::GetPrimaryRootWindow()->GetHost()->AddObserver(this);
178 LockStateController::~LockStateController() {
179 Shell::GetPrimaryRootWindow()->GetHost()->RemoveObserver(this);
182 void LockStateController::SetDelegate(LockStateControllerDelegate
* delegate
) {
183 delegate_
.reset(delegate
);
186 void LockStateController::AddObserver(LockStateObserver
* observer
) {
187 observers_
.AddObserver(observer
);
190 void LockStateController::RemoveObserver(LockStateObserver
* observer
) {
191 observers_
.RemoveObserver(observer
);
194 bool LockStateController::HasObserver(LockStateObserver
* observer
) {
195 return observers_
.HasObserver(observer
);
198 void LockStateController::StartLockAnimation(
199 bool shutdown_after_lock
) {
202 shutdown_after_lock_
= shutdown_after_lock
;
203 can_cancel_lock_animation_
= true;
205 StartCancellablePreLockAnimation();
208 void LockStateController::StartShutdownAnimation() {
209 StartCancellableShutdownAnimation();
212 void LockStateController::StartLockAnimationAndLockImmediately() {
215 StartImmediatePreLockAnimation(true /* request_lock_on_completion */);
218 bool LockStateController::LockRequested() {
219 return lock_fail_timer_
.IsRunning();
222 bool LockStateController::ShutdownRequested() {
223 return shutting_down_
;
226 bool LockStateController::CanCancelLockAnimation() {
227 return can_cancel_lock_animation_
;
230 void LockStateController::CancelLockAnimation() {
231 if (!CanCancelLockAnimation())
233 shutdown_after_lock_
= false;
234 animating_lock_
= false;
235 CancelPreLockAnimation();
238 bool LockStateController::CanCancelShutdownAnimation() {
239 return pre_shutdown_timer_
.IsRunning() ||
240 shutdown_after_lock_
||
241 lock_to_shutdown_timer_
.IsRunning();
244 void LockStateController::CancelShutdownAnimation() {
245 if (!CanCancelShutdownAnimation())
247 if (lock_to_shutdown_timer_
.IsRunning()) {
248 lock_to_shutdown_timer_
.Stop();
251 if (shutdown_after_lock_
) {
252 shutdown_after_lock_
= false;
256 animator_
->StartGlobalAnimation(
257 SessionStateAnimator::ANIMATION_UNDO_GRAYSCALE_BRIGHTNESS
,
258 SessionStateAnimator::ANIMATION_SPEED_REVERT_SHUTDOWN
);
259 pre_shutdown_timer_
.Stop();
262 void LockStateController::OnStartingLock() {
263 if (shutting_down_
|| system_is_locked_
)
267 StartImmediatePreLockAnimation(false /* request_lock_on_completion */);
270 void LockStateController::RequestShutdown() {
274 shutting_down_
= true;
276 Shell
* shell
= ash::Shell::GetInstance();
277 shell
->cursor_manager()->HideCursor();
278 shell
->cursor_manager()->LockCursor();
280 animator_
->StartGlobalAnimation(
281 SessionStateAnimator::ANIMATION_GRAYSCALE_BRIGHTNESS
,
282 SessionStateAnimator::ANIMATION_SPEED_SHUTDOWN
);
283 StartRealShutdownTimer(true);
286 void LockStateController::OnLockScreenHide(
287 base::Callback
<void(void)>& callback
) {
288 StartUnlockAnimationBeforeUIDestroyed(callback
);
291 void LockStateController::SetLockScreenDisplayedCallback(
292 const base::Closure
& callback
) {
293 lock_screen_displayed_callback_
= callback
;
296 void LockStateController::OnHostCloseRequested(
297 const aura::WindowTreeHost
* host
) {
298 Shell::GetInstance()->delegate()->Exit();
301 void LockStateController::OnLoginStateChanged(
302 user::LoginStatus status
) {
303 if (status
!= user::LOGGED_IN_LOCKED
)
304 login_status_
= status
;
305 system_is_locked_
= (status
== user::LOGGED_IN_LOCKED
);
308 void LockStateController::OnAppTerminating() {
309 // If we hear that Chrome is exiting but didn't request it ourselves, all we
310 // can really hope for is that we'll have time to clear the screen.
311 // This is also the case when the user signs off.
312 if (!shutting_down_
) {
313 shutting_down_
= true;
314 Shell
* shell
= ash::Shell::GetInstance();
315 shell
->cursor_manager()->HideCursor();
316 shell
->cursor_manager()->LockCursor();
317 animator_
->StartAnimation(SessionStateAnimator::kAllContainersMask
,
318 SessionStateAnimator::ANIMATION_HIDE_IMMEDIATELY
,
319 SessionStateAnimator::ANIMATION_SPEED_IMMEDIATE
);
323 void LockStateController::OnLockStateChanged(bool locked
) {
324 VLOG(1) << "OnLockStateChanged " << locked
;
325 if (shutting_down_
|| (system_is_locked_
== locked
))
328 system_is_locked_
= locked
;
331 StartPostLockAnimation();
332 lock_fail_timer_
.Stop();
334 StartUnlockAnimationAfterUIDestroyed();
338 void LockStateController::OnLockFailTimeout() {
339 DCHECK(!system_is_locked_
);
340 CHECK(false) << "We can not be sure about the lock state. Crash and let the "
341 << "SessionManager end the session";
344 void LockStateController::StartLockToShutdownTimer() {
345 shutdown_after_lock_
= false;
346 lock_to_shutdown_timer_
.Stop();
347 lock_to_shutdown_timer_
.Start(
349 base::TimeDelta::FromMilliseconds(kLockToShutdownTimeoutMs
),
350 this, &LockStateController::OnLockToShutdownTimeout
);
353 void LockStateController::OnLockToShutdownTimeout() {
354 DCHECK(system_is_locked_
);
355 StartCancellableShutdownAnimation();
358 void LockStateController::StartPreShutdownAnimationTimer() {
359 pre_shutdown_timer_
.Stop();
360 pre_shutdown_timer_
.Start(
362 animator_
->GetDuration(SessionStateAnimator::ANIMATION_SPEED_SHUTDOWN
),
364 &LockStateController::OnPreShutdownAnimationTimeout
);
367 void LockStateController::OnPreShutdownAnimationTimeout() {
368 VLOG(1) << "OnPreShutdownAnimationTimeout";
369 shutting_down_
= true;
371 Shell
* shell
= ash::Shell::GetInstance();
372 shell
->cursor_manager()->HideCursor();
374 StartRealShutdownTimer(false);
377 void LockStateController::StartRealShutdownTimer(bool with_animation_time
) {
378 base::TimeDelta duration
=
379 base::TimeDelta::FromMilliseconds(kShutdownRequestDelayMs
);
380 if (with_animation_time
) {
382 animator_
->GetDuration(SessionStateAnimator::ANIMATION_SPEED_SHUTDOWN
);
385 #if defined(OS_CHROMEOS)
386 const AccessibilityDelegate
* const delegate
=
387 Shell::GetInstance()->accessibility_delegate();
388 base::TimeDelta sound_duration
= delegate
->PlayShutdownSound();
390 std::min(sound_duration
,
391 base::TimeDelta::FromMilliseconds(kMaxShutdownSoundDurationMs
));
392 duration
= std::max(duration
, sound_duration
);
395 real_shutdown_timer_
.Start(
396 FROM_HERE
, duration
, this, &LockStateController::OnRealShutdownTimeout
);
399 void LockStateController::OnRealShutdownTimeout() {
400 VLOG(1) << "OnRealShutdownTimeout";
401 DCHECK(shutting_down_
);
402 #if defined(OS_CHROMEOS)
403 if (!base::SysInfo::IsRunningOnChromeOS()) {
404 ShellDelegate
* delegate
= Shell::GetInstance()->delegate();
411 Shell::GetInstance()->metrics()->RecordUserMetricsAction(
412 UMA_ACCEL_SHUT_DOWN_POWER_BUTTON
);
413 delegate_
->RequestShutdown();
416 void LockStateController::StartCancellableShutdownAnimation() {
417 Shell
* shell
= ash::Shell::GetInstance();
418 // Hide cursor, but let it reappear if the mouse moves.
419 shell
->cursor_manager()->HideCursor();
421 animator_
->StartGlobalAnimation(
422 SessionStateAnimator::ANIMATION_GRAYSCALE_BRIGHTNESS
,
423 SessionStateAnimator::ANIMATION_SPEED_SHUTDOWN
);
424 StartPreShutdownAnimationTimer();
427 void LockStateController::StartImmediatePreLockAnimation(
428 bool request_lock_on_completion
) {
429 VLOG(1) << "StartImmediatePreLockAnimation " << request_lock_on_completion
;
430 animating_lock_
= true;
431 StoreUnlockedProperties();
433 base::Closure next_animation_starter
=
434 base::Bind(&LockStateController::PreLockAnimationFinished
,
435 weak_ptr_factory_
.GetWeakPtr(),
436 request_lock_on_completion
);
437 AnimationFinishedObserver
* observer
=
438 new AnimationFinishedObserver(next_animation_starter
);
442 animator_
->StartAnimationWithObserver(
443 SessionStateAnimator::NON_LOCK_SCREEN_CONTAINERS
,
444 SessionStateAnimator::ANIMATION_LIFT
,
445 SessionStateAnimator::ANIMATION_SPEED_MOVE_WINDOWS
,
447 animator_
->StartAnimationWithObserver(
448 SessionStateAnimator::LAUNCHER
,
449 SessionStateAnimator::ANIMATION_FADE_OUT
,
450 SessionStateAnimator::ANIMATION_SPEED_MOVE_WINDOWS
,
452 // Hide the screen locker containers so we can raise them later.
453 animator_
->StartAnimation(SessionStateAnimator::LOCK_SCREEN_CONTAINERS
,
454 SessionStateAnimator::ANIMATION_HIDE_IMMEDIATELY
,
455 SessionStateAnimator::ANIMATION_SPEED_IMMEDIATE
);
456 AnimateBackgroundAppearanceIfNecessary(
457 SessionStateAnimator::ANIMATION_SPEED_MOVE_WINDOWS
, observer
);
461 DispatchCancelMode();
462 FOR_EACH_OBSERVER(LockStateObserver
, observers_
,
463 OnLockStateEvent(LockStateObserver::EVENT_LOCK_ANIMATION_STARTED
));
466 void LockStateController::StartCancellablePreLockAnimation() {
467 animating_lock_
= true;
468 StoreUnlockedProperties();
469 VLOG(1) << "StartCancellablePreLockAnimation";
470 base::Closure next_animation_starter
=
471 base::Bind(&LockStateController::PreLockAnimationFinished
,
472 weak_ptr_factory_
.GetWeakPtr(),
473 true /* request_lock */);
474 AnimationFinishedObserver
* observer
=
475 new AnimationFinishedObserver(next_animation_starter
);
479 animator_
->StartAnimationWithObserver(
480 SessionStateAnimator::NON_LOCK_SCREEN_CONTAINERS
,
481 SessionStateAnimator::ANIMATION_LIFT
,
482 SessionStateAnimator::ANIMATION_SPEED_UNDOABLE
,
484 animator_
->StartAnimationWithObserver(
485 SessionStateAnimator::LAUNCHER
,
486 SessionStateAnimator::ANIMATION_FADE_OUT
,
487 SessionStateAnimator::ANIMATION_SPEED_UNDOABLE
,
489 // Hide the screen locker containers so we can raise them later.
490 animator_
->StartAnimation(SessionStateAnimator::LOCK_SCREEN_CONTAINERS
,
491 SessionStateAnimator::ANIMATION_HIDE_IMMEDIATELY
,
492 SessionStateAnimator::ANIMATION_SPEED_IMMEDIATE
);
493 AnimateBackgroundAppearanceIfNecessary(
494 SessionStateAnimator::ANIMATION_SPEED_UNDOABLE
, observer
);
496 DispatchCancelMode();
497 FOR_EACH_OBSERVER(LockStateObserver
, observers_
,
498 OnLockStateEvent(LockStateObserver::EVENT_PRELOCK_ANIMATION_STARTED
));
502 void LockStateController::CancelPreLockAnimation() {
503 VLOG(1) << "CancelPreLockAnimation";
504 base::Closure next_animation_starter
=
505 base::Bind(&LockStateController::LockAnimationCancelled
,
506 weak_ptr_factory_
.GetWeakPtr());
507 AnimationFinishedObserver
* observer
=
508 new AnimationFinishedObserver(next_animation_starter
);
512 animator_
->StartAnimationWithObserver(
513 SessionStateAnimator::NON_LOCK_SCREEN_CONTAINERS
,
514 SessionStateAnimator::ANIMATION_UNDO_LIFT
,
515 SessionStateAnimator::ANIMATION_SPEED_UNDO_MOVE_WINDOWS
,
517 animator_
->StartAnimationWithObserver(
518 SessionStateAnimator::LAUNCHER
,
519 SessionStateAnimator::ANIMATION_FADE_IN
,
520 SessionStateAnimator::ANIMATION_SPEED_UNDO_MOVE_WINDOWS
,
522 AnimateBackgroundHidingIfNecessary(
523 SessionStateAnimator::ANIMATION_SPEED_UNDO_MOVE_WINDOWS
, observer
);
528 void LockStateController::StartPostLockAnimation() {
529 VLOG(1) << "StartPostLockAnimation";
530 base::Closure next_animation_starter
=
531 base::Bind(&LockStateController::PostLockAnimationFinished
,
532 weak_ptr_factory_
.GetWeakPtr());
534 AnimationFinishedObserver
* observer
=
535 new AnimationFinishedObserver(next_animation_starter
);
538 animator_
->StartAnimationWithObserver(
539 SessionStateAnimator::LOCK_SCREEN_CONTAINERS
,
540 SessionStateAnimator::ANIMATION_RAISE_TO_SCREEN
,
541 SessionStateAnimator::ANIMATION_SPEED_MOVE_WINDOWS
,
546 void LockStateController::StartUnlockAnimationBeforeUIDestroyed(
547 base::Closure
& callback
) {
548 VLOG(1) << "StartUnlockAnimationBeforeUIDestroyed";
549 animator_
->StartAnimationWithCallback(
550 SessionStateAnimator::LOCK_SCREEN_CONTAINERS
,
551 SessionStateAnimator::ANIMATION_LIFT
,
552 SessionStateAnimator::ANIMATION_SPEED_MOVE_WINDOWS
,
556 void LockStateController::StartUnlockAnimationAfterUIDestroyed() {
557 VLOG(1) << "StartUnlockAnimationAfterUIDestroyed";
558 base::Closure next_animation_starter
=
559 base::Bind(&LockStateController::UnlockAnimationAfterUIDestroyedFinished
,
560 weak_ptr_factory_
.GetWeakPtr());
562 AnimationFinishedObserver
* observer
=
563 new AnimationFinishedObserver(next_animation_starter
);
567 animator_
->StartAnimationWithObserver(
568 SessionStateAnimator::NON_LOCK_SCREEN_CONTAINERS
,
569 SessionStateAnimator::ANIMATION_DROP
,
570 SessionStateAnimator::ANIMATION_SPEED_MOVE_WINDOWS
,
572 animator_
->StartAnimationWithObserver(
573 SessionStateAnimator::LAUNCHER
,
574 SessionStateAnimator::ANIMATION_FADE_IN
,
575 SessionStateAnimator::ANIMATION_SPEED_MOVE_WINDOWS
,
577 AnimateBackgroundHidingIfNecessary(
578 SessionStateAnimator::ANIMATION_SPEED_MOVE_WINDOWS
, observer
);
582 void LockStateController::LockAnimationCancelled() {
583 can_cancel_lock_animation_
= false;
584 RestoreUnlockedProperties();
587 void LockStateController::PreLockAnimationFinished(bool request_lock
) {
588 VLOG(1) << "PreLockAnimationFinished";
589 can_cancel_lock_animation_
= false;
591 // Don't do anything (including starting the lock-fail timer) if the screen
592 // was already locked while the animation was going.
593 if (system_is_locked_
) {
594 DCHECK(!request_lock
) << "Got request to lock already-locked system "
595 << "at completion of pre-lock animation";
600 Shell::GetInstance()->metrics()->RecordUserMetricsAction(
601 shutdown_after_lock_
?
602 UMA_ACCEL_LOCK_SCREEN_POWER_BUTTON
:
603 UMA_ACCEL_LOCK_SCREEN_LOCK_BUTTON
);
604 delegate_
->RequestLockScreen();
607 base::TimeDelta timeout
=
608 base::TimeDelta::FromMilliseconds(kLockFailTimeoutMs
);
609 #if defined(OS_CHROMEOS)
610 // Increase lock timeout for slower hardware, see http://crbug.com/350628
611 const std::string board
= base::SysInfo::GetLsbReleaseBoard();
612 if (board
== "x86-mario" ||
613 StartsWithASCII(board
, "x86-alex", true /* case_sensitive */) ||
614 StartsWithASCII(board
, "x86-zgb", true /* case_sensitive */)) {
618 lock_fail_timer_
.Start(
619 FROM_HERE
, timeout
, this, &LockStateController::OnLockFailTimeout
);
622 void LockStateController::PostLockAnimationFinished() {
623 animating_lock_
= false;
624 VLOG(1) << "PostLockAnimationFinished";
625 FOR_EACH_OBSERVER(LockStateObserver
, observers_
,
626 OnLockStateEvent(LockStateObserver::EVENT_LOCK_ANIMATION_FINISHED
));
627 if (!lock_screen_displayed_callback_
.is_null()) {
628 lock_screen_displayed_callback_
.Run();
629 lock_screen_displayed_callback_
.Reset();
631 CHECK(!views::MenuController::GetActiveInstance());
632 if (shutdown_after_lock_
) {
633 shutdown_after_lock_
= false;
634 StartLockToShutdownTimer();
638 void LockStateController::UnlockAnimationAfterUIDestroyedFinished() {
639 RestoreUnlockedProperties();
642 void LockStateController::StoreUnlockedProperties() {
643 if (!unlocked_properties_
) {
644 unlocked_properties_
.reset(new UnlockedStateProperties());
645 unlocked_properties_
->background_is_hidden
= IsBackgroundHidden();
647 if (unlocked_properties_
->background_is_hidden
) {
648 // Hide background so that it can be animated later.
649 animator_
->StartAnimation(SessionStateAnimator::DESKTOP_BACKGROUND
,
650 SessionStateAnimator::ANIMATION_HIDE_IMMEDIATELY
,
651 SessionStateAnimator::ANIMATION_SPEED_IMMEDIATE
);
656 void LockStateController::RestoreUnlockedProperties() {
657 if (!unlocked_properties_
)
659 if (unlocked_properties_
->background_is_hidden
) {
661 // Restore background visibility.
662 animator_
->StartAnimation(SessionStateAnimator::DESKTOP_BACKGROUND
,
663 SessionStateAnimator::ANIMATION_FADE_IN
,
664 SessionStateAnimator::ANIMATION_SPEED_IMMEDIATE
);
666 unlocked_properties_
.reset();
669 void LockStateController::AnimateBackgroundAppearanceIfNecessary(
670 SessionStateAnimator::AnimationSpeed speed
,
671 ui::LayerAnimationObserver
* observer
) {
672 if (unlocked_properties_
.get() &&
673 unlocked_properties_
->background_is_hidden
) {
674 animator_
->StartAnimationWithObserver(
675 SessionStateAnimator::DESKTOP_BACKGROUND
,
676 SessionStateAnimator::ANIMATION_FADE_IN
,
682 void LockStateController::AnimateBackgroundHidingIfNecessary(
683 SessionStateAnimator::AnimationSpeed speed
,
684 ui::LayerAnimationObserver
* observer
) {
685 if (unlocked_properties_
.get() &&
686 unlocked_properties_
->background_is_hidden
) {
687 animator_
->StartAnimationWithObserver(
688 SessionStateAnimator::DESKTOP_BACKGROUND
,
689 SessionStateAnimator::ANIMATION_FADE_OUT
,