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.
5 #include "ash/wm/lock_state_controller.h"
9 #include "ash/accessibility_delegate.h"
10 #include "ash/ash_switches.h"
11 #include "ash/cancel_mode.h"
12 #include "ash/shell.h"
13 #include "ash/shell_delegate.h"
14 #include "ash/shell_window_ids.h"
15 #include "ash/wm/session_state_animator.h"
16 #include "base/bind_helpers.h"
17 #include "base/command_line.h"
18 #include "base/timer/timer.h"
19 #include "ui/aura/root_window.h"
20 #include "ui/compositor/layer_animation_sequence.h"
21 #include "ui/compositor/scoped_layer_animation_settings.h"
22 #include "ui/views/corewm/compound_event_filter.h"
24 #if defined(OS_CHROMEOS)
25 #include "base/sys_info.h"
26 #include "media/audio/sounds/sounds_manager.h"
29 #if defined(OS_CHROMEOS)
30 using media::SoundsManager;
37 const int kMaxShutdownSoundDurationMs = 1500;
39 aura::Window* GetBackground() {
40 aura::Window* root_window = Shell::GetPrimaryRootWindow();
41 return Shell::GetContainer(root_window,
42 internal::kShellWindowId_DesktopBackgroundContainer);
45 bool IsBackgroundHidden() {
46 return !GetBackground()->IsVisible();
49 void ShowBackground() {
50 ui::ScopedLayerAnimationSettings settings(
51 GetBackground()->layer()->GetAnimator());
52 settings.SetTransitionDuration(base::TimeDelta());
53 GetBackground()->Show();
56 void HideBackground() {
57 ui::ScopedLayerAnimationSettings settings(
58 GetBackground()->layer()->GetAnimator());
59 settings.SetTransitionDuration(base::TimeDelta());
60 GetBackground()->Hide();
63 // This observer is intended to use in cases when some action has to be taken
64 // once some animation successfully completes (i.e. it was not aborted).
65 // Observer will count a number of sequences it is attached to, and a number of
66 // finished sequences (either Ended or Aborted). Once these two numbers are
67 // equal, observer will delete itself, calling callback passed to constructor if
68 // there were no aborted animations.
69 // This way it can be either used to wait for some animation to be finished in
70 // multiple layers, to wait once a sequence of animations is finished in one
71 // layer or the mixture of both.
72 class AnimationFinishedObserver : public ui::LayerAnimationObserver {
74 explicit AnimationFinishedObserver(base::Closure &callback)
75 : callback_(callback),
76 sequences_attached_(0),
77 sequences_completed_(0),
81 // Pauses observer: no checks will be made while paused. It can be used when
82 // a sequence has some immediate animations in the beginning, and for
83 // animations that can be tested with flag that makes all animations
89 // Unpauses observer. It does a check and calls callback if conditions are
95 if (sequences_completed_ == sequences_attached_) {
102 virtual ~AnimationFinishedObserver() {
105 // LayerAnimationObserver implementation
106 virtual void OnLayerAnimationEnded(
107 ui::LayerAnimationSequence* sequence) OVERRIDE {
108 sequences_completed_++;
109 if ((sequences_completed_ == sequences_attached_) && !paused_) {
115 virtual void OnLayerAnimationAborted(
116 ui::LayerAnimationSequence* sequence) OVERRIDE {
117 sequences_completed_++;
118 if ((sequences_completed_ == sequences_attached_) && !paused_)
122 virtual void OnLayerAnimationScheduled(
123 ui::LayerAnimationSequence* sequence) OVERRIDE {
126 virtual void OnAttachedToSequence(
127 ui::LayerAnimationSequence* sequence) OVERRIDE {
128 LayerAnimationObserver::OnAttachedToSequence(sequence);
129 sequences_attached_++;
132 // Callback to be called.
133 base::Closure callback_;
135 // Number of sequences this observer was attached to.
136 int sequences_attached_;
138 // Number of sequences either ended or aborted.
139 int sequences_completed_;
143 DISALLOW_COPY_AND_ASSIGN(AnimationFinishedObserver);
148 const int LockStateController::kLockTimeoutMs = 400;
149 const int LockStateController::kShutdownTimeoutMs = 400;
150 const int LockStateController::kLockFailTimeoutMs = 8000;
151 const int LockStateController::kLockToShutdownTimeoutMs = 150;
152 const int LockStateController::kShutdownRequestDelayMs = 50;
154 LockStateController::TestApi::TestApi(LockStateController* controller)
155 : controller_(controller) {
158 LockStateController::TestApi::~TestApi() {
161 LockStateController::LockStateController()
162 : animator_(new internal::SessionStateAnimator()),
163 login_status_(user::LOGGED_IN_NONE),
164 system_is_locked_(false),
165 shutting_down_(false),
166 shutdown_after_lock_(false),
167 animating_lock_(false),
168 can_cancel_lock_animation_(false) {
169 Shell::GetPrimaryRootWindow()->GetDispatcher()->AddRootWindowObserver(this);
172 LockStateController::~LockStateController() {
173 Shell::GetPrimaryRootWindow()->GetDispatcher()->RemoveRootWindowObserver(
177 void LockStateController::SetDelegate(LockStateControllerDelegate* delegate) {
178 delegate_.reset(delegate);
181 void LockStateController::AddObserver(LockStateObserver* observer) {
182 observers_.AddObserver(observer);
185 void LockStateController::RemoveObserver(LockStateObserver* observer) {
186 observers_.RemoveObserver(observer);
189 bool LockStateController::HasObserver(LockStateObserver* observer) {
190 return observers_.HasObserver(observer);
193 void LockStateController::StartLockAnimation(
194 bool shutdown_after_lock) {
197 shutdown_after_lock_ = shutdown_after_lock;
198 can_cancel_lock_animation_ = true;
200 StartCancellablePreLockAnimation();
203 void LockStateController::StartShutdownAnimation() {
204 StartCancellableShutdownAnimation();
207 void LockStateController::StartLockAnimationAndLockImmediately() {
210 StartImmediatePreLockAnimation(true /* request_lock_on_completion */);
213 bool LockStateController::LockRequested() {
214 return lock_fail_timer_.IsRunning();
217 bool LockStateController::ShutdownRequested() {
218 return shutting_down_;
221 bool LockStateController::CanCancelLockAnimation() {
222 return can_cancel_lock_animation_;
225 void LockStateController::CancelLockAnimation() {
226 if (!CanCancelLockAnimation())
228 shutdown_after_lock_ = false;
229 animating_lock_ = false;
230 CancelPreLockAnimation();
233 bool LockStateController::CanCancelShutdownAnimation() {
234 return pre_shutdown_timer_.IsRunning() ||
235 shutdown_after_lock_ ||
236 lock_to_shutdown_timer_.IsRunning();
239 void LockStateController::CancelShutdownAnimation() {
240 if (!CanCancelShutdownAnimation())
242 if (lock_to_shutdown_timer_.IsRunning()) {
243 lock_to_shutdown_timer_.Stop();
246 if (shutdown_after_lock_) {
247 shutdown_after_lock_ = false;
251 animator_->StartGlobalAnimation(
252 internal::SessionStateAnimator::ANIMATION_UNDO_GRAYSCALE_BRIGHTNESS,
253 internal::SessionStateAnimator::ANIMATION_SPEED_REVERT_SHUTDOWN);
254 pre_shutdown_timer_.Stop();
257 void LockStateController::OnStartingLock() {
258 if (shutting_down_ || system_is_locked_)
262 StartImmediatePreLockAnimation(false /* request_lock_on_completion */);
265 void LockStateController::RequestShutdown() {
269 shutting_down_ = true;
271 Shell* shell = ash::Shell::GetInstance();
272 shell->env_filter()->set_cursor_hidden_by_filter(false);
273 shell->cursor_manager()->HideCursor();
275 animator_->StartGlobalAnimation(
276 internal::SessionStateAnimator::ANIMATION_GRAYSCALE_BRIGHTNESS,
277 internal::SessionStateAnimator::ANIMATION_SPEED_SHUTDOWN);
278 StartRealShutdownTimer(true);
281 void LockStateController::OnLockScreenHide(
282 base::Callback<void(void)>& callback) {
283 StartUnlockAnimationBeforeUIDestroyed(callback);
286 void LockStateController::SetLockScreenDisplayedCallback(
287 const base::Closure& callback) {
288 lock_screen_displayed_callback_ = callback;
291 void LockStateController::OnRootWindowHostCloseRequested(
292 const aura::RootWindow*) {
293 Shell::GetInstance()->delegate()->Exit();
296 void LockStateController::OnLoginStateChanged(
297 user::LoginStatus status) {
298 if (status != user::LOGGED_IN_LOCKED)
299 login_status_ = status;
300 system_is_locked_ = (status == user::LOGGED_IN_LOCKED);
303 void LockStateController::OnAppTerminating() {
304 // If we hear that Chrome is exiting but didn't request it ourselves, all we
305 // can really hope for is that we'll have time to clear the screen.
306 // This is also the case when the user signs off.
307 if (!shutting_down_) {
308 shutting_down_ = true;
309 Shell* shell = ash::Shell::GetInstance();
310 shell->env_filter()->set_cursor_hidden_by_filter(false);
311 shell->cursor_manager()->HideCursor();
312 animator_->StartAnimation(
313 internal::SessionStateAnimator::kAllContainersMask,
314 internal::SessionStateAnimator::ANIMATION_HIDE_IMMEDIATELY,
315 internal::SessionStateAnimator::ANIMATION_SPEED_IMMEDIATE);
319 void LockStateController::OnLockStateChanged(bool locked) {
320 if (shutting_down_ || (system_is_locked_ == locked))
323 system_is_locked_ = locked;
326 StartPostLockAnimation();
327 lock_fail_timer_.Stop();
329 StartUnlockAnimationAfterUIDestroyed();
333 void LockStateController::OnLockFailTimeout() {
334 DCHECK(!system_is_locked_);
335 // Undo lock animation.
336 StartUnlockAnimationAfterUIDestroyed();
339 void LockStateController::StartLockToShutdownTimer() {
340 shutdown_after_lock_ = false;
341 lock_to_shutdown_timer_.Stop();
342 lock_to_shutdown_timer_.Start(
344 base::TimeDelta::FromMilliseconds(kLockToShutdownTimeoutMs),
345 this, &LockStateController::OnLockToShutdownTimeout);
348 void LockStateController::OnLockToShutdownTimeout() {
349 DCHECK(system_is_locked_);
350 StartCancellableShutdownAnimation();
353 void LockStateController::StartPreShutdownAnimationTimer() {
354 pre_shutdown_timer_.Stop();
355 pre_shutdown_timer_.Start(
358 GetDuration(internal::SessionStateAnimator::ANIMATION_SPEED_SHUTDOWN),
360 &LockStateController::OnPreShutdownAnimationTimeout);
363 void LockStateController::OnPreShutdownAnimationTimeout() {
364 shutting_down_ = true;
366 Shell* shell = ash::Shell::GetInstance();
367 shell->env_filter()->set_cursor_hidden_by_filter(false);
368 shell->cursor_manager()->HideCursor();
370 StartRealShutdownTimer(false);
373 void LockStateController::StartRealShutdownTimer(
374 bool with_animation_time) {
375 base::TimeDelta duration =
376 base::TimeDelta::FromMilliseconds(kShutdownRequestDelayMs);
377 if (with_animation_time) {
378 duration += animator_->GetDuration(
379 internal::SessionStateAnimator::ANIMATION_SPEED_SHUTDOWN);
382 #if defined(OS_CHROMEOS)
383 const AccessibilityDelegate* const delegate =
384 Shell::GetInstance()->accessibility_delegate();
385 if (delegate->IsSpokenFeedbackEnabled()) {
386 const base::TimeDelta shutdown_sound_duration = std::min(
387 SoundsManager::Get()->GetDuration(SoundsManager::SOUND_SHUTDOWN),
388 base::TimeDelta::FromMilliseconds(kMaxShutdownSoundDurationMs));
389 duration = std::max(duration, shutdown_sound_duration);
390 SoundsManager::Get()->Play(SoundsManager::SOUND_SHUTDOWN);
394 real_shutdown_timer_.Start(
398 &LockStateController::OnRealShutdownTimeout);
401 void LockStateController::OnRealShutdownTimeout() {
402 DCHECK(shutting_down_);
403 #if defined(OS_CHROMEOS)
404 if (!base::SysInfo::IsRunningOnChromeOS()) {
405 ShellDelegate* delegate = Shell::GetInstance()->delegate();
412 Shell::GetInstance()->delegate()->RecordUserMetricsAction(
413 UMA_ACCEL_SHUT_DOWN_POWER_BUTTON);
414 delegate_->RequestShutdown();
417 void LockStateController::StartCancellableShutdownAnimation() {
418 Shell* shell = ash::Shell::GetInstance();
419 // Hide cursor, but let it reappear if the mouse moves.
420 shell->env_filter()->set_cursor_hidden_by_filter(true);
421 shell->cursor_manager()->HideCursor();
423 animator_->StartGlobalAnimation(
424 internal::SessionStateAnimator::ANIMATION_GRAYSCALE_BRIGHTNESS,
425 internal::SessionStateAnimator::ANIMATION_SPEED_SHUTDOWN);
426 StartPreShutdownAnimationTimer();
429 void LockStateController::StartImmediatePreLockAnimation(
430 bool request_lock_on_completion) {
431 animating_lock_ = true;
433 StoreUnlockedProperties();
435 base::Closure next_animation_starter =
436 base::Bind(&LockStateController::PreLockAnimationFinished,
437 base::Unretained(this), request_lock_on_completion);
438 AnimationFinishedObserver* observer =
439 new AnimationFinishedObserver(next_animation_starter);
443 animator_->StartAnimationWithObserver(
444 internal::SessionStateAnimator::NON_LOCK_SCREEN_CONTAINERS,
445 internal::SessionStateAnimator::ANIMATION_LIFT,
446 internal::SessionStateAnimator::ANIMATION_SPEED_MOVE_WINDOWS,
448 animator_->StartAnimationWithObserver(
449 internal::SessionStateAnimator::LAUNCHER,
450 internal::SessionStateAnimator::ANIMATION_FADE_OUT,
451 internal::SessionStateAnimator::ANIMATION_SPEED_MOVE_WINDOWS,
453 // Hide the screen locker containers so we can raise them later.
454 animator_->StartAnimation(
455 internal::SessionStateAnimator::LOCK_SCREEN_CONTAINERS,
456 internal::SessionStateAnimator::ANIMATION_HIDE_IMMEDIATELY,
457 internal::SessionStateAnimator::ANIMATION_SPEED_IMMEDIATE);
458 AnimateBackgroundAppearanceIfNecessary(
459 internal::SessionStateAnimator::ANIMATION_SPEED_MOVE_WINDOWS,
464 DispatchCancelMode();
465 FOR_EACH_OBSERVER(LockStateObserver, observers_,
466 OnLockStateEvent(LockStateObserver::EVENT_LOCK_ANIMATION_STARTED));
469 void LockStateController::StartCancellablePreLockAnimation() {
470 animating_lock_ = true;
471 StoreUnlockedProperties();
473 base::Closure next_animation_starter =
474 base::Bind(&LockStateController::PreLockAnimationFinished,
475 base::Unretained(this), true /* request_lock */);
476 AnimationFinishedObserver* observer =
477 new AnimationFinishedObserver(next_animation_starter);
481 animator_->StartAnimationWithObserver(
482 internal::SessionStateAnimator::NON_LOCK_SCREEN_CONTAINERS,
483 internal::SessionStateAnimator::ANIMATION_LIFT,
484 internal::SessionStateAnimator::ANIMATION_SPEED_UNDOABLE,
486 animator_->StartAnimationWithObserver(
487 internal::SessionStateAnimator::LAUNCHER,
488 internal::SessionStateAnimator::ANIMATION_FADE_OUT,
489 internal::SessionStateAnimator::ANIMATION_SPEED_UNDOABLE,
491 // Hide the screen locker containers so we can raise them later.
492 animator_->StartAnimation(
493 internal::SessionStateAnimator::LOCK_SCREEN_CONTAINERS,
494 internal::SessionStateAnimator::ANIMATION_HIDE_IMMEDIATELY,
495 internal::SessionStateAnimator::ANIMATION_SPEED_IMMEDIATE);
496 AnimateBackgroundAppearanceIfNecessary(
497 internal::SessionStateAnimator::ANIMATION_SPEED_UNDOABLE,
500 DispatchCancelMode();
501 FOR_EACH_OBSERVER(LockStateObserver, observers_,
502 OnLockStateEvent(LockStateObserver::EVENT_PRELOCK_ANIMATION_STARTED));
506 void LockStateController::CancelPreLockAnimation() {
507 base::Closure next_animation_starter =
508 base::Bind(&LockStateController::LockAnimationCancelled,
509 base::Unretained(this));
510 AnimationFinishedObserver* observer =
511 new AnimationFinishedObserver(next_animation_starter);
515 animator_->StartAnimationWithObserver(
516 internal::SessionStateAnimator::NON_LOCK_SCREEN_CONTAINERS,
517 internal::SessionStateAnimator::ANIMATION_UNDO_LIFT,
518 internal::SessionStateAnimator::ANIMATION_SPEED_UNDO_MOVE_WINDOWS,
520 animator_->StartAnimationWithObserver(
521 internal::SessionStateAnimator::LAUNCHER,
522 internal::SessionStateAnimator::ANIMATION_FADE_IN,
523 internal::SessionStateAnimator::ANIMATION_SPEED_UNDO_MOVE_WINDOWS,
525 AnimateBackgroundHidingIfNecessary(
526 internal::SessionStateAnimator::ANIMATION_SPEED_UNDO_MOVE_WINDOWS,
532 void LockStateController::StartPostLockAnimation() {
533 base::Closure next_animation_starter =
534 base::Bind(&LockStateController::PostLockAnimationFinished,
535 base::Unretained(this));
537 AnimationFinishedObserver* observer =
538 new AnimationFinishedObserver(next_animation_starter);
541 animator_->StartAnimationWithObserver(
542 internal::SessionStateAnimator::LOCK_SCREEN_CONTAINERS,
543 internal::SessionStateAnimator::ANIMATION_RAISE_TO_SCREEN,
544 internal::SessionStateAnimator::ANIMATION_SPEED_MOVE_WINDOWS,
549 void LockStateController::StartUnlockAnimationBeforeUIDestroyed(
550 base::Closure& callback) {
551 animator_->StartAnimationWithCallback(
552 internal::SessionStateAnimator::LOCK_SCREEN_CONTAINERS,
553 internal::SessionStateAnimator::ANIMATION_LIFT,
554 internal::SessionStateAnimator::ANIMATION_SPEED_MOVE_WINDOWS,
558 void LockStateController::StartUnlockAnimationAfterUIDestroyed() {
559 base::Closure next_animation_starter =
560 base::Bind(&LockStateController::UnlockAnimationAfterUIDestroyedFinished,
561 base::Unretained(this));
563 AnimationFinishedObserver* observer =
564 new AnimationFinishedObserver(next_animation_starter);
568 animator_->StartAnimationWithObserver(
569 internal::SessionStateAnimator::NON_LOCK_SCREEN_CONTAINERS,
570 internal::SessionStateAnimator::ANIMATION_DROP,
571 internal::SessionStateAnimator::ANIMATION_SPEED_MOVE_WINDOWS,
573 animator_->StartAnimationWithObserver(
574 internal::SessionStateAnimator::LAUNCHER,
575 internal::SessionStateAnimator::ANIMATION_FADE_IN,
576 internal::SessionStateAnimator::ANIMATION_SPEED_MOVE_WINDOWS,
578 AnimateBackgroundHidingIfNecessary(
579 internal::SessionStateAnimator::ANIMATION_SPEED_MOVE_WINDOWS,
584 void LockStateController::LockAnimationCancelled() {
585 can_cancel_lock_animation_ = false;
586 RestoreUnlockedProperties();
589 void LockStateController::PreLockAnimationFinished(bool request_lock) {
590 can_cancel_lock_animation_ = false;
593 Shell::GetInstance()->delegate()->RecordUserMetricsAction(
594 shutdown_after_lock_ ?
595 UMA_ACCEL_LOCK_SCREEN_POWER_BUTTON :
596 UMA_ACCEL_LOCK_SCREEN_LOCK_BUTTON);
597 delegate_->RequestLockScreen();
600 lock_fail_timer_.Start(
602 base::TimeDelta::FromMilliseconds(kLockFailTimeoutMs),
604 &LockStateController::OnLockFailTimeout);
607 void LockStateController::PostLockAnimationFinished() {
608 animating_lock_ = false;
610 FOR_EACH_OBSERVER(LockStateObserver, observers_,
611 OnLockStateEvent(LockStateObserver::EVENT_LOCK_ANIMATION_FINISHED));
612 if (!lock_screen_displayed_callback_.is_null()) {
613 lock_screen_displayed_callback_.Run();
614 lock_screen_displayed_callback_.Reset();
616 if (shutdown_after_lock_) {
617 shutdown_after_lock_ = false;
618 StartLockToShutdownTimer();
622 void LockStateController::UnlockAnimationAfterUIDestroyedFinished() {
623 RestoreUnlockedProperties();
626 void LockStateController::StoreUnlockedProperties() {
627 if (!unlocked_properties_) {
628 unlocked_properties_.reset(new UnlockedStateProperties());
629 unlocked_properties_->background_is_hidden = IsBackgroundHidden();
631 if (unlocked_properties_->background_is_hidden) {
632 // Hide background so that it can be animated later.
633 animator_->StartAnimation(
634 internal::SessionStateAnimator::DESKTOP_BACKGROUND,
635 internal::SessionStateAnimator::ANIMATION_HIDE_IMMEDIATELY,
636 internal::SessionStateAnimator::ANIMATION_SPEED_IMMEDIATE);
641 void LockStateController::RestoreUnlockedProperties() {
642 if (!unlocked_properties_)
644 if (unlocked_properties_->background_is_hidden) {
646 // Restore background visibility.
647 animator_->StartAnimation(
648 internal::SessionStateAnimator::DESKTOP_BACKGROUND,
649 internal::SessionStateAnimator::ANIMATION_FADE_IN,
650 internal::SessionStateAnimator::ANIMATION_SPEED_IMMEDIATE);
652 unlocked_properties_.reset();
655 void LockStateController::AnimateBackgroundAppearanceIfNecessary(
656 internal::SessionStateAnimator::AnimationSpeed speed,
657 ui::LayerAnimationObserver* observer) {
658 if (unlocked_properties_.get() &&
659 unlocked_properties_->background_is_hidden) {
660 animator_->StartAnimationWithObserver(
661 internal::SessionStateAnimator::DESKTOP_BACKGROUND,
662 internal::SessionStateAnimator::ANIMATION_FADE_IN,
668 void LockStateController::AnimateBackgroundHidingIfNecessary(
669 internal::SessionStateAnimator::AnimationSpeed speed,
670 ui::LayerAnimationObserver* observer) {
671 if (unlocked_properties_.get() &&
672 unlocked_properties_->background_is_hidden) {
673 animator_->StartAnimationWithObserver(
674 internal::SessionStateAnimator::DESKTOP_BACKGROUND,
675 internal::SessionStateAnimator::ANIMATION_FADE_OUT,