Home | History | Annotate | Download | only in wm
      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
    696