Separate Simple Backend creation from initialization.
[chromium-blink-merge.git] / ash / wm / session_state_controller_impl2.cc
blob4e533a4a9c8472dc24aa768a51d0ef1c8b5b0827
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"
9 #include "ash/shell.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"
23 #endif
25 namespace ash {
27 namespace {
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 {
63 public:
64 explicit AnimationFinishedObserver(base::Closure &callback)
65 : callback_(callback),
66 sequences_attached_(0),
67 sequences_completed_(0),
68 paused_(false) {
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
74 // immediate.
75 void Pause() {
76 paused_ = true;
79 // Unpauses observer. It does a check and calls callback if conditions are
80 // met.
81 void Unpause() {
82 if (!paused_)
83 return;
84 paused_ = false;
85 if (sequences_completed_ == sequences_attached_) {
86 callback_.Run();
87 delete this;
91 private:
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_) {
100 callback_.Run();
101 delete this;
105 virtual void OnLayerAnimationAborted(
106 ui::LayerAnimationSequence* sequence) OVERRIDE {
107 sequences_completed_++;
108 if ((sequences_completed_ == sequences_attached_) && !paused_)
109 delete this;
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_;
131 bool paused_;
133 DISALLOW_COPY_AND_ASSIGN(AnimationFinishedObserver);
136 } // namespace
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))
185 return;
187 system_is_locked_ = locked;
189 if (locked) {
190 StartPostLockAnimation();
191 lock_fail_timer_.Stop();
192 } else {
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_)
204 return;
205 if (animating_lock_)
206 return;
207 StartImmediatePreLockAnimation(false /* request_lock_on_completion */);
210 void SessionStateControllerImpl2::StartLockAnimationAndLockImmediately() {
211 if (animating_lock_)
212 return;
213 StartImmediatePreLockAnimation(true /* request_lock_on_completion */);
216 void SessionStateControllerImpl2::StartLockAnimation(bool shutdown_after_lock) {
217 if (animating_lock_)
218 return;
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())
239 return;
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())
257 return;
258 if (lock_to_shutdown_timer_.IsRunning()) {
259 lock_to_shutdown_timer_.Stop();
260 return;
262 if (shutdown_after_lock_) {
263 shutdown_after_lock_ = false;
264 return;
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() {
274 if (!shutting_down_)
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(
304 FROM_HERE,
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(
336 FROM_HERE,
337 animator_->
338 GetDuration(internal::SessionStateAnimator::ANIMATION_SPEED_SHUTDOWN),
339 this,
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(
362 FROM_HERE,
363 duration,
364 this,
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();
373 if (delegate) {
374 delegate->Exit();
375 return;
378 #endif
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;
397 if (request_lock) {
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(
406 FROM_HERE,
407 base::TimeDelta::FromMilliseconds(kLockFailTimeoutMs),
408 this,
409 &SessionStateControllerImpl2::OnLockFailTimeout);
412 void SessionStateControllerImpl2::PostLockAnimationFinished() {
413 animating_lock_ = false;
415 FOR_EACH_OBSERVER(SessionStateObserver, observers_,
416 OnSessionStateEvent(
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);
444 observer->Pause();
446 animator_->StartAnimationWithObserver(
447 internal::SessionStateAnimator::NON_LOCK_SCREEN_CONTAINERS,
448 internal::SessionStateAnimator::ANIMATION_LIFT,
449 internal::SessionStateAnimator::ANIMATION_SPEED_MOVE_WINDOWS,
450 observer);
451 animator_->StartAnimationWithObserver(
452 internal::SessionStateAnimator::LAUNCHER,
453 internal::SessionStateAnimator::ANIMATION_FADE_OUT,
454 internal::SessionStateAnimator::ANIMATION_SPEED_MOVE_WINDOWS,
455 observer);
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,
463 observer);
465 observer->Unpause();
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);
482 observer->Pause();
484 animator_->StartAnimationWithObserver(
485 internal::SessionStateAnimator::NON_LOCK_SCREEN_CONTAINERS,
486 internal::SessionStateAnimator::ANIMATION_LIFT,
487 internal::SessionStateAnimator::ANIMATION_SPEED_UNDOABLE,
488 observer);
489 animator_->StartAnimationWithObserver(
490 internal::SessionStateAnimator::LAUNCHER,
491 internal::SessionStateAnimator::ANIMATION_FADE_OUT,
492 internal::SessionStateAnimator::ANIMATION_SPEED_UNDOABLE,
493 observer);
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,
501 observer);
503 DispatchCancelMode();
504 FOR_EACH_OBSERVER(SessionStateObserver, observers_,
505 OnSessionStateEvent(
506 SessionStateObserver::EVENT_PRELOCK_ANIMATION_STARTED));
507 observer->Unpause();
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);
517 observer->Pause();
519 animator_->StartAnimationWithObserver(
520 internal::SessionStateAnimator::NON_LOCK_SCREEN_CONTAINERS,
521 internal::SessionStateAnimator::ANIMATION_UNDO_LIFT,
522 internal::SessionStateAnimator::ANIMATION_SPEED_UNDO_MOVE_WINDOWS,
523 observer);
524 animator_->StartAnimationWithObserver(
525 internal::SessionStateAnimator::LAUNCHER,
526 internal::SessionStateAnimator::ANIMATION_FADE_IN,
527 internal::SessionStateAnimator::ANIMATION_SPEED_UNDO_MOVE_WINDOWS,
528 observer);
529 AnimateBackgroundHidingIfNecessary(
530 internal::SessionStateAnimator::ANIMATION_SPEED_UNDO_MOVE_WINDOWS,
531 observer);
533 observer->Unpause();
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);
544 observer->Pause();
545 animator_->StartAnimationWithObserver(
546 internal::SessionStateAnimator::LOCK_SCREEN_CONTAINERS,
547 internal::SessionStateAnimator::ANIMATION_RAISE_TO_SCREEN,
548 internal::SessionStateAnimator::ANIMATION_SPEED_MOVE_WINDOWS,
549 observer);
550 observer->Unpause();
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,
559 callback);
562 void SessionStateControllerImpl2::StartUnlockAnimationAfterUIDestroyed() {
563 base::Closure next_animation_starter =
564 base::Bind(
565 &SessionStateControllerImpl2::UnlockAnimationAfterUIDestroyedFinished,
566 base::Unretained(this));
568 AnimationFinishedObserver* observer =
569 new AnimationFinishedObserver(next_animation_starter);
571 observer->Pause();
573 animator_->StartAnimationWithObserver(
574 internal::SessionStateAnimator::NON_LOCK_SCREEN_CONTAINERS,
575 internal::SessionStateAnimator::ANIMATION_DROP,
576 internal::SessionStateAnimator::ANIMATION_SPEED_MOVE_WINDOWS,
577 observer);
578 animator_->StartAnimationWithObserver(
579 internal::SessionStateAnimator::LAUNCHER,
580 internal::SessionStateAnimator::ANIMATION_FADE_IN,
581 internal::SessionStateAnimator::ANIMATION_SPEED_MOVE_WINDOWS,
582 observer);
583 AnimateBackgroundHidingIfNecessary(
584 internal::SessionStateAnimator::ANIMATION_SPEED_MOVE_WINDOWS,
585 observer);
586 observer->Unpause();
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);
600 ShowBackground();
604 void SessionStateControllerImpl2::RestoreUnlockedProperties() {
605 if (!unlocked_properties_.get())
606 return;
607 if (unlocked_properties_->background_is_hidden) {
608 HideBackground();
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,
626 speed,
627 observer);
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,
639 speed,
640 observer);
644 } // namespace ash