Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / ash / wm / lock_state_controller.cc
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.
4
5 #include "ash/wm/lock_state_controller.h"
6
7 #include <algorithm>
8
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/timer/timer.h"
20 #include "ui/aura/window_tree_host.h"
21 #include "ui/compositor/layer_animation_sequence.h"
22 #include "ui/compositor/scoped_layer_animation_settings.h"
23 #include "ui/views/controls/menu/menu_controller.h"
24 #include "ui/wm/core/compound_event_filter.h"
25
26 #if defined(OS_CHROMEOS)
27 #include "base/sys_info.h"
28 #include "media/audio/sounds/sounds_manager.h"
29 #endif
30
31 #if defined(OS_CHROMEOS)
32 using media::SoundsManager;
33 #endif
34
35 namespace ash {
36
37 namespace {
38
39 #if defined(OS_CHROMEOS)
40 const int kMaxShutdownSoundDurationMs = 1500;
41 #endif
42
43 aura::Window* GetBackground() {
44   aura::Window* root_window = Shell::GetPrimaryRootWindow();
45   return Shell::GetContainer(root_window,
46                              kShellWindowId_DesktopBackgroundContainer);
47 }
48
49 bool IsBackgroundHidden() {
50   return !GetBackground()->IsVisible();
51 }
52
53 void ShowBackground() {
54   ui::ScopedLayerAnimationSettings settings(
55       GetBackground()->layer()->GetAnimator());
56   settings.SetTransitionDuration(base::TimeDelta());
57   GetBackground()->Show();
58 }
59
60 void HideBackground() {
61   ui::ScopedLayerAnimationSettings settings(
62       GetBackground()->layer()->GetAnimator());
63   settings.SetTransitionDuration(base::TimeDelta());
64   GetBackground()->Hide();
65 }
66
67 // This observer is intended to use in cases when some action has to be taken
68 // once some animation successfully completes (i.e. it was not aborted).
69 // Observer will count a number of sequences it is attached to, and a number of
70 // finished sequences (either Ended or Aborted). Once these two numbers are
71 // equal, observer will delete itself, calling callback passed to constructor if
72 // there were no aborted animations.
73 // This way it can be either used to wait for some animation to be finished in
74 // multiple layers, to wait once a sequence of animations is finished in one
75 // layer or the mixture of both.
76 class AnimationFinishedObserver : public ui::LayerAnimationObserver {
77  public:
78   explicit AnimationFinishedObserver(base::Closure &callback)
79       : callback_(callback),
80         sequences_attached_(0),
81         sequences_completed_(0),
82         paused_(false) {
83   }
84
85   // Pauses observer: no checks will be made while paused. It can be used when
86   // a sequence has some immediate animations in the beginning, and for
87   // animations that can be tested with flag that makes all animations
88   // immediate.
89   void Pause() {
90     paused_ = true;
91   }
92
93   // Unpauses observer. It does a check and calls callback if conditions are
94   // met.
95   void Unpause() {
96     if (!paused_)
97       return;
98     paused_ = false;
99     if (sequences_completed_ == sequences_attached_) {
100       callback_.Run();
101       delete this;
102     }
103   }
104
105  private:
106   virtual ~AnimationFinishedObserver() {
107   }
108
109   // LayerAnimationObserver implementation
110   virtual void OnLayerAnimationEnded(
111       ui::LayerAnimationSequence* sequence) OVERRIDE {
112     sequences_completed_++;
113     if ((sequences_completed_ == sequences_attached_) && !paused_) {
114       callback_.Run();
115       delete this;
116     }
117   }
118
119   virtual void OnLayerAnimationAborted(
120       ui::LayerAnimationSequence* sequence) OVERRIDE {
121     sequences_completed_++;
122     if ((sequences_completed_ == sequences_attached_) && !paused_)
123       delete this;
124   }
125
126   virtual void OnLayerAnimationScheduled(
127       ui::LayerAnimationSequence* sequence) OVERRIDE {
128   }
129
130   virtual void OnAttachedToSequence(
131       ui::LayerAnimationSequence* sequence) OVERRIDE {
132     LayerAnimationObserver::OnAttachedToSequence(sequence);
133     sequences_attached_++;
134   }
135
136   // Callback to be called.
137   base::Closure callback_;
138
139   // Number of sequences this observer was attached to.
140   int sequences_attached_;
141
142   // Number of sequences either ended or aborted.
143   int sequences_completed_;
144
145   bool paused_;
146
147   DISALLOW_COPY_AND_ASSIGN(AnimationFinishedObserver);
148 };
149
150 }  // namespace
151
152 const int LockStateController::kLockTimeoutMs = 400;
153 const int LockStateController::kShutdownTimeoutMs = 400;
154 const int LockStateController::kLockFailTimeoutMs = 8000;
155 const int LockStateController::kLockToShutdownTimeoutMs = 150;
156 const int LockStateController::kShutdownRequestDelayMs = 50;
157
158 LockStateController::TestApi::TestApi(LockStateController* controller)
159     : controller_(controller) {
160 }
161
162 LockStateController::TestApi::~TestApi() {
163 }
164
165 LockStateController::LockStateController()
166     : animator_(new SessionStateAnimator()),
167       login_status_(user::LOGGED_IN_NONE),
168       system_is_locked_(false),
169       shutting_down_(false),
170       shutdown_after_lock_(false),
171       animating_lock_(false),
172       can_cancel_lock_animation_(false),
173       weak_ptr_factory_(this) {
174   Shell::GetPrimaryRootWindow()->GetHost()->AddObserver(this);
175 }
176
177 LockStateController::~LockStateController() {
178   Shell::GetPrimaryRootWindow()->GetHost()->RemoveObserver(this);
179 }
180
181 void LockStateController::SetDelegate(LockStateControllerDelegate* delegate) {
182   delegate_.reset(delegate);
183 }
184
185 void LockStateController::AddObserver(LockStateObserver* observer) {
186   observers_.AddObserver(observer);
187 }
188
189 void LockStateController::RemoveObserver(LockStateObserver* observer) {
190   observers_.RemoveObserver(observer);
191 }
192
193 bool LockStateController::HasObserver(LockStateObserver* observer) {
194   return observers_.HasObserver(observer);
195 }
196
197 void LockStateController::StartLockAnimation(
198     bool shutdown_after_lock) {
199   if (animating_lock_)
200     return;
201   shutdown_after_lock_ = shutdown_after_lock;
202   can_cancel_lock_animation_ = true;
203
204   StartCancellablePreLockAnimation();
205 }
206
207 void LockStateController::StartShutdownAnimation() {
208   StartCancellableShutdownAnimation();
209 }
210
211 void LockStateController::StartLockAnimationAndLockImmediately() {
212   if (animating_lock_)
213     return;
214   StartImmediatePreLockAnimation(true /* request_lock_on_completion */);
215 }
216
217 bool LockStateController::LockRequested() {
218   return lock_fail_timer_.IsRunning();
219 }
220
221 bool LockStateController::ShutdownRequested() {
222   return shutting_down_;
223 }
224
225 bool LockStateController::CanCancelLockAnimation() {
226   return can_cancel_lock_animation_;
227 }
228
229 void LockStateController::CancelLockAnimation() {
230   if (!CanCancelLockAnimation())
231     return;
232   shutdown_after_lock_ = false;
233   animating_lock_ = false;
234   CancelPreLockAnimation();
235 }
236
237 bool LockStateController::CanCancelShutdownAnimation() {
238   return pre_shutdown_timer_.IsRunning() ||
239          shutdown_after_lock_ ||
240          lock_to_shutdown_timer_.IsRunning();
241 }
242
243 void LockStateController::CancelShutdownAnimation() {
244   if (!CanCancelShutdownAnimation())
245     return;
246   if (lock_to_shutdown_timer_.IsRunning()) {
247     lock_to_shutdown_timer_.Stop();
248     return;
249   }
250   if (shutdown_after_lock_) {
251     shutdown_after_lock_ = false;
252     return;
253   }
254
255   animator_->StartGlobalAnimation(
256       SessionStateAnimator::ANIMATION_UNDO_GRAYSCALE_BRIGHTNESS,
257       SessionStateAnimator::ANIMATION_SPEED_REVERT_SHUTDOWN);
258   pre_shutdown_timer_.Stop();
259 }
260
261 void LockStateController::OnStartingLock() {
262   if (shutting_down_ || system_is_locked_)
263     return;
264   if (animating_lock_)
265     return;
266   StartImmediatePreLockAnimation(false /* request_lock_on_completion */);
267 }
268
269 void LockStateController::RequestShutdown() {
270   if (shutting_down_)
271     return;
272
273   shutting_down_ = true;
274
275   Shell* shell = ash::Shell::GetInstance();
276   shell->cursor_manager()->HideCursor();
277   shell->cursor_manager()->LockCursor();
278
279   animator_->StartGlobalAnimation(
280       SessionStateAnimator::ANIMATION_GRAYSCALE_BRIGHTNESS,
281       SessionStateAnimator::ANIMATION_SPEED_SHUTDOWN);
282   StartRealShutdownTimer(true);
283 }
284
285 void LockStateController::OnLockScreenHide(
286   base::Callback<void(void)>& callback) {
287   StartUnlockAnimationBeforeUIDestroyed(callback);
288 }
289
290 void LockStateController::SetLockScreenDisplayedCallback(
291     const base::Closure& callback) {
292   lock_screen_displayed_callback_ = callback;
293 }
294
295 void LockStateController::OnHostCloseRequested(
296     const aura::WindowTreeHost* host) {
297   Shell::GetInstance()->delegate()->Exit();
298 }
299
300 void LockStateController::OnLoginStateChanged(
301     user::LoginStatus status) {
302   if (status != user::LOGGED_IN_LOCKED)
303     login_status_ = status;
304   system_is_locked_ = (status == user::LOGGED_IN_LOCKED);
305 }
306
307 void LockStateController::OnAppTerminating() {
308   // If we hear that Chrome is exiting but didn't request it ourselves, all we
309   // can really hope for is that we'll have time to clear the screen.
310   // This is also the case when the user signs off.
311   if (!shutting_down_) {
312     shutting_down_ = true;
313     Shell* shell = ash::Shell::GetInstance();
314     shell->cursor_manager()->HideCursor();
315     shell->cursor_manager()->LockCursor();
316     animator_->StartAnimation(SessionStateAnimator::kAllContainersMask,
317                               SessionStateAnimator::ANIMATION_HIDE_IMMEDIATELY,
318                               SessionStateAnimator::ANIMATION_SPEED_IMMEDIATE);
319   }
320 }
321
322 void LockStateController::OnLockStateChanged(bool locked) {
323   VLOG(1) << "OnLockStateChanged " << locked;
324   if (shutting_down_ || (system_is_locked_ == locked))
325     return;
326
327   system_is_locked_ = locked;
328
329   if (locked) {
330     StartPostLockAnimation();
331     lock_fail_timer_.Stop();
332   } else {
333     StartUnlockAnimationAfterUIDestroyed();
334   }
335 }
336
337 void LockStateController::OnLockFailTimeout() {
338   DCHECK(!system_is_locked_);
339   CHECK(false) << "We can not be sure about the lock state. Crash and let the "
340                << "SessionManager end the session";
341 }
342
343 void LockStateController::StartLockToShutdownTimer() {
344   shutdown_after_lock_ = false;
345   lock_to_shutdown_timer_.Stop();
346   lock_to_shutdown_timer_.Start(
347       FROM_HERE,
348       base::TimeDelta::FromMilliseconds(kLockToShutdownTimeoutMs),
349       this, &LockStateController::OnLockToShutdownTimeout);
350 }
351
352 void LockStateController::OnLockToShutdownTimeout() {
353   DCHECK(system_is_locked_);
354   StartCancellableShutdownAnimation();
355 }
356
357 void LockStateController::StartPreShutdownAnimationTimer() {
358   pre_shutdown_timer_.Stop();
359   pre_shutdown_timer_.Start(
360       FROM_HERE,
361       animator_->GetDuration(SessionStateAnimator::ANIMATION_SPEED_SHUTDOWN),
362       this,
363       &LockStateController::OnPreShutdownAnimationTimeout);
364 }
365
366 void LockStateController::OnPreShutdownAnimationTimeout() {
367   VLOG(1) << "OnPreShutdownAnimationTimeout";
368   shutting_down_ = true;
369
370   Shell* shell = ash::Shell::GetInstance();
371   shell->cursor_manager()->HideCursor();
372
373   StartRealShutdownTimer(false);
374 }
375
376 void LockStateController::StartRealShutdownTimer(bool with_animation_time) {
377   base::TimeDelta duration =
378       base::TimeDelta::FromMilliseconds(kShutdownRequestDelayMs);
379   if (with_animation_time) {
380     duration +=
381         animator_->GetDuration(SessionStateAnimator::ANIMATION_SPEED_SHUTDOWN);
382   }
383
384 #if defined(OS_CHROMEOS)
385   const AccessibilityDelegate* const delegate =
386       Shell::GetInstance()->accessibility_delegate();
387   base::TimeDelta sound_duration = delegate->PlayShutdownSound();
388   sound_duration =
389       std::min(sound_duration,
390                base::TimeDelta::FromMilliseconds(kMaxShutdownSoundDurationMs));
391   duration = std::max(duration, sound_duration);
392 #endif
393
394   real_shutdown_timer_.Start(
395       FROM_HERE, duration, this, &LockStateController::OnRealShutdownTimeout);
396 }
397
398 void LockStateController::OnRealShutdownTimeout() {
399   VLOG(1) << "OnRealShutdownTimeout";
400   DCHECK(shutting_down_);
401 #if defined(OS_CHROMEOS)
402   if (!base::SysInfo::IsRunningOnChromeOS()) {
403     ShellDelegate* delegate = Shell::GetInstance()->delegate();
404     if (delegate) {
405       delegate->Exit();
406       return;
407     }
408   }
409 #endif
410   Shell::GetInstance()->metrics()->RecordUserMetricsAction(
411       UMA_ACCEL_SHUT_DOWN_POWER_BUTTON);
412   delegate_->RequestShutdown();
413 }
414
415 void LockStateController::StartCancellableShutdownAnimation() {
416   Shell* shell = ash::Shell::GetInstance();
417   // Hide cursor, but let it reappear if the mouse moves.
418   shell->cursor_manager()->HideCursor();
419
420   animator_->StartGlobalAnimation(
421       SessionStateAnimator::ANIMATION_GRAYSCALE_BRIGHTNESS,
422       SessionStateAnimator::ANIMATION_SPEED_SHUTDOWN);
423   StartPreShutdownAnimationTimer();
424 }
425
426 void LockStateController::StartImmediatePreLockAnimation(
427     bool request_lock_on_completion) {
428   VLOG(1) << "StartImmediatePreLockAnimation " << request_lock_on_completion;
429   animating_lock_ = true;
430   StoreUnlockedProperties();
431
432   base::Closure next_animation_starter =
433       base::Bind(&LockStateController::PreLockAnimationFinished,
434                  weak_ptr_factory_.GetWeakPtr(),
435                  request_lock_on_completion);
436   AnimationFinishedObserver* observer =
437       new AnimationFinishedObserver(next_animation_starter);
438
439   observer->Pause();
440
441   animator_->StartAnimationWithObserver(
442       SessionStateAnimator::NON_LOCK_SCREEN_CONTAINERS,
443       SessionStateAnimator::ANIMATION_LIFT,
444       SessionStateAnimator::ANIMATION_SPEED_MOVE_WINDOWS,
445       observer);
446   animator_->StartAnimationWithObserver(
447       SessionStateAnimator::LAUNCHER,
448       SessionStateAnimator::ANIMATION_FADE_OUT,
449       SessionStateAnimator::ANIMATION_SPEED_MOVE_WINDOWS,
450       observer);
451   // Hide the screen locker containers so we can raise them later.
452   animator_->StartAnimation(SessionStateAnimator::LOCK_SCREEN_CONTAINERS,
453                             SessionStateAnimator::ANIMATION_HIDE_IMMEDIATELY,
454                             SessionStateAnimator::ANIMATION_SPEED_IMMEDIATE);
455   AnimateBackgroundAppearanceIfNecessary(
456       SessionStateAnimator::ANIMATION_SPEED_MOVE_WINDOWS, observer);
457
458   observer->Unpause();
459
460   DispatchCancelMode();
461   FOR_EACH_OBSERVER(LockStateObserver, observers_,
462       OnLockStateEvent(LockStateObserver::EVENT_LOCK_ANIMATION_STARTED));
463 }
464
465 void LockStateController::StartCancellablePreLockAnimation() {
466   animating_lock_ = true;
467   StoreUnlockedProperties();
468   VLOG(1) << "StartCancellablePreLockAnimation";
469   base::Closure next_animation_starter =
470       base::Bind(&LockStateController::PreLockAnimationFinished,
471                  weak_ptr_factory_.GetWeakPtr(),
472                  true /* request_lock */);
473   AnimationFinishedObserver* observer =
474       new AnimationFinishedObserver(next_animation_starter);
475
476   observer->Pause();
477
478   animator_->StartAnimationWithObserver(
479       SessionStateAnimator::NON_LOCK_SCREEN_CONTAINERS,
480       SessionStateAnimator::ANIMATION_LIFT,
481       SessionStateAnimator::ANIMATION_SPEED_UNDOABLE,
482       observer);
483   animator_->StartAnimationWithObserver(
484       SessionStateAnimator::LAUNCHER,
485       SessionStateAnimator::ANIMATION_FADE_OUT,
486       SessionStateAnimator::ANIMATION_SPEED_UNDOABLE,
487       observer);
488   // Hide the screen locker containers so we can raise them later.
489   animator_->StartAnimation(SessionStateAnimator::LOCK_SCREEN_CONTAINERS,
490                             SessionStateAnimator::ANIMATION_HIDE_IMMEDIATELY,
491                             SessionStateAnimator::ANIMATION_SPEED_IMMEDIATE);
492   AnimateBackgroundAppearanceIfNecessary(
493       SessionStateAnimator::ANIMATION_SPEED_UNDOABLE, observer);
494
495   DispatchCancelMode();
496   FOR_EACH_OBSERVER(LockStateObserver, observers_,
497       OnLockStateEvent(LockStateObserver::EVENT_PRELOCK_ANIMATION_STARTED));
498   observer->Unpause();
499 }
500
501 void LockStateController::CancelPreLockAnimation() {
502   VLOG(1) << "CancelPreLockAnimation";
503   base::Closure next_animation_starter =
504       base::Bind(&LockStateController::LockAnimationCancelled,
505                  weak_ptr_factory_.GetWeakPtr());
506   AnimationFinishedObserver* observer =
507       new AnimationFinishedObserver(next_animation_starter);
508
509   observer->Pause();
510
511   animator_->StartAnimationWithObserver(
512       SessionStateAnimator::NON_LOCK_SCREEN_CONTAINERS,
513       SessionStateAnimator::ANIMATION_UNDO_LIFT,
514       SessionStateAnimator::ANIMATION_SPEED_UNDO_MOVE_WINDOWS,
515       observer);
516   animator_->StartAnimationWithObserver(
517       SessionStateAnimator::LAUNCHER,
518       SessionStateAnimator::ANIMATION_FADE_IN,
519       SessionStateAnimator::ANIMATION_SPEED_UNDO_MOVE_WINDOWS,
520       observer);
521   AnimateBackgroundHidingIfNecessary(
522       SessionStateAnimator::ANIMATION_SPEED_UNDO_MOVE_WINDOWS, observer);
523
524   observer->Unpause();
525 }
526
527 void LockStateController::StartPostLockAnimation() {
528   VLOG(1) << "StartPostLockAnimation";
529   base::Closure next_animation_starter =
530       base::Bind(&LockStateController::PostLockAnimationFinished,
531                  weak_ptr_factory_.GetWeakPtr());
532
533   AnimationFinishedObserver* observer =
534       new AnimationFinishedObserver(next_animation_starter);
535
536   observer->Pause();
537   animator_->StartAnimationWithObserver(
538       SessionStateAnimator::LOCK_SCREEN_CONTAINERS,
539       SessionStateAnimator::ANIMATION_RAISE_TO_SCREEN,
540       SessionStateAnimator::ANIMATION_SPEED_MOVE_WINDOWS,
541       observer);
542   observer->Unpause();
543 }
544
545 void LockStateController::StartUnlockAnimationBeforeUIDestroyed(
546     base::Closure& callback) {
547   VLOG(1) << "StartUnlockAnimationBeforeUIDestroyed";
548   animator_->StartAnimationWithCallback(
549       SessionStateAnimator::LOCK_SCREEN_CONTAINERS,
550       SessionStateAnimator::ANIMATION_LIFT,
551       SessionStateAnimator::ANIMATION_SPEED_MOVE_WINDOWS,
552       callback);
553 }
554
555 void LockStateController::StartUnlockAnimationAfterUIDestroyed() {
556   VLOG(1) << "StartUnlockAnimationAfterUIDestroyed";
557   base::Closure next_animation_starter =
558       base::Bind(&LockStateController::UnlockAnimationAfterUIDestroyedFinished,
559                  weak_ptr_factory_.GetWeakPtr());
560
561   AnimationFinishedObserver* observer =
562       new AnimationFinishedObserver(next_animation_starter);
563
564   observer->Pause();
565
566   animator_->StartAnimationWithObserver(
567       SessionStateAnimator::NON_LOCK_SCREEN_CONTAINERS,
568       SessionStateAnimator::ANIMATION_DROP,
569       SessionStateAnimator::ANIMATION_SPEED_MOVE_WINDOWS,
570       observer);
571   animator_->StartAnimationWithObserver(
572       SessionStateAnimator::LAUNCHER,
573       SessionStateAnimator::ANIMATION_FADE_IN,
574       SessionStateAnimator::ANIMATION_SPEED_MOVE_WINDOWS,
575       observer);
576   AnimateBackgroundHidingIfNecessary(
577       SessionStateAnimator::ANIMATION_SPEED_MOVE_WINDOWS, observer);
578   observer->Unpause();
579 }
580
581 void LockStateController::LockAnimationCancelled() {
582   can_cancel_lock_animation_ = false;
583   RestoreUnlockedProperties();
584 }
585
586 void LockStateController::PreLockAnimationFinished(bool request_lock) {
587   can_cancel_lock_animation_ = false;
588   VLOG(1) << "PreLockAnimationFinished";
589   if (request_lock) {
590     Shell::GetInstance()->metrics()->RecordUserMetricsAction(
591         shutdown_after_lock_ ?
592         UMA_ACCEL_LOCK_SCREEN_POWER_BUTTON :
593         UMA_ACCEL_LOCK_SCREEN_LOCK_BUTTON);
594     delegate_->RequestLockScreen();
595   }
596
597   int lock_timeout = kLockFailTimeoutMs;
598
599 #if defined(OS_CHROMEOS)
600   std::string board = base::SysInfo::GetLsbReleaseBoard();
601
602   // Increase lock timeout for slower hardware, see http://crbug.com/350628
603   if (board == "x86-mario" ||
604       board.substr(0, 8) == "x86-alex" ||
605       board.substr(0, 7) == "x86-zgb") {
606     lock_timeout *= 2;
607   }
608 #endif
609
610   lock_fail_timer_.Start(
611       FROM_HERE,
612       base::TimeDelta::FromMilliseconds(lock_timeout),
613       this,
614       &LockStateController::OnLockFailTimeout);
615 }
616
617 void LockStateController::PostLockAnimationFinished() {
618   animating_lock_ = false;
619   VLOG(1) << "PostLockAnimationFinished";
620   FOR_EACH_OBSERVER(LockStateObserver, observers_,
621       OnLockStateEvent(LockStateObserver::EVENT_LOCK_ANIMATION_FINISHED));
622   if (!lock_screen_displayed_callback_.is_null()) {
623     lock_screen_displayed_callback_.Run();
624     lock_screen_displayed_callback_.Reset();
625   }
626   CHECK(!views::MenuController::GetActiveInstance());
627   if (shutdown_after_lock_) {
628     shutdown_after_lock_ = false;
629     StartLockToShutdownTimer();
630   }
631 }
632
633 void LockStateController::UnlockAnimationAfterUIDestroyedFinished() {
634   RestoreUnlockedProperties();
635 }
636
637 void LockStateController::StoreUnlockedProperties() {
638   if (!unlocked_properties_) {
639     unlocked_properties_.reset(new UnlockedStateProperties());
640     unlocked_properties_->background_is_hidden = IsBackgroundHidden();
641   }
642   if (unlocked_properties_->background_is_hidden) {
643     // Hide background so that it can be animated later.
644     animator_->StartAnimation(SessionStateAnimator::DESKTOP_BACKGROUND,
645                               SessionStateAnimator::ANIMATION_HIDE_IMMEDIATELY,
646                               SessionStateAnimator::ANIMATION_SPEED_IMMEDIATE);
647     ShowBackground();
648   }
649 }
650
651 void LockStateController::RestoreUnlockedProperties() {
652   if (!unlocked_properties_)
653     return;
654   if (unlocked_properties_->background_is_hidden) {
655     HideBackground();
656     // Restore background visibility.
657     animator_->StartAnimation(SessionStateAnimator::DESKTOP_BACKGROUND,
658                               SessionStateAnimator::ANIMATION_FADE_IN,
659                               SessionStateAnimator::ANIMATION_SPEED_IMMEDIATE);
660   }
661   unlocked_properties_.reset();
662 }
663
664 void LockStateController::AnimateBackgroundAppearanceIfNecessary(
665     SessionStateAnimator::AnimationSpeed speed,
666     ui::LayerAnimationObserver* observer) {
667   if (unlocked_properties_.get() &&
668       unlocked_properties_->background_is_hidden) {
669     animator_->StartAnimationWithObserver(
670         SessionStateAnimator::DESKTOP_BACKGROUND,
671         SessionStateAnimator::ANIMATION_FADE_IN,
672         speed,
673         observer);
674   }
675 }
676
677 void LockStateController::AnimateBackgroundHidingIfNecessary(
678     SessionStateAnimator::AnimationSpeed speed,
679     ui::LayerAnimationObserver* observer) {
680   if (unlocked_properties_.get() &&
681       unlocked_properties_->background_is_hidden) {
682     animator_->StartAnimationWithObserver(
683         SessionStateAnimator::DESKTOP_BACKGROUND,
684         SessionStateAnimator::ANIMATION_FADE_OUT,
685         speed,
686         observer);
687   }
688 }
689
690 }  // namespace ash