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