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/window_tree_host.h"
21 #include "ui/compositor/layer_animation_sequence.h"
22 #include "ui/compositor/scoped_layer_animation_settings.h"
23 #include "ui/views/controls/menu/menu_controller.h"
24 #include "ui/wm/core/compound_event_filter.h"
26 #if defined(OS_CHROMEOS)
27 #include "base/sys_info.h"
28 #include "media/audio/sounds/sounds_manager.h"
31 #if defined(OS_CHROMEOS)
32 using media::SoundsManager;
39 #if defined(OS_CHROMEOS)
40 const int kMaxShutdownSoundDurationMs = 1500;
43 aura::Window* GetBackground() {
44 aura::Window* root_window = Shell::GetPrimaryRootWindow();
45 return Shell::GetContainer(root_window,
46 kShellWindowId_DesktopBackgroundContainer);
49 bool IsBackgroundHidden() {
50 return !GetBackground()->IsVisible();
53 void ShowBackground() {
54 ui::ScopedLayerAnimationSettings settings(
55 GetBackground()->layer()->GetAnimator());
56 settings.SetTransitionDuration(base::TimeDelta());
57 GetBackground()->Show();
60 void HideBackground() {
61 ui::ScopedLayerAnimationSettings settings(
62 GetBackground()->layer()->GetAnimator());
63 settings.SetTransitionDuration(base::TimeDelta());
64 GetBackground()->Hide();
67 // This observer is intended to use in cases when some action has to be taken
68 // once some animation successfully completes (i.e. it was not aborted).
69 // Observer will count a number of sequences it is attached to, and a number of
70 // finished sequences (either Ended or Aborted). Once these two numbers are
71 // equal, observer will delete itself, calling callback passed to constructor if
72 // there were no aborted animations.
73 // This way it can be either used to wait for some animation to be finished in
74 // multiple layers, to wait once a sequence of animations is finished in one
75 // layer or the mixture of both.
76 class AnimationFinishedObserver : public ui::LayerAnimationObserver {
78 explicit AnimationFinishedObserver(base::Closure &callback)
79 : callback_(callback),
80 sequences_attached_(0),
81 sequences_completed_(0),
85 // Pauses observer: no checks will be made while paused. It can be used when
86 // a sequence has some immediate animations in the beginning, and for
87 // animations that can be tested with flag that makes all animations
93 // Unpauses observer. It does a check and calls callback if conditions are
99 if (sequences_completed_ == sequences_attached_) {
106 virtual ~AnimationFinishedObserver() {
109 // LayerAnimationObserver implementation
110 virtual void OnLayerAnimationEnded(
111 ui::LayerAnimationSequence* sequence) OVERRIDE {
112 sequences_completed_++;
113 if ((sequences_completed_ == sequences_attached_) && !paused_) {
119 virtual void OnLayerAnimationAborted(
120 ui::LayerAnimationSequence* sequence) OVERRIDE {
121 sequences_completed_++;
122 if ((sequences_completed_ == sequences_attached_) && !paused_)
126 virtual void OnLayerAnimationScheduled(
127 ui::LayerAnimationSequence* sequence) OVERRIDE {
130 virtual void OnAttachedToSequence(
131 ui::LayerAnimationSequence* sequence) OVERRIDE {
132 LayerAnimationObserver::OnAttachedToSequence(sequence);
133 sequences_attached_++;
136 // Callback to be called.
137 base::Closure callback_;
139 // Number of sequences this observer was attached to.
140 int sequences_attached_;
142 // Number of sequences either ended or aborted.
143 int sequences_completed_;
147 DISALLOW_COPY_AND_ASSIGN(AnimationFinishedObserver);
152 const int LockStateController::kLockTimeoutMs = 400;
153 const int LockStateController::kShutdownTimeoutMs = 400;
154 const int LockStateController::kLockFailTimeoutMs = 8000;
155 const int LockStateController::kLockToShutdownTimeoutMs = 150;
156 const int LockStateController::kShutdownRequestDelayMs = 50;
158 LockStateController::TestApi::TestApi(LockStateController* controller)
159 : controller_(controller) {
162 LockStateController::TestApi::~TestApi() {
165 LockStateController::LockStateController()
166 : animator_(new SessionStateAnimator()),
167 login_status_(user::LOGGED_IN_NONE),
168 system_is_locked_(false),
169 shutting_down_(false),
170 shutdown_after_lock_(false),
171 animating_lock_(false),
172 can_cancel_lock_animation_(false),
173 weak_ptr_factory_(this) {
174 Shell::GetPrimaryRootWindow()->GetHost()->AddObserver(this);
177 LockStateController::~LockStateController() {
178 Shell::GetPrimaryRootWindow()->GetHost()->RemoveObserver(this);
181 void LockStateController::SetDelegate(LockStateControllerDelegate* delegate) {
182 delegate_.reset(delegate);
185 void LockStateController::AddObserver(LockStateObserver* observer) {
186 observers_.AddObserver(observer);
189 void LockStateController::RemoveObserver(LockStateObserver* observer) {
190 observers_.RemoveObserver(observer);
193 bool LockStateController::HasObserver(LockStateObserver* observer) {
194 return observers_.HasObserver(observer);
197 void LockStateController::StartLockAnimation(
198 bool shutdown_after_lock) {
201 shutdown_after_lock_ = shutdown_after_lock;
202 can_cancel_lock_animation_ = true;
204 StartCancellablePreLockAnimation();
207 void LockStateController::StartShutdownAnimation() {
208 StartCancellableShutdownAnimation();
211 void LockStateController::StartLockAnimationAndLockImmediately() {
214 StartImmediatePreLockAnimation(true /* request_lock_on_completion */);
217 bool LockStateController::LockRequested() {
218 return lock_fail_timer_.IsRunning();
221 bool LockStateController::ShutdownRequested() {
222 return shutting_down_;
225 bool LockStateController::CanCancelLockAnimation() {
226 return can_cancel_lock_animation_;
229 void LockStateController::CancelLockAnimation() {
230 if (!CanCancelLockAnimation())
232 shutdown_after_lock_ = false;
233 animating_lock_ = false;
234 CancelPreLockAnimation();
237 bool LockStateController::CanCancelShutdownAnimation() {
238 return pre_shutdown_timer_.IsRunning() ||
239 shutdown_after_lock_ ||
240 lock_to_shutdown_timer_.IsRunning();
243 void LockStateController::CancelShutdownAnimation() {
244 if (!CanCancelShutdownAnimation())
246 if (lock_to_shutdown_timer_.IsRunning()) {
247 lock_to_shutdown_timer_.Stop();
250 if (shutdown_after_lock_) {
251 shutdown_after_lock_ = false;
255 animator_->StartGlobalAnimation(
256 SessionStateAnimator::ANIMATION_UNDO_GRAYSCALE_BRIGHTNESS,
257 SessionStateAnimator::ANIMATION_SPEED_REVERT_SHUTDOWN);
258 pre_shutdown_timer_.Stop();
261 void LockStateController::OnStartingLock() {
262 if (shutting_down_ || system_is_locked_)
266 StartImmediatePreLockAnimation(false /* request_lock_on_completion */);
269 void LockStateController::RequestShutdown() {
273 shutting_down_ = true;
275 Shell* shell = ash::Shell::GetInstance();
276 shell->cursor_manager()->HideCursor();
277 shell->cursor_manager()->LockCursor();
279 animator_->StartGlobalAnimation(
280 SessionStateAnimator::ANIMATION_GRAYSCALE_BRIGHTNESS,
281 SessionStateAnimator::ANIMATION_SPEED_SHUTDOWN);
282 StartRealShutdownTimer(true);
285 void LockStateController::OnLockScreenHide(
286 base::Callback<void(void)>& callback) {
287 StartUnlockAnimationBeforeUIDestroyed(callback);
290 void LockStateController::SetLockScreenDisplayedCallback(
291 const base::Closure& callback) {
292 lock_screen_displayed_callback_ = callback;
295 void LockStateController::OnHostCloseRequested(
296 const aura::WindowTreeHost* host) {
297 Shell::GetInstance()->delegate()->Exit();
300 void LockStateController::OnLoginStateChanged(
301 user::LoginStatus status) {
302 if (status != user::LOGGED_IN_LOCKED)
303 login_status_ = status;
304 system_is_locked_ = (status == user::LOGGED_IN_LOCKED);
307 void LockStateController::OnAppTerminating() {
308 // If we hear that Chrome is exiting but didn't request it ourselves, all we
309 // can really hope for is that we'll have time to clear the screen.
310 // This is also the case when the user signs off.
311 if (!shutting_down_) {
312 shutting_down_ = true;
313 Shell* shell = ash::Shell::GetInstance();
314 shell->cursor_manager()->HideCursor();
315 shell->cursor_manager()->LockCursor();
316 animator_->StartAnimation(SessionStateAnimator::kAllContainersMask,
317 SessionStateAnimator::ANIMATION_HIDE_IMMEDIATELY,
318 SessionStateAnimator::ANIMATION_SPEED_IMMEDIATE);
322 void LockStateController::OnLockStateChanged(bool locked) {
323 VLOG(1) << "OnLockStateChanged " << locked;
324 if (shutting_down_ || (system_is_locked_ == locked))
327 system_is_locked_ = locked;
330 StartPostLockAnimation();
331 lock_fail_timer_.Stop();
333 StartUnlockAnimationAfterUIDestroyed();
337 void LockStateController::OnLockFailTimeout() {
338 DCHECK(!system_is_locked_);
339 CHECK(false) << "We can not be sure about the lock state. Crash and let the "
340 << "SessionManager end the session";
343 void LockStateController::StartLockToShutdownTimer() {
344 shutdown_after_lock_ = false;
345 lock_to_shutdown_timer_.Stop();
346 lock_to_shutdown_timer_.Start(
348 base::TimeDelta::FromMilliseconds(kLockToShutdownTimeoutMs),
349 this, &LockStateController::OnLockToShutdownTimeout);
352 void LockStateController::OnLockToShutdownTimeout() {
353 DCHECK(system_is_locked_);
354 StartCancellableShutdownAnimation();
357 void LockStateController::StartPreShutdownAnimationTimer() {
358 pre_shutdown_timer_.Stop();
359 pre_shutdown_timer_.Start(
361 animator_->GetDuration(SessionStateAnimator::ANIMATION_SPEED_SHUTDOWN),
363 &LockStateController::OnPreShutdownAnimationTimeout);
366 void LockStateController::OnPreShutdownAnimationTimeout() {
367 VLOG(1) << "OnPreShutdownAnimationTimeout";
368 shutting_down_ = true;
370 Shell* shell = ash::Shell::GetInstance();
371 shell->cursor_manager()->HideCursor();
373 StartRealShutdownTimer(false);
376 void LockStateController::StartRealShutdownTimer(bool with_animation_time) {
377 base::TimeDelta duration =
378 base::TimeDelta::FromMilliseconds(kShutdownRequestDelayMs);
379 if (with_animation_time) {
381 animator_->GetDuration(SessionStateAnimator::ANIMATION_SPEED_SHUTDOWN);
384 #if defined(OS_CHROMEOS)
385 const AccessibilityDelegate* const delegate =
386 Shell::GetInstance()->accessibility_delegate();
387 base::TimeDelta sound_duration = delegate->PlayShutdownSound();
389 std::min(sound_duration,
390 base::TimeDelta::FromMilliseconds(kMaxShutdownSoundDurationMs));
391 duration = std::max(duration, sound_duration);
394 real_shutdown_timer_.Start(
395 FROM_HERE, duration, this, &LockStateController::OnRealShutdownTimeout);
398 void LockStateController::OnRealShutdownTimeout() {
399 VLOG(1) << "OnRealShutdownTimeout";
400 DCHECK(shutting_down_);
401 #if defined(OS_CHROMEOS)
402 if (!base::SysInfo::IsRunningOnChromeOS()) {
403 ShellDelegate* delegate = Shell::GetInstance()->delegate();
410 Shell::GetInstance()->metrics()->RecordUserMetricsAction(
411 UMA_ACCEL_SHUT_DOWN_POWER_BUTTON);
412 delegate_->RequestShutdown();
415 void LockStateController::StartCancellableShutdownAnimation() {
416 Shell* shell = ash::Shell::GetInstance();
417 // Hide cursor, but let it reappear if the mouse moves.
418 shell->cursor_manager()->HideCursor();
420 animator_->StartGlobalAnimation(
421 SessionStateAnimator::ANIMATION_GRAYSCALE_BRIGHTNESS,
422 SessionStateAnimator::ANIMATION_SPEED_SHUTDOWN);
423 StartPreShutdownAnimationTimer();
426 void LockStateController::StartImmediatePreLockAnimation(
427 bool request_lock_on_completion) {
428 VLOG(1) << "StartImmediatePreLockAnimation " << request_lock_on_completion;
429 animating_lock_ = true;
430 StoreUnlockedProperties();
432 base::Closure next_animation_starter =
433 base::Bind(&LockStateController::PreLockAnimationFinished,
434 weak_ptr_factory_.GetWeakPtr(),
435 request_lock_on_completion);
436 AnimationFinishedObserver* observer =
437 new AnimationFinishedObserver(next_animation_starter);
441 animator_->StartAnimationWithObserver(
442 SessionStateAnimator::NON_LOCK_SCREEN_CONTAINERS,
443 SessionStateAnimator::ANIMATION_LIFT,
444 SessionStateAnimator::ANIMATION_SPEED_MOVE_WINDOWS,
446 animator_->StartAnimationWithObserver(
447 SessionStateAnimator::LAUNCHER,
448 SessionStateAnimator::ANIMATION_FADE_OUT,
449 SessionStateAnimator::ANIMATION_SPEED_MOVE_WINDOWS,
451 // Hide the screen locker containers so we can raise them later.
452 animator_->StartAnimation(SessionStateAnimator::LOCK_SCREEN_CONTAINERS,
453 SessionStateAnimator::ANIMATION_HIDE_IMMEDIATELY,
454 SessionStateAnimator::ANIMATION_SPEED_IMMEDIATE);
455 AnimateBackgroundAppearanceIfNecessary(
456 SessionStateAnimator::ANIMATION_SPEED_MOVE_WINDOWS, observer);
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 weak_ptr_factory_.GetWeakPtr(),
472 true /* request_lock */);
473 AnimationFinishedObserver* observer =
474 new AnimationFinishedObserver(next_animation_starter);
478 animator_->StartAnimationWithObserver(
479 SessionStateAnimator::NON_LOCK_SCREEN_CONTAINERS,
480 SessionStateAnimator::ANIMATION_LIFT,
481 SessionStateAnimator::ANIMATION_SPEED_UNDOABLE,
483 animator_->StartAnimationWithObserver(
484 SessionStateAnimator::LAUNCHER,
485 SessionStateAnimator::ANIMATION_FADE_OUT,
486 SessionStateAnimator::ANIMATION_SPEED_UNDOABLE,
488 // Hide the screen locker containers so we can raise them later.
489 animator_->StartAnimation(SessionStateAnimator::LOCK_SCREEN_CONTAINERS,
490 SessionStateAnimator::ANIMATION_HIDE_IMMEDIATELY,
491 SessionStateAnimator::ANIMATION_SPEED_IMMEDIATE);
492 AnimateBackgroundAppearanceIfNecessary(
493 SessionStateAnimator::ANIMATION_SPEED_UNDOABLE, observer);
495 DispatchCancelMode();
496 FOR_EACH_OBSERVER(LockStateObserver, observers_,
497 OnLockStateEvent(LockStateObserver::EVENT_PRELOCK_ANIMATION_STARTED));
501 void LockStateController::CancelPreLockAnimation() {
502 VLOG(1) << "CancelPreLockAnimation";
503 base::Closure next_animation_starter =
504 base::Bind(&LockStateController::LockAnimationCancelled,
505 weak_ptr_factory_.GetWeakPtr());
506 AnimationFinishedObserver* observer =
507 new AnimationFinishedObserver(next_animation_starter);
511 animator_->StartAnimationWithObserver(
512 SessionStateAnimator::NON_LOCK_SCREEN_CONTAINERS,
513 SessionStateAnimator::ANIMATION_UNDO_LIFT,
514 SessionStateAnimator::ANIMATION_SPEED_UNDO_MOVE_WINDOWS,
516 animator_->StartAnimationWithObserver(
517 SessionStateAnimator::LAUNCHER,
518 SessionStateAnimator::ANIMATION_FADE_IN,
519 SessionStateAnimator::ANIMATION_SPEED_UNDO_MOVE_WINDOWS,
521 AnimateBackgroundHidingIfNecessary(
522 SessionStateAnimator::ANIMATION_SPEED_UNDO_MOVE_WINDOWS, observer);
527 void LockStateController::StartPostLockAnimation() {
528 VLOG(1) << "StartPostLockAnimation";
529 base::Closure next_animation_starter =
530 base::Bind(&LockStateController::PostLockAnimationFinished,
531 weak_ptr_factory_.GetWeakPtr());
533 AnimationFinishedObserver* observer =
534 new AnimationFinishedObserver(next_animation_starter);
537 animator_->StartAnimationWithObserver(
538 SessionStateAnimator::LOCK_SCREEN_CONTAINERS,
539 SessionStateAnimator::ANIMATION_RAISE_TO_SCREEN,
540 SessionStateAnimator::ANIMATION_SPEED_MOVE_WINDOWS,
545 void LockStateController::StartUnlockAnimationBeforeUIDestroyed(
546 base::Closure& callback) {
547 VLOG(1) << "StartUnlockAnimationBeforeUIDestroyed";
548 animator_->StartAnimationWithCallback(
549 SessionStateAnimator::LOCK_SCREEN_CONTAINERS,
550 SessionStateAnimator::ANIMATION_LIFT,
551 SessionStateAnimator::ANIMATION_SPEED_MOVE_WINDOWS,
555 void LockStateController::StartUnlockAnimationAfterUIDestroyed() {
556 VLOG(1) << "StartUnlockAnimationAfterUIDestroyed";
557 base::Closure next_animation_starter =
558 base::Bind(&LockStateController::UnlockAnimationAfterUIDestroyedFinished,
559 weak_ptr_factory_.GetWeakPtr());
561 AnimationFinishedObserver* observer =
562 new AnimationFinishedObserver(next_animation_starter);
566 animator_->StartAnimationWithObserver(
567 SessionStateAnimator::NON_LOCK_SCREEN_CONTAINERS,
568 SessionStateAnimator::ANIMATION_DROP,
569 SessionStateAnimator::ANIMATION_SPEED_MOVE_WINDOWS,
571 animator_->StartAnimationWithObserver(
572 SessionStateAnimator::LAUNCHER,
573 SessionStateAnimator::ANIMATION_FADE_IN,
574 SessionStateAnimator::ANIMATION_SPEED_MOVE_WINDOWS,
576 AnimateBackgroundHidingIfNecessary(
577 SessionStateAnimator::ANIMATION_SPEED_MOVE_WINDOWS, observer);
581 void LockStateController::LockAnimationCancelled() {
582 can_cancel_lock_animation_ = false;
583 RestoreUnlockedProperties();
586 void LockStateController::PreLockAnimationFinished(bool request_lock) {
587 can_cancel_lock_animation_ = false;
588 VLOG(1) << "PreLockAnimationFinished";
590 Shell::GetInstance()->metrics()->RecordUserMetricsAction(
591 shutdown_after_lock_ ?
592 UMA_ACCEL_LOCK_SCREEN_POWER_BUTTON :
593 UMA_ACCEL_LOCK_SCREEN_LOCK_BUTTON);
594 delegate_->RequestLockScreen();
597 int lock_timeout = kLockFailTimeoutMs;
599 #if defined(OS_CHROMEOS)
600 std::string board = base::SysInfo::GetLsbReleaseBoard();
602 // Increase lock timeout for slower hardware, see http://crbug.com/350628
603 if (board == "x86-mario" ||
604 board.substr(0, 8) == "x86-alex" ||
605 board.substr(0, 7) == "x86-zgb") {
610 lock_fail_timer_.Start(
612 base::TimeDelta::FromMilliseconds(lock_timeout),
614 &LockStateController::OnLockFailTimeout);
617 void LockStateController::PostLockAnimationFinished() {
618 animating_lock_ = false;
619 VLOG(1) << "PostLockAnimationFinished";
620 FOR_EACH_OBSERVER(LockStateObserver, observers_,
621 OnLockStateEvent(LockStateObserver::EVENT_LOCK_ANIMATION_FINISHED));
622 if (!lock_screen_displayed_callback_.is_null()) {
623 lock_screen_displayed_callback_.Run();
624 lock_screen_displayed_callback_.Reset();
626 CHECK(!views::MenuController::GetActiveInstance());
627 if (shutdown_after_lock_) {
628 shutdown_after_lock_ = false;
629 StartLockToShutdownTimer();
633 void LockStateController::UnlockAnimationAfterUIDestroyedFinished() {
634 RestoreUnlockedProperties();
637 void LockStateController::StoreUnlockedProperties() {
638 if (!unlocked_properties_) {
639 unlocked_properties_.reset(new UnlockedStateProperties());
640 unlocked_properties_->background_is_hidden = IsBackgroundHidden();
642 if (unlocked_properties_->background_is_hidden) {
643 // Hide background so that it can be animated later.
644 animator_->StartAnimation(SessionStateAnimator::DESKTOP_BACKGROUND,
645 SessionStateAnimator::ANIMATION_HIDE_IMMEDIATELY,
646 SessionStateAnimator::ANIMATION_SPEED_IMMEDIATE);
651 void LockStateController::RestoreUnlockedProperties() {
652 if (!unlocked_properties_)
654 if (unlocked_properties_->background_is_hidden) {
656 // Restore background visibility.
657 animator_->StartAnimation(SessionStateAnimator::DESKTOP_BACKGROUND,
658 SessionStateAnimator::ANIMATION_FADE_IN,
659 SessionStateAnimator::ANIMATION_SPEED_IMMEDIATE);
661 unlocked_properties_.reset();
664 void LockStateController::AnimateBackgroundAppearanceIfNecessary(
665 SessionStateAnimator::AnimationSpeed speed,
666 ui::LayerAnimationObserver* observer) {
667 if (unlocked_properties_.get() &&
668 unlocked_properties_->background_is_hidden) {
669 animator_->StartAnimationWithObserver(
670 SessionStateAnimator::DESKTOP_BACKGROUND,
671 SessionStateAnimator::ANIMATION_FADE_IN,
677 void LockStateController::AnimateBackgroundHidingIfNecessary(
678 SessionStateAnimator::AnimationSpeed speed,
679 ui::LayerAnimationObserver* observer) {
680 if (unlocked_properties_.get() &&
681 unlocked_properties_->background_is_hidden) {
682 animator_->StartAnimationWithObserver(
683 SessionStateAnimator::DESKTOP_BACKGROUND,
684 SessionStateAnimator::ANIMATION_FADE_OUT,