1 // Copyright (c) 2012 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/session_state_controller_impl2.h"
7 #include "ash/ash_switches.h"
8 #include "ash/cancel_mode.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.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"
21 #if defined(OS_CHROMEOS)
22 #include "base/chromeos/chromeos_version.h"
29 aura::Window
* GetBackground() {
30 aura::RootWindow
* root_window
= Shell::GetPrimaryRootWindow();
31 return Shell::GetContainer(root_window
,
32 internal::kShellWindowId_DesktopBackgroundContainer
);
35 bool IsBackgroundHidden() {
36 return !GetBackground()->IsVisible();
39 void ShowBackground() {
40 ui::ScopedLayerAnimationSettings
settings(
41 GetBackground()->layer()->GetAnimator());
42 settings
.SetTransitionDuration(base::TimeDelta());
43 GetBackground()->Show();
46 void HideBackground() {
47 ui::ScopedLayerAnimationSettings
settings(
48 GetBackground()->layer()->GetAnimator());
49 settings
.SetTransitionDuration(base::TimeDelta());
50 GetBackground()->Hide();
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.
62 class AnimationFinishedObserver
: public ui::LayerAnimationObserver
{
64 explicit AnimationFinishedObserver(base::Closure
&callback
)
65 : callback_(callback
),
66 sequences_attached_(0),
67 sequences_completed_(0),
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
79 // Unpauses observer. It does a check and calls callback if conditions are
85 if (sequences_completed_
== sequences_attached_
) {
92 virtual ~AnimationFinishedObserver() {
95 // LayerAnimationObserver implementation
96 virtual void OnLayerAnimationEnded(
97 ui::LayerAnimationSequence
* sequence
) OVERRIDE
{
98 sequences_completed_
++;
99 if ((sequences_completed_
== sequences_attached_
) && !paused_
) {
105 virtual void OnLayerAnimationAborted(
106 ui::LayerAnimationSequence
* sequence
) OVERRIDE
{
107 sequences_completed_
++;
108 if ((sequences_completed_
== sequences_attached_
) && !paused_
)
112 virtual void OnLayerAnimationScheduled(
113 ui::LayerAnimationSequence
* sequence
) OVERRIDE
{
116 virtual void OnAttachedToSequence(
117 ui::LayerAnimationSequence
* sequence
) OVERRIDE
{
118 LayerAnimationObserver::OnAttachedToSequence(sequence
);
119 sequences_attached_
++;
122 // Callback to be called.
123 base::Closure callback_
;
125 // Number of sequences this observer was attached to.
126 int sequences_attached_
;
128 // Number of sequences either ended or aborted.
129 int sequences_completed_
;
133 DISALLOW_COPY_AND_ASSIGN(AnimationFinishedObserver
);
138 SessionStateControllerImpl2::TestApi::TestApi(
139 SessionStateControllerImpl2
* controller
)
140 : controller_(controller
) {
143 SessionStateControllerImpl2::TestApi::~TestApi() {
146 SessionStateControllerImpl2::SessionStateControllerImpl2()
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);
156 SessionStateControllerImpl2::~SessionStateControllerImpl2() {
157 Shell::GetPrimaryRootWindow()->RemoveRootWindowObserver(this);
160 void SessionStateControllerImpl2::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
);
167 void SessionStateControllerImpl2::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
);
183 void SessionStateControllerImpl2::OnLockStateChanged(bool locked
) {
184 if (shutting_down_
|| (system_is_locked_
== locked
))
187 system_is_locked_
= locked
;
190 StartPostLockAnimation();
191 lock_fail_timer_
.Stop();
193 StartUnlockAnimationAfterUIDestroyed();
197 void SessionStateControllerImpl2::SetLockScreenDisplayedCallback(
198 base::Closure
& callback
) {
199 lock_screen_displayed_callback_
= callback
;
202 void SessionStateControllerImpl2::OnStartingLock() {
203 if (shutting_down_
|| system_is_locked_
)
207 StartImmediatePreLockAnimation(false /* request_lock_on_completion */);
210 void SessionStateControllerImpl2::StartLockAnimationAndLockImmediately() {
213 StartImmediatePreLockAnimation(true /* request_lock_on_completion */);
216 void SessionStateControllerImpl2::StartLockAnimation(bool shutdown_after_lock
) {
219 shutdown_after_lock_
= shutdown_after_lock
;
220 can_cancel_lock_animation_
= true;
222 StartCancellablePreLockAnimation();
225 bool SessionStateControllerImpl2::LockRequested() {
226 return lock_fail_timer_
.IsRunning();
229 bool SessionStateControllerImpl2::ShutdownRequested() {
230 return shutting_down_
;
233 bool SessionStateControllerImpl2::CanCancelLockAnimation() {
234 return can_cancel_lock_animation_
;
237 void SessionStateControllerImpl2::CancelLockAnimation() {
238 if (!CanCancelLockAnimation())
240 shutdown_after_lock_
= false;
241 animating_lock_
= false;
242 CancelPreLockAnimation();
245 bool SessionStateControllerImpl2::CanCancelShutdownAnimation() {
246 return pre_shutdown_timer_
.IsRunning() ||
247 shutdown_after_lock_
||
248 lock_to_shutdown_timer_
.IsRunning();
251 void SessionStateControllerImpl2::StartShutdownAnimation() {
252 StartCancellableShutdownAnimation();
255 void SessionStateControllerImpl2::CancelShutdownAnimation() {
256 if (!CanCancelShutdownAnimation())
258 if (lock_to_shutdown_timer_
.IsRunning()) {
259 lock_to_shutdown_timer_
.Stop();
262 if (shutdown_after_lock_
) {
263 shutdown_after_lock_
= false;
267 animator_
->StartGlobalAnimation(
268 internal::SessionStateAnimator::ANIMATION_UNDO_GRAYSCALE_BRIGHTNESS
,
269 internal::SessionStateAnimator::ANIMATION_SPEED_REVERT_SHUTDOWN
);
270 pre_shutdown_timer_
.Stop();
273 void SessionStateControllerImpl2::RequestShutdown() {
275 RequestShutdownImpl();
278 void SessionStateControllerImpl2::RequestShutdownImpl() {
279 DCHECK(!shutting_down_
);
280 shutting_down_
= true;
282 Shell
* shell
= ash::Shell::GetInstance();
283 shell
->env_filter()->set_cursor_hidden_by_filter(false);
284 shell
->cursor_manager()->HideCursor();
286 StartShutdownAnimationImpl();
289 void SessionStateControllerImpl2::OnRootWindowHostCloseRequested(
290 const aura::RootWindow
*) {
291 Shell::GetInstance()->delegate()->Exit();
294 void SessionStateControllerImpl2::OnLockFailTimeout() {
295 DCHECK(!system_is_locked_
);
296 // Undo lock animation.
297 StartUnlockAnimationAfterUIDestroyed();
300 void SessionStateControllerImpl2::StartLockToShutdownTimer() {
301 shutdown_after_lock_
= false;
302 lock_to_shutdown_timer_
.Stop();
303 lock_to_shutdown_timer_
.Start(
305 base::TimeDelta::FromMilliseconds(kLockToShutdownTimeoutMs
),
306 this, &SessionStateControllerImpl2::OnLockToShutdownTimeout
);
309 void SessionStateControllerImpl2::OnLockToShutdownTimeout() {
310 DCHECK(system_is_locked_
);
311 StartCancellableShutdownAnimation();
314 void SessionStateControllerImpl2::StartCancellableShutdownAnimation() {
315 Shell
* shell
= ash::Shell::GetInstance();
316 // Hide cursor, but let it reappear if the mouse moves.
317 shell
->env_filter()->set_cursor_hidden_by_filter(true);
318 shell
->cursor_manager()->HideCursor();
320 animator_
->StartGlobalAnimation(
321 internal::SessionStateAnimator::ANIMATION_GRAYSCALE_BRIGHTNESS
,
322 internal::SessionStateAnimator::ANIMATION_SPEED_SHUTDOWN
);
323 StartPreShutdownAnimationTimer();
326 void SessionStateControllerImpl2::StartShutdownAnimationImpl() {
327 animator_
->StartGlobalAnimation(
328 internal::SessionStateAnimator::ANIMATION_GRAYSCALE_BRIGHTNESS
,
329 internal::SessionStateAnimator::ANIMATION_SPEED_SHUTDOWN
);
330 StartRealShutdownTimer(true);
333 void SessionStateControllerImpl2::StartPreShutdownAnimationTimer() {
334 pre_shutdown_timer_
.Stop();
335 pre_shutdown_timer_
.Start(
338 GetDuration(internal::SessionStateAnimator::ANIMATION_SPEED_SHUTDOWN
),
340 &SessionStateControllerImpl2::OnPreShutdownAnimationTimeout
);
343 void SessionStateControllerImpl2::OnPreShutdownAnimationTimeout() {
344 shutting_down_
= true;
346 Shell
* shell
= ash::Shell::GetInstance();
347 shell
->env_filter()->set_cursor_hidden_by_filter(false);
348 shell
->cursor_manager()->HideCursor();
350 StartRealShutdownTimer(false);
353 void SessionStateControllerImpl2::StartRealShutdownTimer(
354 bool with_animation_time
) {
355 base::TimeDelta duration
=
356 base::TimeDelta::FromMilliseconds(kShutdownRequestDelayMs
);
357 if (with_animation_time
) {
358 duration
+= animator_
->GetDuration(
359 internal::SessionStateAnimator::ANIMATION_SPEED_SHUTDOWN
);
361 real_shutdown_timer_
.Start(
365 &SessionStateControllerImpl2::OnRealShutdownTimeout
);
368 void SessionStateControllerImpl2::OnRealShutdownTimeout() {
369 DCHECK(shutting_down_
);
370 #if defined(OS_CHROMEOS)
371 if (!base::chromeos::IsRunningOnChromeOS()) {
372 ShellDelegate
* delegate
= Shell::GetInstance()->delegate();
379 Shell::GetInstance()->delegate()->RecordUserMetricsAction(
380 UMA_ACCEL_SHUT_DOWN_POWER_BUTTON
);
381 delegate_
->RequestShutdown();
384 void SessionStateControllerImpl2::OnLockScreenHide(
385 base::Callback
<void(void)>& callback
) {
386 StartUnlockAnimationBeforeUIDestroyed(callback
);
389 void SessionStateControllerImpl2::LockAnimationCancelled() {
390 can_cancel_lock_animation_
= false;
391 RestoreUnlockedProperties();
394 void SessionStateControllerImpl2::PreLockAnimationFinished(bool request_lock
) {
395 can_cancel_lock_animation_
= false;
398 Shell::GetInstance()->delegate()->RecordUserMetricsAction(
399 shutdown_after_lock_
?
400 UMA_ACCEL_LOCK_SCREEN_POWER_BUTTON
:
401 UMA_ACCEL_LOCK_SCREEN_LOCK_BUTTON
);
402 delegate_
->RequestLockScreen();
405 lock_fail_timer_
.Start(
407 base::TimeDelta::FromMilliseconds(kLockFailTimeoutMs
),
409 &SessionStateControllerImpl2::OnLockFailTimeout
);
412 void SessionStateControllerImpl2::PostLockAnimationFinished() {
413 animating_lock_
= false;
415 FOR_EACH_OBSERVER(SessionStateObserver
, observers_
,
417 SessionStateObserver::EVENT_LOCK_ANIMATION_FINISHED
));
418 if (!lock_screen_displayed_callback_
.is_null()) {
419 lock_screen_displayed_callback_
.Run();
420 lock_screen_displayed_callback_
.Reset();
422 if (shutdown_after_lock_
) {
423 shutdown_after_lock_
= false;
424 StartLockToShutdownTimer();
428 void SessionStateControllerImpl2::UnlockAnimationAfterUIDestroyedFinished() {
429 RestoreUnlockedProperties();
432 void SessionStateControllerImpl2::StartImmediatePreLockAnimation(
433 bool request_lock_on_completion
) {
434 animating_lock_
= true;
436 StoreUnlockedProperties();
438 base::Closure next_animation_starter
=
439 base::Bind(&SessionStateControllerImpl2::PreLockAnimationFinished
,
440 base::Unretained(this), request_lock_on_completion
);
441 AnimationFinishedObserver
* observer
=
442 new AnimationFinishedObserver(next_animation_starter
);
446 animator_
->StartAnimationWithObserver(
447 internal::SessionStateAnimator::NON_LOCK_SCREEN_CONTAINERS
,
448 internal::SessionStateAnimator::ANIMATION_LIFT
,
449 internal::SessionStateAnimator::ANIMATION_SPEED_MOVE_WINDOWS
,
451 animator_
->StartAnimationWithObserver(
452 internal::SessionStateAnimator::LAUNCHER
,
453 internal::SessionStateAnimator::ANIMATION_FADE_OUT
,
454 internal::SessionStateAnimator::ANIMATION_SPEED_MOVE_WINDOWS
,
456 // Hide the screen locker containers so we can raise them later.
457 animator_
->StartAnimation(
458 internal::SessionStateAnimator::LOCK_SCREEN_CONTAINERS
,
459 internal::SessionStateAnimator::ANIMATION_HIDE_IMMEDIATELY
,
460 internal::SessionStateAnimator::ANIMATION_SPEED_IMMEDIATE
);
461 AnimateBackgroundAppearanceIfNecessary(
462 internal::SessionStateAnimator::ANIMATION_SPEED_MOVE_WINDOWS
,
467 DispatchCancelMode();
468 FOR_EACH_OBSERVER(SessionStateObserver
, observers_
,
469 OnSessionStateEvent(SessionStateObserver::EVENT_LOCK_ANIMATION_STARTED
));
472 void SessionStateControllerImpl2::StartCancellablePreLockAnimation() {
473 animating_lock_
= true;
474 StoreUnlockedProperties();
476 base::Closure next_animation_starter
=
477 base::Bind(&SessionStateControllerImpl2::PreLockAnimationFinished
,
478 base::Unretained(this), true /* request_lock */);
479 AnimationFinishedObserver
* observer
=
480 new AnimationFinishedObserver(next_animation_starter
);
484 animator_
->StartAnimationWithObserver(
485 internal::SessionStateAnimator::NON_LOCK_SCREEN_CONTAINERS
,
486 internal::SessionStateAnimator::ANIMATION_LIFT
,
487 internal::SessionStateAnimator::ANIMATION_SPEED_UNDOABLE
,
489 animator_
->StartAnimationWithObserver(
490 internal::SessionStateAnimator::LAUNCHER
,
491 internal::SessionStateAnimator::ANIMATION_FADE_OUT
,
492 internal::SessionStateAnimator::ANIMATION_SPEED_UNDOABLE
,
494 // Hide the screen locker containers so we can raise them later.
495 animator_
->StartAnimation(
496 internal::SessionStateAnimator::LOCK_SCREEN_CONTAINERS
,
497 internal::SessionStateAnimator::ANIMATION_HIDE_IMMEDIATELY
,
498 internal::SessionStateAnimator::ANIMATION_SPEED_IMMEDIATE
);
499 AnimateBackgroundAppearanceIfNecessary(
500 internal::SessionStateAnimator::ANIMATION_SPEED_UNDOABLE
,
503 DispatchCancelMode();
504 FOR_EACH_OBSERVER(SessionStateObserver
, observers_
,
506 SessionStateObserver::EVENT_PRELOCK_ANIMATION_STARTED
));
510 void SessionStateControllerImpl2::CancelPreLockAnimation() {
511 base::Closure next_animation_starter
=
512 base::Bind(&SessionStateControllerImpl2::LockAnimationCancelled
,
513 base::Unretained(this));
514 AnimationFinishedObserver
* observer
=
515 new AnimationFinishedObserver(next_animation_starter
);
519 animator_
->StartAnimationWithObserver(
520 internal::SessionStateAnimator::NON_LOCK_SCREEN_CONTAINERS
,
521 internal::SessionStateAnimator::ANIMATION_UNDO_LIFT
,
522 internal::SessionStateAnimator::ANIMATION_SPEED_UNDO_MOVE_WINDOWS
,
524 animator_
->StartAnimationWithObserver(
525 internal::SessionStateAnimator::LAUNCHER
,
526 internal::SessionStateAnimator::ANIMATION_FADE_IN
,
527 internal::SessionStateAnimator::ANIMATION_SPEED_UNDO_MOVE_WINDOWS
,
529 AnimateBackgroundHidingIfNecessary(
530 internal::SessionStateAnimator::ANIMATION_SPEED_UNDO_MOVE_WINDOWS
,
536 void SessionStateControllerImpl2::StartPostLockAnimation() {
537 base::Closure next_animation_starter
=
538 base::Bind(&SessionStateControllerImpl2::PostLockAnimationFinished
,
539 base::Unretained(this));
541 AnimationFinishedObserver
* observer
=
542 new AnimationFinishedObserver(next_animation_starter
);
545 animator_
->StartAnimationWithObserver(
546 internal::SessionStateAnimator::LOCK_SCREEN_CONTAINERS
,
547 internal::SessionStateAnimator::ANIMATION_RAISE_TO_SCREEN
,
548 internal::SessionStateAnimator::ANIMATION_SPEED_MOVE_WINDOWS
,
553 void SessionStateControllerImpl2::StartUnlockAnimationBeforeUIDestroyed(
554 base::Closure
& callback
) {
555 animator_
->StartAnimationWithCallback(
556 internal::SessionStateAnimator::LOCK_SCREEN_CONTAINERS
,
557 internal::SessionStateAnimator::ANIMATION_LIFT
,
558 internal::SessionStateAnimator::ANIMATION_SPEED_MOVE_WINDOWS
,
562 void SessionStateControllerImpl2::StartUnlockAnimationAfterUIDestroyed() {
563 base::Closure next_animation_starter
=
565 &SessionStateControllerImpl2::UnlockAnimationAfterUIDestroyedFinished
,
566 base::Unretained(this));
568 AnimationFinishedObserver
* observer
=
569 new AnimationFinishedObserver(next_animation_starter
);
573 animator_
->StartAnimationWithObserver(
574 internal::SessionStateAnimator::NON_LOCK_SCREEN_CONTAINERS
,
575 internal::SessionStateAnimator::ANIMATION_DROP
,
576 internal::SessionStateAnimator::ANIMATION_SPEED_MOVE_WINDOWS
,
578 animator_
->StartAnimationWithObserver(
579 internal::SessionStateAnimator::LAUNCHER
,
580 internal::SessionStateAnimator::ANIMATION_FADE_IN
,
581 internal::SessionStateAnimator::ANIMATION_SPEED_MOVE_WINDOWS
,
583 AnimateBackgroundHidingIfNecessary(
584 internal::SessionStateAnimator::ANIMATION_SPEED_MOVE_WINDOWS
,
589 void SessionStateControllerImpl2::StoreUnlockedProperties() {
590 if (!unlocked_properties_
.get()) {
591 unlocked_properties_
.reset(new UnlockedStateProperties());
592 unlocked_properties_
->background_is_hidden
= IsBackgroundHidden();
594 if (unlocked_properties_
->background_is_hidden
) {
595 // Hide background so that it can be animated later.
596 animator_
->StartAnimation(
597 internal::SessionStateAnimator::DESKTOP_BACKGROUND
,
598 internal::SessionStateAnimator::ANIMATION_HIDE_IMMEDIATELY
,
599 internal::SessionStateAnimator::ANIMATION_SPEED_IMMEDIATE
);
604 void SessionStateControllerImpl2::RestoreUnlockedProperties() {
605 if (!unlocked_properties_
.get())
607 if (unlocked_properties_
->background_is_hidden
) {
609 // Restore background visibility.
610 animator_
->StartAnimation(
611 internal::SessionStateAnimator::DESKTOP_BACKGROUND
,
612 internal::SessionStateAnimator::ANIMATION_FADE_IN
,
613 internal::SessionStateAnimator::ANIMATION_SPEED_IMMEDIATE
);
615 unlocked_properties_
.reset();
618 void SessionStateControllerImpl2::AnimateBackgroundAppearanceIfNecessary(
619 internal::SessionStateAnimator::AnimationSpeed speed
,
620 ui::LayerAnimationObserver
* observer
) {
621 if (unlocked_properties_
.get() &&
622 unlocked_properties_
->background_is_hidden
) {
623 animator_
->StartAnimationWithObserver(
624 internal::SessionStateAnimator::DESKTOP_BACKGROUND
,
625 internal::SessionStateAnimator::ANIMATION_FADE_IN
,
631 void SessionStateControllerImpl2::AnimateBackgroundHidingIfNecessary(
632 internal::SessionStateAnimator::AnimationSpeed speed
,
633 ui::LayerAnimationObserver
* observer
) {
634 if (unlocked_properties_
.get() &&
635 unlocked_properties_
->background_is_hidden
) {
636 animator_
->StartAnimationWithObserver(
637 internal::SessionStateAnimator::DESKTOP_BACKGROUND
,
638 internal::SessionStateAnimator::ANIMATION_FADE_OUT
,