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/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 "ui/aura/root_window.h"
21 #include "ui/compositor/layer_animation_sequence.h"
22 #include "ui/compositor/scoped_layer_animation_settings.h"
23 #include "ui/views/corewm/compound_event_filter.h"
25 #if defined(OS_CHROMEOS)
26 #include "base/sys_info.h"
27 #include "media/audio/sounds/sounds_manager.h"
30 #if defined(OS_CHROMEOS)
31 using media::SoundsManager;
38 const int kMaxShutdownSoundDurationMs = 1500;
40 aura::Window* GetBackground() {
41 aura::Window* root_window = Shell::GetPrimaryRootWindow();
42 return Shell::GetContainer(root_window,
43 internal::kShellWindowId_DesktopBackgroundContainer);
46 bool IsBackgroundHidden() {
47 return !GetBackground()->IsVisible();
50 void ShowBackground() {
51 ui::ScopedLayerAnimationSettings settings(
52 GetBackground()->layer()->GetAnimator());
53 settings.SetTransitionDuration(base::TimeDelta());
54 GetBackground()->Show();
57 void HideBackground() {
58 ui::ScopedLayerAnimationSettings settings(
59 GetBackground()->layer()->GetAnimator());
60 settings.SetTransitionDuration(base::TimeDelta());
61 GetBackground()->Hide();
64 // This observer is intended to use in cases when some action has to be taken
65 // once some animation successfully completes (i.e. it was not aborted).
66 // Observer will count a number of sequences it is attached to, and a number of
67 // finished sequences (either Ended or Aborted). Once these two numbers are
68 // equal, observer will delete itself, calling callback passed to constructor if
69 // there were no aborted animations.
70 // This way it can be either used to wait for some animation to be finished in
71 // multiple layers, to wait once a sequence of animations is finished in one
72 // layer or the mixture of both.
73 class AnimationFinishedObserver : public ui::LayerAnimationObserver {
75 explicit AnimationFinishedObserver(base::Closure &callback)
76 : callback_(callback),
77 sequences_attached_(0),
78 sequences_completed_(0),
82 // Pauses observer: no checks will be made while paused. It can be used when
83 // a sequence has some immediate animations in the beginning, and for
84 // animations that can be tested with flag that makes all animations
90 // Unpauses observer. It does a check and calls callback if conditions are
96 if (sequences_completed_ == sequences_attached_) {
103 virtual ~AnimationFinishedObserver() {
106 // LayerAnimationObserver implementation
107 virtual void OnLayerAnimationEnded(
108 ui::LayerAnimationSequence* sequence) OVERRIDE {
109 sequences_completed_++;
110 if ((sequences_completed_ == sequences_attached_) && !paused_) {
116 virtual void OnLayerAnimationAborted(
117 ui::LayerAnimationSequence* sequence) OVERRIDE {
118 sequences_completed_++;
119 if ((sequences_completed_ == sequences_attached_) && !paused_)
123 virtual void OnLayerAnimationScheduled(
124 ui::LayerAnimationSequence* sequence) OVERRIDE {
127 virtual void OnAttachedToSequence(
128 ui::LayerAnimationSequence* sequence) OVERRIDE {
129 LayerAnimationObserver::OnAttachedToSequence(sequence);
130 sequences_attached_++;
133 // Callback to be called.
134 base::Closure callback_;
136 // Number of sequences this observer was attached to.
137 int sequences_attached_;
139 // Number of sequences either ended or aborted.
140 int sequences_completed_;
144 DISALLOW_COPY_AND_ASSIGN(AnimationFinishedObserver);
149 const int LockStateController::kLockTimeoutMs = 400;
150 const int LockStateController::kShutdownTimeoutMs = 400;
151 const int LockStateController::kLockFailTimeoutMs = 8000;
152 const int LockStateController::kLockToShutdownTimeoutMs = 150;
153 const int LockStateController::kShutdownRequestDelayMs = 50;
155 LockStateController::TestApi::TestApi(LockStateController* controller)
156 : controller_(controller) {
159 LockStateController::TestApi::~TestApi() {
162 LockStateController::LockStateController()
163 : animator_(new internal::SessionStateAnimator()),
164 login_status_(user::LOGGED_IN_NONE),
165 system_is_locked_(false),
166 shutting_down_(false),
167 shutdown_after_lock_(false),
168 animating_lock_(false),
169 can_cancel_lock_animation_(false) {
170 Shell::GetPrimaryRootWindow()->GetDispatcher()->AddRootWindowObserver(this);
173 LockStateController::~LockStateController() {
174 Shell::GetPrimaryRootWindow()->GetDispatcher()->RemoveRootWindowObserver(
178 void LockStateController::SetDelegate(LockStateControllerDelegate* delegate) {
179 delegate_.reset(delegate);
182 void LockStateController::AddObserver(LockStateObserver* observer) {
183 observers_.AddObserver(observer);
186 void LockStateController::RemoveObserver(LockStateObserver* observer) {
187 observers_.RemoveObserver(observer);
190 bool LockStateController::HasObserver(LockStateObserver* observer) {
191 return observers_.HasObserver(observer);
194 void LockStateController::StartLockAnimation(
195 bool shutdown_after_lock) {
198 shutdown_after_lock_ = shutdown_after_lock;
199 can_cancel_lock_animation_ = true;
201 StartCancellablePreLockAnimation();
204 void LockStateController::StartShutdownAnimation() {
205 StartCancellableShutdownAnimation();
208 void LockStateController::StartLockAnimationAndLockImmediately() {
211 StartImmediatePreLockAnimation(true /* request_lock_on_completion */);
214 bool LockStateController::LockRequested() {
215 return lock_fail_timer_.IsRunning();
218 bool LockStateController::ShutdownRequested() {
219 return shutting_down_;
222 bool LockStateController::CanCancelLockAnimation() {
223 return can_cancel_lock_animation_;
226 void LockStateController::CancelLockAnimation() {
227 if (!CanCancelLockAnimation())
229 shutdown_after_lock_ = false;
230 animating_lock_ = false;
231 CancelPreLockAnimation();
234 bool LockStateController::CanCancelShutdownAnimation() {
235 return pre_shutdown_timer_.IsRunning() ||
236 shutdown_after_lock_ ||
237 lock_to_shutdown_timer_.IsRunning();
240 void LockStateController::CancelShutdownAnimation() {
241 if (!CanCancelShutdownAnimation())
243 if (lock_to_shutdown_timer_.IsRunning()) {
244 lock_to_shutdown_timer_.Stop();
247 if (shutdown_after_lock_) {
248 shutdown_after_lock_ = false;
252 animator_->StartGlobalAnimation(
253 internal::SessionStateAnimator::ANIMATION_UNDO_GRAYSCALE_BRIGHTNESS,
254 internal::SessionStateAnimator::ANIMATION_SPEED_REVERT_SHUTDOWN);
255 pre_shutdown_timer_.Stop();
258 void LockStateController::OnStartingLock() {
259 if (shutting_down_ || system_is_locked_)
263 StartImmediatePreLockAnimation(false /* request_lock_on_completion */);
266 void LockStateController::RequestShutdown() {
270 shutting_down_ = true;
272 Shell* shell = ash::Shell::GetInstance();
273 shell->cursor_manager()->HideCursor();
274 shell->cursor_manager()->LockCursor();
276 animator_->StartGlobalAnimation(
277 internal::SessionStateAnimator::ANIMATION_GRAYSCALE_BRIGHTNESS,
278 internal::SessionStateAnimator::ANIMATION_SPEED_SHUTDOWN);
279 StartRealShutdownTimer(true);
282 void LockStateController::OnLockScreenHide(
283 base::Callback<void(void)>& callback) {
284 StartUnlockAnimationBeforeUIDestroyed(callback);
287 void LockStateController::SetLockScreenDisplayedCallback(
288 const base::Closure& callback) {
289 lock_screen_displayed_callback_ = callback;
292 void LockStateController::OnWindowTreeHostCloseRequested(
293 const aura::RootWindow*) {
294 Shell::GetInstance()->delegate()->Exit();
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);
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);
320 void LockStateController::OnLockStateChanged(bool locked) {
321 VLOG(1) << "OnLockStateChanged " << locked;
322 if (shutting_down_ || (system_is_locked_ == locked))
325 system_is_locked_ = locked;
328 StartPostLockAnimation();
329 lock_fail_timer_.Stop();
331 StartUnlockAnimationAfterUIDestroyed();
335 void LockStateController::OnLockFailTimeout() {
336 DCHECK(!system_is_locked_);
337 CHECK(false) << "We can not be sure about the lock state. Crash and let the "
338 << "SessionManager end the session";
341 void LockStateController::StartLockToShutdownTimer() {
342 shutdown_after_lock_ = false;
343 lock_to_shutdown_timer_.Stop();
344 lock_to_shutdown_timer_.Start(
346 base::TimeDelta::FromMilliseconds(kLockToShutdownTimeoutMs),
347 this, &LockStateController::OnLockToShutdownTimeout);
350 void LockStateController::OnLockToShutdownTimeout() {
351 DCHECK(system_is_locked_);
352 StartCancellableShutdownAnimation();
355 void LockStateController::StartPreShutdownAnimationTimer() {
356 pre_shutdown_timer_.Stop();
357 pre_shutdown_timer_.Start(
360 GetDuration(internal::SessionStateAnimator::ANIMATION_SPEED_SHUTDOWN),
362 &LockStateController::OnPreShutdownAnimationTimeout);
365 void LockStateController::OnPreShutdownAnimationTimeout() {
366 VLOG(1) << "OnPreShutdownAnimationTimeout";
367 shutting_down_ = true;
369 Shell* shell = ash::Shell::GetInstance();
370 shell->cursor_manager()->HideCursor();
372 StartRealShutdownTimer(false);
375 void LockStateController::StartRealShutdownTimer(bool with_animation_time) {
376 base::TimeDelta duration =
377 base::TimeDelta::FromMilliseconds(kShutdownRequestDelayMs);
378 if (with_animation_time) {
379 duration += animator_->GetDuration(
380 internal::SessionStateAnimator::ANIMATION_SPEED_SHUTDOWN);
383 #if defined(OS_CHROMEOS)
384 const AccessibilityDelegate* const delegate =
385 Shell::GetInstance()->accessibility_delegate();
386 base::TimeDelta sound_duration = delegate->PlayShutdownSound();
388 std::min(sound_duration,
389 base::TimeDelta::FromMilliseconds(kMaxShutdownSoundDurationMs));
390 duration = std::max(duration, sound_duration);
393 real_shutdown_timer_.Start(
394 FROM_HERE, duration, this, &LockStateController::OnRealShutdownTimeout);
397 void LockStateController::OnRealShutdownTimeout() {
398 VLOG(1) << "OnRealShutdownTimeout";
399 DCHECK(shutting_down_);
400 #if defined(OS_CHROMEOS)
401 if (!base::SysInfo::IsRunningOnChromeOS()) {
402 ShellDelegate* delegate = Shell::GetInstance()->delegate();
409 Shell::GetInstance()->metrics()->RecordUserMetricsAction(
410 UMA_ACCEL_SHUT_DOWN_POWER_BUTTON);
411 delegate_->RequestShutdown();
414 void LockStateController::StartCancellableShutdownAnimation() {
415 Shell* shell = ash::Shell::GetInstance();
416 // Hide cursor, but let it reappear if the mouse moves.
417 shell->cursor_manager()->HideCursor();
419 animator_->StartGlobalAnimation(
420 internal::SessionStateAnimator::ANIMATION_GRAYSCALE_BRIGHTNESS,
421 internal::SessionStateAnimator::ANIMATION_SPEED_SHUTDOWN);
422 StartPreShutdownAnimationTimer();
425 void LockStateController::StartImmediatePreLockAnimation(
426 bool request_lock_on_completion) {
427 VLOG(1) << "StartImmediatePreLockAnimation " << request_lock_on_completion;
428 animating_lock_ = true;
429 StoreUnlockedProperties();
431 base::Closure next_animation_starter =
432 base::Bind(&LockStateController::PreLockAnimationFinished,
433 base::Unretained(this), request_lock_on_completion);
434 AnimationFinishedObserver* observer =
435 new AnimationFinishedObserver(next_animation_starter);
439 animator_->StartAnimationWithObserver(
440 internal::SessionStateAnimator::NON_LOCK_SCREEN_CONTAINERS,
441 internal::SessionStateAnimator::ANIMATION_LIFT,
442 internal::SessionStateAnimator::ANIMATION_SPEED_MOVE_WINDOWS,
444 animator_->StartAnimationWithObserver(
445 internal::SessionStateAnimator::LAUNCHER,
446 internal::SessionStateAnimator::ANIMATION_FADE_OUT,
447 internal::SessionStateAnimator::ANIMATION_SPEED_MOVE_WINDOWS,
449 // Hide the screen locker containers so we can raise them later.
450 animator_->StartAnimation(
451 internal::SessionStateAnimator::LOCK_SCREEN_CONTAINERS,
452 internal::SessionStateAnimator::ANIMATION_HIDE_IMMEDIATELY,
453 internal::SessionStateAnimator::ANIMATION_SPEED_IMMEDIATE);
454 AnimateBackgroundAppearanceIfNecessary(
455 internal::SessionStateAnimator::ANIMATION_SPEED_MOVE_WINDOWS,
460 DispatchCancelMode();
461 FOR_EACH_OBSERVER(LockStateObserver, observers_,
462 OnLockStateEvent(LockStateObserver::EVENT_LOCK_ANIMATION_STARTED));
465 void LockStateController::StartCancellablePreLockAnimation() {
466 animating_lock_ = true;
467 StoreUnlockedProperties();
468 VLOG(1) << "StartCancellablePreLockAnimation";
469 base::Closure next_animation_starter =
470 base::Bind(&LockStateController::PreLockAnimationFinished,
471 base::Unretained(this), true /* request_lock */);
472 AnimationFinishedObserver* observer =
473 new AnimationFinishedObserver(next_animation_starter);
477 animator_->StartAnimationWithObserver(
478 internal::SessionStateAnimator::NON_LOCK_SCREEN_CONTAINERS,
479 internal::SessionStateAnimator::ANIMATION_LIFT,
480 internal::SessionStateAnimator::ANIMATION_SPEED_UNDOABLE,
482 animator_->StartAnimationWithObserver(
483 internal::SessionStateAnimator::LAUNCHER,
484 internal::SessionStateAnimator::ANIMATION_FADE_OUT,
485 internal::SessionStateAnimator::ANIMATION_SPEED_UNDOABLE,
487 // Hide the screen locker containers so we can raise them later.
488 animator_->StartAnimation(
489 internal::SessionStateAnimator::LOCK_SCREEN_CONTAINERS,
490 internal::SessionStateAnimator::ANIMATION_HIDE_IMMEDIATELY,
491 internal::SessionStateAnimator::ANIMATION_SPEED_IMMEDIATE);
492 AnimateBackgroundAppearanceIfNecessary(
493 internal::SessionStateAnimator::ANIMATION_SPEED_UNDOABLE,
496 DispatchCancelMode();
497 FOR_EACH_OBSERVER(LockStateObserver, observers_,
498 OnLockStateEvent(LockStateObserver::EVENT_PRELOCK_ANIMATION_STARTED));
502 void LockStateController::CancelPreLockAnimation() {
503 VLOG(1) << "CancelPreLockAnimation";
504 base::Closure next_animation_starter =
505 base::Bind(&LockStateController::LockAnimationCancelled,
506 base::Unretained(this));
507 AnimationFinishedObserver* observer =
508 new AnimationFinishedObserver(next_animation_starter);
512 animator_->StartAnimationWithObserver(
513 internal::SessionStateAnimator::NON_LOCK_SCREEN_CONTAINERS,
514 internal::SessionStateAnimator::ANIMATION_UNDO_LIFT,
515 internal::SessionStateAnimator::ANIMATION_SPEED_UNDO_MOVE_WINDOWS,
517 animator_->StartAnimationWithObserver(
518 internal::SessionStateAnimator::LAUNCHER,
519 internal::SessionStateAnimator::ANIMATION_FADE_IN,
520 internal::SessionStateAnimator::ANIMATION_SPEED_UNDO_MOVE_WINDOWS,
522 AnimateBackgroundHidingIfNecessary(
523 internal::SessionStateAnimator::ANIMATION_SPEED_UNDO_MOVE_WINDOWS,
529 void LockStateController::StartPostLockAnimation() {
530 VLOG(1) << "StartPostLockAnimation";
531 base::Closure next_animation_starter =
532 base::Bind(&LockStateController::PostLockAnimationFinished,
533 base::Unretained(this));
535 AnimationFinishedObserver* observer =
536 new AnimationFinishedObserver(next_animation_starter);
539 animator_->StartAnimationWithObserver(
540 internal::SessionStateAnimator::LOCK_SCREEN_CONTAINERS,
541 internal::SessionStateAnimator::ANIMATION_RAISE_TO_SCREEN,
542 internal::SessionStateAnimator::ANIMATION_SPEED_MOVE_WINDOWS,
547 void LockStateController::StartUnlockAnimationBeforeUIDestroyed(
548 base::Closure& callback) {
549 VLOG(1) << "StartUnlockAnimationBeforeUIDestroyed";
550 animator_->StartAnimationWithCallback(
551 internal::SessionStateAnimator::LOCK_SCREEN_CONTAINERS,
552 internal::SessionStateAnimator::ANIMATION_LIFT,
553 internal::SessionStateAnimator::ANIMATION_SPEED_MOVE_WINDOWS,
557 void LockStateController::StartUnlockAnimationAfterUIDestroyed() {
558 VLOG(1) << "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;
591 VLOG(1) << "PreLockAnimationFinished";
593 Shell::GetInstance()->metrics()->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;
609 VLOG(1) << "PostLockAnimationFinished";
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,