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