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