Upstream version 9.37.195.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/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"
26
27 #if defined(OS_CHROMEOS)
28 #include "base/sys_info.h"
29 #include "media/audio/sounds/sounds_manager.h"
30 #endif
31
32 #if defined(OS_CHROMEOS)
33 using media::SoundsManager;
34 #endif
35
36 namespace ash {
37
38 namespace {
39
40 #if defined(OS_CHROMEOS)
41 const int kMaxShutdownSoundDurationMs = 1500;
42 #endif
43
44 aura::Window* GetBackground() {
45   aura::Window* root_window = Shell::GetPrimaryRootWindow();
46   return Shell::GetContainer(root_window,
47                              kShellWindowId_DesktopBackgroundContainer);
48 }
49
50 bool IsBackgroundHidden() {
51   return !GetBackground()->IsVisible();
52 }
53
54 void ShowBackground() {
55   ui::ScopedLayerAnimationSettings settings(
56       GetBackground()->layer()->GetAnimator());
57   settings.SetTransitionDuration(base::TimeDelta());
58   GetBackground()->Show();
59 }
60
61 void HideBackground() {
62   ui::ScopedLayerAnimationSettings settings(
63       GetBackground()->layer()->GetAnimator());
64   settings.SetTransitionDuration(base::TimeDelta());
65   GetBackground()->Hide();
66 }
67
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 {
78  public:
79   explicit AnimationFinishedObserver(base::Closure &callback)
80       : callback_(callback),
81         sequences_attached_(0),
82         sequences_completed_(0),
83         paused_(false) {
84   }
85
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
89   // immediate.
90   void Pause() {
91     paused_ = true;
92   }
93
94   // Unpauses observer. It does a check and calls callback if conditions are
95   // met.
96   void Unpause() {
97     if (!paused_)
98       return;
99     paused_ = false;
100     if (sequences_completed_ == sequences_attached_) {
101       callback_.Run();
102       delete this;
103     }
104   }
105
106  private:
107   virtual ~AnimationFinishedObserver() {
108   }
109
110   // LayerAnimationObserver implementation
111   virtual void OnLayerAnimationEnded(
112       ui::LayerAnimationSequence* sequence) OVERRIDE {
113     sequences_completed_++;
114     if ((sequences_completed_ == sequences_attached_) && !paused_) {
115       callback_.Run();
116       delete this;
117     }
118   }
119
120   virtual void OnLayerAnimationAborted(
121       ui::LayerAnimationSequence* sequence) OVERRIDE {
122     sequences_completed_++;
123     if ((sequences_completed_ == sequences_attached_) && !paused_)
124       delete this;
125   }
126
127   virtual void OnLayerAnimationScheduled(
128       ui::LayerAnimationSequence* sequence) OVERRIDE {
129   }
130
131   virtual void OnAttachedToSequence(
132       ui::LayerAnimationSequence* sequence) OVERRIDE {
133     LayerAnimationObserver::OnAttachedToSequence(sequence);
134     sequences_attached_++;
135   }
136
137   // Callback to be called.
138   base::Closure callback_;
139
140   // Number of sequences this observer was attached to.
141   int sequences_attached_;
142
143   // Number of sequences either ended or aborted.
144   int sequences_completed_;
145
146   bool paused_;
147
148   DISALLOW_COPY_AND_ASSIGN(AnimationFinishedObserver);
149 };
150
151 }  // namespace
152
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;
158
159 LockStateController::TestApi::TestApi(LockStateController* controller)
160     : controller_(controller) {
161 }
162
163 LockStateController::TestApi::~TestApi() {
164 }
165
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);
176 }
177
178 LockStateController::~LockStateController() {
179   Shell::GetPrimaryRootWindow()->GetHost()->RemoveObserver(this);
180 }
181
182 void LockStateController::SetDelegate(LockStateControllerDelegate* delegate) {
183   delegate_.reset(delegate);
184 }
185
186 void LockStateController::AddObserver(LockStateObserver* observer) {
187   observers_.AddObserver(observer);
188 }
189
190 void LockStateController::RemoveObserver(LockStateObserver* observer) {
191   observers_.RemoveObserver(observer);
192 }
193
194 bool LockStateController::HasObserver(LockStateObserver* observer) {
195   return observers_.HasObserver(observer);
196 }
197
198 void LockStateController::StartLockAnimation(
199     bool shutdown_after_lock) {
200   if (animating_lock_)
201     return;
202   shutdown_after_lock_ = shutdown_after_lock;
203   can_cancel_lock_animation_ = true;
204
205   StartCancellablePreLockAnimation();
206 }
207
208 void LockStateController::StartShutdownAnimation() {
209   StartCancellableShutdownAnimation();
210 }
211
212 void LockStateController::StartLockAnimationAndLockImmediately() {
213   if (animating_lock_)
214     return;
215   StartImmediatePreLockAnimation(true /* request_lock_on_completion */);
216 }
217
218 bool LockStateController::LockRequested() {
219   return lock_fail_timer_.IsRunning();
220 }
221
222 bool LockStateController::ShutdownRequested() {
223   return shutting_down_;
224 }
225
226 bool LockStateController::CanCancelLockAnimation() {
227   return can_cancel_lock_animation_;
228 }
229
230 void LockStateController::CancelLockAnimation() {
231   if (!CanCancelLockAnimation())
232     return;
233   shutdown_after_lock_ = false;
234   animating_lock_ = false;
235   CancelPreLockAnimation();
236 }
237
238 bool LockStateController::CanCancelShutdownAnimation() {
239   return pre_shutdown_timer_.IsRunning() ||
240          shutdown_after_lock_ ||
241          lock_to_shutdown_timer_.IsRunning();
242 }
243
244 void LockStateController::CancelShutdownAnimation() {
245   if (!CanCancelShutdownAnimation())
246     return;
247   if (lock_to_shutdown_timer_.IsRunning()) {
248     lock_to_shutdown_timer_.Stop();
249     return;
250   }
251   if (shutdown_after_lock_) {
252     shutdown_after_lock_ = false;
253     return;
254   }
255
256   animator_->StartGlobalAnimation(
257       SessionStateAnimator::ANIMATION_UNDO_GRAYSCALE_BRIGHTNESS,
258       SessionStateAnimator::ANIMATION_SPEED_REVERT_SHUTDOWN);
259   pre_shutdown_timer_.Stop();
260 }
261
262 void LockStateController::OnStartingLock() {
263   if (shutting_down_ || system_is_locked_)
264     return;
265   if (animating_lock_)
266     return;
267   StartImmediatePreLockAnimation(false /* request_lock_on_completion */);
268 }
269
270 void LockStateController::RequestShutdown() {
271   if (shutting_down_)
272     return;
273
274   shutting_down_ = true;
275
276   Shell* shell = ash::Shell::GetInstance();
277   shell->cursor_manager()->HideCursor();
278   shell->cursor_manager()->LockCursor();
279
280   animator_->StartGlobalAnimation(
281       SessionStateAnimator::ANIMATION_GRAYSCALE_BRIGHTNESS,
282       SessionStateAnimator::ANIMATION_SPEED_SHUTDOWN);
283   StartRealShutdownTimer(true);
284 }
285
286 void LockStateController::OnLockScreenHide(
287   base::Callback<void(void)>& callback) {
288   StartUnlockAnimationBeforeUIDestroyed(callback);
289 }
290
291 void LockStateController::SetLockScreenDisplayedCallback(
292     const base::Closure& callback) {
293   lock_screen_displayed_callback_ = callback;
294 }
295
296 void LockStateController::OnHostCloseRequested(
297     const aura::WindowTreeHost* host) {
298   Shell::GetInstance()->delegate()->Exit();
299 }
300
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);
306 }
307
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);
320   }
321 }
322
323 void LockStateController::OnLockStateChanged(bool locked) {
324   VLOG(1) << "OnLockStateChanged " << locked;
325   if (shutting_down_ || (system_is_locked_ == locked))
326     return;
327
328   system_is_locked_ = locked;
329
330   if (locked) {
331     StartPostLockAnimation();
332     lock_fail_timer_.Stop();
333   } else {
334     StartUnlockAnimationAfterUIDestroyed();
335   }
336 }
337
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";
342 }
343
344 void LockStateController::StartLockToShutdownTimer() {
345   shutdown_after_lock_ = false;
346   lock_to_shutdown_timer_.Stop();
347   lock_to_shutdown_timer_.Start(
348       FROM_HERE,
349       base::TimeDelta::FromMilliseconds(kLockToShutdownTimeoutMs),
350       this, &LockStateController::OnLockToShutdownTimeout);
351 }
352
353 void LockStateController::OnLockToShutdownTimeout() {
354   DCHECK(system_is_locked_);
355   StartCancellableShutdownAnimation();
356 }
357
358 void LockStateController::StartPreShutdownAnimationTimer() {
359   pre_shutdown_timer_.Stop();
360   pre_shutdown_timer_.Start(
361       FROM_HERE,
362       animator_->GetDuration(SessionStateAnimator::ANIMATION_SPEED_SHUTDOWN),
363       this,
364       &LockStateController::OnPreShutdownAnimationTimeout);
365 }
366
367 void LockStateController::OnPreShutdownAnimationTimeout() {
368   VLOG(1) << "OnPreShutdownAnimationTimeout";
369   shutting_down_ = true;
370
371   Shell* shell = ash::Shell::GetInstance();
372   shell->cursor_manager()->HideCursor();
373
374   StartRealShutdownTimer(false);
375 }
376
377 void LockStateController::StartRealShutdownTimer(bool with_animation_time) {
378   base::TimeDelta duration =
379       base::TimeDelta::FromMilliseconds(kShutdownRequestDelayMs);
380   if (with_animation_time) {
381     duration +=
382         animator_->GetDuration(SessionStateAnimator::ANIMATION_SPEED_SHUTDOWN);
383   }
384
385 #if defined(OS_CHROMEOS)
386   const AccessibilityDelegate* const delegate =
387       Shell::GetInstance()->accessibility_delegate();
388   base::TimeDelta sound_duration = delegate->PlayShutdownSound();
389   sound_duration =
390       std::min(sound_duration,
391                base::TimeDelta::FromMilliseconds(kMaxShutdownSoundDurationMs));
392   duration = std::max(duration, sound_duration);
393 #endif
394
395   real_shutdown_timer_.Start(
396       FROM_HERE, duration, this, &LockStateController::OnRealShutdownTimeout);
397 }
398
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();
405     if (delegate) {
406       delegate->Exit();
407       return;
408     }
409   }
410 #endif
411   Shell::GetInstance()->metrics()->RecordUserMetricsAction(
412       UMA_ACCEL_SHUT_DOWN_POWER_BUTTON);
413   delegate_->RequestShutdown();
414 }
415
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();
420
421   animator_->StartGlobalAnimation(
422       SessionStateAnimator::ANIMATION_GRAYSCALE_BRIGHTNESS,
423       SessionStateAnimator::ANIMATION_SPEED_SHUTDOWN);
424   StartPreShutdownAnimationTimer();
425 }
426
427 void LockStateController::StartImmediatePreLockAnimation(
428     bool request_lock_on_completion) {
429   VLOG(1) << "StartImmediatePreLockAnimation " << request_lock_on_completion;
430   animating_lock_ = true;
431   StoreUnlockedProperties();
432
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);
439
440   observer->Pause();
441
442   animator_->StartAnimationWithObserver(
443       SessionStateAnimator::NON_LOCK_SCREEN_CONTAINERS,
444       SessionStateAnimator::ANIMATION_LIFT,
445       SessionStateAnimator::ANIMATION_SPEED_MOVE_WINDOWS,
446       observer);
447   animator_->StartAnimationWithObserver(
448       SessionStateAnimator::LAUNCHER,
449       SessionStateAnimator::ANIMATION_FADE_OUT,
450       SessionStateAnimator::ANIMATION_SPEED_MOVE_WINDOWS,
451       observer);
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);
458
459   observer->Unpause();
460
461   DispatchCancelMode();
462   FOR_EACH_OBSERVER(LockStateObserver, observers_,
463       OnLockStateEvent(LockStateObserver::EVENT_LOCK_ANIMATION_STARTED));
464 }
465
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);
476
477   observer->Pause();
478
479   animator_->StartAnimationWithObserver(
480       SessionStateAnimator::NON_LOCK_SCREEN_CONTAINERS,
481       SessionStateAnimator::ANIMATION_LIFT,
482       SessionStateAnimator::ANIMATION_SPEED_UNDOABLE,
483       observer);
484   animator_->StartAnimationWithObserver(
485       SessionStateAnimator::LAUNCHER,
486       SessionStateAnimator::ANIMATION_FADE_OUT,
487       SessionStateAnimator::ANIMATION_SPEED_UNDOABLE,
488       observer);
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);
495
496   DispatchCancelMode();
497   FOR_EACH_OBSERVER(LockStateObserver, observers_,
498       OnLockStateEvent(LockStateObserver::EVENT_PRELOCK_ANIMATION_STARTED));
499   observer->Unpause();
500 }
501
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);
509
510   observer->Pause();
511
512   animator_->StartAnimationWithObserver(
513       SessionStateAnimator::NON_LOCK_SCREEN_CONTAINERS,
514       SessionStateAnimator::ANIMATION_UNDO_LIFT,
515       SessionStateAnimator::ANIMATION_SPEED_UNDO_MOVE_WINDOWS,
516       observer);
517   animator_->StartAnimationWithObserver(
518       SessionStateAnimator::LAUNCHER,
519       SessionStateAnimator::ANIMATION_FADE_IN,
520       SessionStateAnimator::ANIMATION_SPEED_UNDO_MOVE_WINDOWS,
521       observer);
522   AnimateBackgroundHidingIfNecessary(
523       SessionStateAnimator::ANIMATION_SPEED_UNDO_MOVE_WINDOWS, observer);
524
525   observer->Unpause();
526 }
527
528 void LockStateController::StartPostLockAnimation() {
529   VLOG(1) << "StartPostLockAnimation";
530   base::Closure next_animation_starter =
531       base::Bind(&LockStateController::PostLockAnimationFinished,
532                  weak_ptr_factory_.GetWeakPtr());
533
534   AnimationFinishedObserver* observer =
535       new AnimationFinishedObserver(next_animation_starter);
536
537   observer->Pause();
538   animator_->StartAnimationWithObserver(
539       SessionStateAnimator::LOCK_SCREEN_CONTAINERS,
540       SessionStateAnimator::ANIMATION_RAISE_TO_SCREEN,
541       SessionStateAnimator::ANIMATION_SPEED_MOVE_WINDOWS,
542       observer);
543   observer->Unpause();
544 }
545
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,
553       callback);
554 }
555
556 void LockStateController::StartUnlockAnimationAfterUIDestroyed() {
557   VLOG(1) << "StartUnlockAnimationAfterUIDestroyed";
558   base::Closure next_animation_starter =
559       base::Bind(&LockStateController::UnlockAnimationAfterUIDestroyedFinished,
560                  weak_ptr_factory_.GetWeakPtr());
561
562   AnimationFinishedObserver* observer =
563       new AnimationFinishedObserver(next_animation_starter);
564
565   observer->Pause();
566
567   animator_->StartAnimationWithObserver(
568       SessionStateAnimator::NON_LOCK_SCREEN_CONTAINERS,
569       SessionStateAnimator::ANIMATION_DROP,
570       SessionStateAnimator::ANIMATION_SPEED_MOVE_WINDOWS,
571       observer);
572   animator_->StartAnimationWithObserver(
573       SessionStateAnimator::LAUNCHER,
574       SessionStateAnimator::ANIMATION_FADE_IN,
575       SessionStateAnimator::ANIMATION_SPEED_MOVE_WINDOWS,
576       observer);
577   AnimateBackgroundHidingIfNecessary(
578       SessionStateAnimator::ANIMATION_SPEED_MOVE_WINDOWS, observer);
579   observer->Unpause();
580 }
581
582 void LockStateController::LockAnimationCancelled() {
583   can_cancel_lock_animation_ = false;
584   RestoreUnlockedProperties();
585 }
586
587 void LockStateController::PreLockAnimationFinished(bool request_lock) {
588   VLOG(1) << "PreLockAnimationFinished";
589   can_cancel_lock_animation_ = false;
590
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";
596     return;
597   }
598
599   if (request_lock) {
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();
605   }
606
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 */)) {
615     timeout *= 2;
616   }
617 #endif
618   lock_fail_timer_.Start(
619       FROM_HERE, timeout, this, &LockStateController::OnLockFailTimeout);
620 }
621
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();
630   }
631   CHECK(!views::MenuController::GetActiveInstance());
632   if (shutdown_after_lock_) {
633     shutdown_after_lock_ = false;
634     StartLockToShutdownTimer();
635   }
636 }
637
638 void LockStateController::UnlockAnimationAfterUIDestroyedFinished() {
639   RestoreUnlockedProperties();
640 }
641
642 void LockStateController::StoreUnlockedProperties() {
643   if (!unlocked_properties_) {
644     unlocked_properties_.reset(new UnlockedStateProperties());
645     unlocked_properties_->background_is_hidden = IsBackgroundHidden();
646   }
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);
652     ShowBackground();
653   }
654 }
655
656 void LockStateController::RestoreUnlockedProperties() {
657   if (!unlocked_properties_)
658     return;
659   if (unlocked_properties_->background_is_hidden) {
660     HideBackground();
661     // Restore background visibility.
662     animator_->StartAnimation(SessionStateAnimator::DESKTOP_BACKGROUND,
663                               SessionStateAnimator::ANIMATION_FADE_IN,
664                               SessionStateAnimator::ANIMATION_SPEED_IMMEDIATE);
665   }
666   unlocked_properties_.reset();
667 }
668
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,
677         speed,
678         observer);
679   }
680 }
681
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,
690         speed,
691         observer);
692   }
693 }
694
695 }  // namespace ash