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 if (shutting_down_
|| (system_is_locked_
== locked
))
324 system_is_locked_
= locked
;
327 StartPostLockAnimation();
328 lock_fail_timer_
.Stop();
330 StartUnlockAnimationAfterUIDestroyed();
334 void LockStateController::OnLockFailTimeout() {
335 DCHECK(!system_is_locked_
);
336 // Undo lock animation.
337 StartUnlockAnimationAfterUIDestroyed();
340 void LockStateController::StartLockToShutdownTimer() {
341 shutdown_after_lock_
= false;
342 lock_to_shutdown_timer_
.Stop();
343 lock_to_shutdown_timer_
.Start(
345 base::TimeDelta::FromMilliseconds(kLockToShutdownTimeoutMs
),
346 this, &LockStateController::OnLockToShutdownTimeout
);
349 void LockStateController::OnLockToShutdownTimeout() {
350 DCHECK(system_is_locked_
);
351 StartCancellableShutdownAnimation();
354 void LockStateController::StartPreShutdownAnimationTimer() {
355 pre_shutdown_timer_
.Stop();
356 pre_shutdown_timer_
.Start(
359 GetDuration(internal::SessionStateAnimator::ANIMATION_SPEED_SHUTDOWN
),
361 &LockStateController::OnPreShutdownAnimationTimeout
);
364 void LockStateController::OnPreShutdownAnimationTimeout() {
365 shutting_down_
= true;
367 Shell
* shell
= ash::Shell::GetInstance();
368 shell
->cursor_manager()->HideCursor();
370 StartRealShutdownTimer(false);
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
);
381 #if defined(OS_CHROMEOS)
382 const AccessibilityDelegate
* const delegate
=
383 Shell::GetInstance()->accessibility_delegate();
384 base::TimeDelta sound_duration
= delegate
->PlayShutdownSound();
386 std::min(sound_duration
,
387 base::TimeDelta::FromMilliseconds(kMaxShutdownSoundDurationMs
));
388 duration
= std::max(duration
, sound_duration
);
391 real_shutdown_timer_
.Start(
392 FROM_HERE
, duration
, this, &LockStateController::OnRealShutdownTimeout
);
395 void LockStateController::OnRealShutdownTimeout() {
396 DCHECK(shutting_down_
);
397 #if defined(OS_CHROMEOS)
398 if (!base::SysInfo::IsRunningOnChromeOS()) {
399 ShellDelegate
* delegate
= Shell::GetInstance()->delegate();
406 Shell::GetInstance()->metrics()->RecordUserMetricsAction(
407 UMA_ACCEL_SHUT_DOWN_POWER_BUTTON
);
408 delegate_
->RequestShutdown();
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();
416 animator_
->StartGlobalAnimation(
417 internal::SessionStateAnimator::ANIMATION_GRAYSCALE_BRIGHTNESS
,
418 internal::SessionStateAnimator::ANIMATION_SPEED_SHUTDOWN
);
419 StartPreShutdownAnimationTimer();
422 void LockStateController::StartImmediatePreLockAnimation(
423 bool request_lock_on_completion
) {
424 animating_lock_
= true;
426 StoreUnlockedProperties();
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
);
436 animator_
->StartAnimationWithObserver(
437 internal::SessionStateAnimator::NON_LOCK_SCREEN_CONTAINERS
,
438 internal::SessionStateAnimator::ANIMATION_LIFT
,
439 internal::SessionStateAnimator::ANIMATION_SPEED_MOVE_WINDOWS
,
441 animator_
->StartAnimationWithObserver(
442 internal::SessionStateAnimator::LAUNCHER
,
443 internal::SessionStateAnimator::ANIMATION_FADE_OUT
,
444 internal::SessionStateAnimator::ANIMATION_SPEED_MOVE_WINDOWS
,
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
,
457 DispatchCancelMode();
458 FOR_EACH_OBSERVER(LockStateObserver
, observers_
,
459 OnLockStateEvent(LockStateObserver::EVENT_LOCK_ANIMATION_STARTED
));
462 void LockStateController::StartCancellablePreLockAnimation() {
463 animating_lock_
= true;
464 StoreUnlockedProperties();
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
);
474 animator_
->StartAnimationWithObserver(
475 internal::SessionStateAnimator::NON_LOCK_SCREEN_CONTAINERS
,
476 internal::SessionStateAnimator::ANIMATION_LIFT
,
477 internal::SessionStateAnimator::ANIMATION_SPEED_UNDOABLE
,
479 animator_
->StartAnimationWithObserver(
480 internal::SessionStateAnimator::LAUNCHER
,
481 internal::SessionStateAnimator::ANIMATION_FADE_OUT
,
482 internal::SessionStateAnimator::ANIMATION_SPEED_UNDOABLE
,
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
,
493 DispatchCancelMode();
494 FOR_EACH_OBSERVER(LockStateObserver
, observers_
,
495 OnLockStateEvent(LockStateObserver::EVENT_PRELOCK_ANIMATION_STARTED
));
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
);
508 animator_
->StartAnimationWithObserver(
509 internal::SessionStateAnimator::NON_LOCK_SCREEN_CONTAINERS
,
510 internal::SessionStateAnimator::ANIMATION_UNDO_LIFT
,
511 internal::SessionStateAnimator::ANIMATION_SPEED_UNDO_MOVE_WINDOWS
,
513 animator_
->StartAnimationWithObserver(
514 internal::SessionStateAnimator::LAUNCHER
,
515 internal::SessionStateAnimator::ANIMATION_FADE_IN
,
516 internal::SessionStateAnimator::ANIMATION_SPEED_UNDO_MOVE_WINDOWS
,
518 AnimateBackgroundHidingIfNecessary(
519 internal::SessionStateAnimator::ANIMATION_SPEED_UNDO_MOVE_WINDOWS
,
525 void LockStateController::StartPostLockAnimation() {
526 base::Closure next_animation_starter
=
527 base::Bind(&LockStateController::PostLockAnimationFinished
,
528 base::Unretained(this));
530 AnimationFinishedObserver
* observer
=
531 new AnimationFinishedObserver(next_animation_starter
);
534 animator_
->StartAnimationWithObserver(
535 internal::SessionStateAnimator::LOCK_SCREEN_CONTAINERS
,
536 internal::SessionStateAnimator::ANIMATION_RAISE_TO_SCREEN
,
537 internal::SessionStateAnimator::ANIMATION_SPEED_MOVE_WINDOWS
,
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
,
551 void LockStateController::StartUnlockAnimationAfterUIDestroyed() {
552 base::Closure next_animation_starter
=
553 base::Bind(&LockStateController::UnlockAnimationAfterUIDestroyedFinished
,
554 base::Unretained(this));
556 AnimationFinishedObserver
* observer
=
557 new AnimationFinishedObserver(next_animation_starter
);
561 animator_
->StartAnimationWithObserver(
562 internal::SessionStateAnimator::NON_LOCK_SCREEN_CONTAINERS
,
563 internal::SessionStateAnimator::ANIMATION_DROP
,
564 internal::SessionStateAnimator::ANIMATION_SPEED_MOVE_WINDOWS
,
566 animator_
->StartAnimationWithObserver(
567 internal::SessionStateAnimator::LAUNCHER
,
568 internal::SessionStateAnimator::ANIMATION_FADE_IN
,
569 internal::SessionStateAnimator::ANIMATION_SPEED_MOVE_WINDOWS
,
571 AnimateBackgroundHidingIfNecessary(
572 internal::SessionStateAnimator::ANIMATION_SPEED_MOVE_WINDOWS
,
577 void LockStateController::LockAnimationCancelled() {
578 can_cancel_lock_animation_
= false;
579 RestoreUnlockedProperties();
582 void LockStateController::PreLockAnimationFinished(bool request_lock
) {
583 can_cancel_lock_animation_
= false;
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();
593 lock_fail_timer_
.Start(
595 base::TimeDelta::FromMilliseconds(kLockFailTimeoutMs
),
597 &LockStateController::OnLockFailTimeout
);
600 void LockStateController::PostLockAnimationFinished() {
601 animating_lock_
= false;
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();
609 if (shutdown_after_lock_
) {
610 shutdown_after_lock_
= false;
611 StartLockToShutdownTimer();
615 void LockStateController::UnlockAnimationAfterUIDestroyedFinished() {
616 RestoreUnlockedProperties();
619 void LockStateController::StoreUnlockedProperties() {
620 if (!unlocked_properties_
) {
621 unlocked_properties_
.reset(new UnlockedStateProperties());
622 unlocked_properties_
->background_is_hidden
= IsBackgroundHidden();
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
);
634 void LockStateController::RestoreUnlockedProperties() {
635 if (!unlocked_properties_
)
637 if (unlocked_properties_
->background_is_hidden
) {
639 // Restore background visibility.
640 animator_
->StartAnimation(
641 internal::SessionStateAnimator::DESKTOP_BACKGROUND
,
642 internal::SessionStateAnimator::ANIMATION_FADE_IN
,
643 internal::SessionStateAnimator::ANIMATION_SPEED_IMMEDIATE
);
645 unlocked_properties_
.reset();
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
,
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
,