Put WeakPtrFactory member last in USBEventRouter
[chromium-blink-merge.git] / ash / wm / lock_state_controller.cc
blob0bf6d30043b3086054c338eafa86f338e0808975
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"
7 #include <algorithm>
8 #include <string>
10 #include "ash/accessibility_delegate.h"
11 #include "ash/ash_switches.h"
12 #include "ash/cancel_mode.h"
13 #include "ash/metrics/user_metrics_recorder.h"
14 #include "ash/shell.h"
15 #include "ash/shell_delegate.h"
16 #include "ash/shell_window_ids.h"
17 #include "ash/wm/session_state_animator.h"
18 #include "ash/wm/session_state_animator_impl.h"
19 #include "base/bind.h"
20 #include "base/bind_helpers.h"
21 #include "base/command_line.h"
22 #include "base/location.h"
23 #include "base/logging.h"
24 #include "base/strings/string_util.h"
25 #include "base/timer/timer.h"
26 #include "ui/aura/window_tree_host.h"
27 #include "ui/views/controls/menu/menu_controller.h"
28 #include "ui/wm/core/compound_event_filter.h"
30 #if defined(OS_CHROMEOS)
31 #include "base/sys_info.h"
32 #include "media/audio/sounds/sounds_manager.h"
33 #endif
35 #if defined(OS_CHROMEOS)
36 using media::SoundsManager;
37 #endif
39 namespace ash {
41 namespace {
43 #if defined(OS_CHROMEOS)
44 const int kMaxShutdownSoundDurationMs = 1500;
45 #endif
47 } // namespace
49 const int LockStateController::kLockTimeoutMs = 400;
50 const int LockStateController::kShutdownTimeoutMs = 400;
51 const int LockStateController::kLockFailTimeoutMs = 8000;
52 const int LockStateController::kLockToShutdownTimeoutMs = 150;
53 const int LockStateController::kShutdownRequestDelayMs = 50;
55 LockStateController::TestApi::TestApi(LockStateController* controller)
56 : controller_(controller) {
59 LockStateController::TestApi::~TestApi() {
62 LockStateController::LockStateController()
63 : animator_(new SessionStateAnimatorImpl()),
64 login_status_(user::LOGGED_IN_NONE),
65 system_is_locked_(false),
66 shutting_down_(false),
67 shutdown_after_lock_(false),
68 animating_lock_(false),
69 can_cancel_lock_animation_(false),
70 weak_ptr_factory_(this) {
71 Shell::GetPrimaryRootWindow()->GetHost()->AddObserver(this);
74 LockStateController::~LockStateController() {
75 Shell::GetPrimaryRootWindow()->GetHost()->RemoveObserver(this);
78 void LockStateController::SetDelegate(
79 scoped_ptr<LockStateControllerDelegate> delegate) {
80 delegate_ = delegate.Pass();
83 void LockStateController::AddObserver(LockStateObserver* observer) {
84 observers_.AddObserver(observer);
87 void LockStateController::RemoveObserver(LockStateObserver* observer) {
88 observers_.RemoveObserver(observer);
91 bool LockStateController::HasObserver(const LockStateObserver* observer) const {
92 return observers_.HasObserver(observer);
95 void LockStateController::StartLockAnimation(
96 bool shutdown_after_lock) {
97 if (animating_lock_)
98 return;
99 shutdown_after_lock_ = shutdown_after_lock;
100 can_cancel_lock_animation_ = true;
102 StartCancellablePreLockAnimation();
105 void LockStateController::StartShutdownAnimation() {
106 StartCancellableShutdownAnimation();
109 void LockStateController::StartLockAnimationAndLockImmediately(
110 bool shutdown_after_lock) {
111 if (animating_lock_)
112 return;
113 shutdown_after_lock_ = shutdown_after_lock;
114 StartImmediatePreLockAnimation(true /* request_lock_on_completion */);
117 bool LockStateController::LockRequested() {
118 return lock_fail_timer_.IsRunning();
121 bool LockStateController::ShutdownRequested() {
122 return shutting_down_;
125 bool LockStateController::CanCancelLockAnimation() {
126 return can_cancel_lock_animation_;
129 void LockStateController::CancelLockAnimation() {
130 if (!CanCancelLockAnimation())
131 return;
132 shutdown_after_lock_ = false;
133 animating_lock_ = false;
134 CancelPreLockAnimation();
137 bool LockStateController::CanCancelShutdownAnimation() {
138 return pre_shutdown_timer_.IsRunning() ||
139 shutdown_after_lock_ ||
140 lock_to_shutdown_timer_.IsRunning();
143 void LockStateController::CancelShutdownAnimation() {
144 if (!CanCancelShutdownAnimation())
145 return;
146 if (lock_to_shutdown_timer_.IsRunning()) {
147 lock_to_shutdown_timer_.Stop();
148 return;
150 if (shutdown_after_lock_) {
151 shutdown_after_lock_ = false;
152 return;
155 animator_->StartAnimation(
156 SessionStateAnimator::ROOT_CONTAINER,
157 SessionStateAnimator::ANIMATION_UNDO_GRAYSCALE_BRIGHTNESS,
158 SessionStateAnimator::ANIMATION_SPEED_REVERT_SHUTDOWN);
159 pre_shutdown_timer_.Stop();
162 void LockStateController::OnStartingLock() {
163 if (shutting_down_ || system_is_locked_)
164 return;
165 if (animating_lock_)
166 return;
167 StartImmediatePreLockAnimation(false /* request_lock_on_completion */);
170 void LockStateController::RequestShutdown(ShutdownMode mode) {
171 if (shutting_down_)
172 return;
174 shutting_down_ = true;
176 Shell* shell = ash::Shell::GetInstance();
177 shell->cursor_manager()->HideCursor();
178 shell->cursor_manager()->LockCursor();
180 animator_->StartAnimation(
181 SessionStateAnimator::ROOT_CONTAINER,
182 SessionStateAnimator::ANIMATION_GRAYSCALE_BRIGHTNESS,
183 SessionStateAnimator::ANIMATION_SPEED_SHUTDOWN);
184 StartRealShutdownTimer(true, mode);
187 void LockStateController::OnLockScreenHide(
188 base::Callback<void(void)>& callback) {
189 StartUnlockAnimationBeforeUIDestroyed(callback);
192 void LockStateController::SetLockScreenDisplayedCallback(
193 const base::Closure& callback) {
194 lock_screen_displayed_callback_ = callback;
197 void LockStateController::OnHostCloseRequested(
198 const aura::WindowTreeHost* host) {
199 Shell::GetInstance()->delegate()->Exit();
202 void LockStateController::OnLoginStateChanged(
203 user::LoginStatus status) {
204 if (status != user::LOGGED_IN_LOCKED)
205 login_status_ = status;
206 system_is_locked_ = (status == user::LOGGED_IN_LOCKED);
209 void LockStateController::OnAppTerminating() {
210 // If we hear that Chrome is exiting but didn't request it ourselves, all we
211 // can really hope for is that we'll have time to clear the screen.
212 // This is also the case when the user signs off.
213 if (!shutting_down_) {
214 shutting_down_ = true;
215 Shell* shell = ash::Shell::GetInstance();
216 shell->cursor_manager()->HideCursor();
217 shell->cursor_manager()->LockCursor();
218 animator_->StartAnimation(SessionStateAnimator::kAllNonRootContainersMask,
219 SessionStateAnimator::ANIMATION_HIDE_IMMEDIATELY,
220 SessionStateAnimator::ANIMATION_SPEED_IMMEDIATE);
224 void LockStateController::OnLockStateChanged(bool locked) {
225 VLOG(1) << "OnLockStateChanged " << locked;
226 if (shutting_down_ || (system_is_locked_ == locked))
227 return;
229 system_is_locked_ = locked;
231 if (locked) {
232 StartPostLockAnimation();
233 lock_fail_timer_.Stop();
234 } else {
235 StartUnlockAnimationAfterUIDestroyed();
239 void LockStateController::OnLockFailTimeout() {
240 DCHECK(!system_is_locked_);
241 LOG(FATAL) << "Screen lock took too long; crashing intentionally";
244 void LockStateController::StartLockToShutdownTimer() {
245 shutdown_after_lock_ = false;
246 lock_to_shutdown_timer_.Stop();
247 lock_to_shutdown_timer_.Start(
248 FROM_HERE,
249 base::TimeDelta::FromMilliseconds(kLockToShutdownTimeoutMs),
250 this, &LockStateController::OnLockToShutdownTimeout);
253 void LockStateController::OnLockToShutdownTimeout() {
254 DCHECK(system_is_locked_);
255 StartCancellableShutdownAnimation();
258 void LockStateController::StartPreShutdownAnimationTimer() {
259 pre_shutdown_timer_.Stop();
260 pre_shutdown_timer_.Start(
261 FROM_HERE,
262 animator_->GetDuration(SessionStateAnimator::ANIMATION_SPEED_SHUTDOWN),
263 this,
264 &LockStateController::OnPreShutdownAnimationTimeout);
267 void LockStateController::OnPreShutdownAnimationTimeout() {
268 VLOG(1) << "OnPreShutdownAnimationTimeout";
269 shutting_down_ = true;
271 Shell* shell = ash::Shell::GetInstance();
272 shell->cursor_manager()->HideCursor();
274 StartRealShutdownTimer(false, POWER_OFF);
277 void LockStateController::StartRealShutdownTimer(bool with_animation_time,
278 ShutdownMode shutdown_mode) {
279 base::TimeDelta duration =
280 base::TimeDelta::FromMilliseconds(kShutdownRequestDelayMs);
281 if (with_animation_time) {
282 duration +=
283 animator_->GetDuration(SessionStateAnimator::ANIMATION_SPEED_SHUTDOWN);
286 #if defined(OS_CHROMEOS)
287 const AccessibilityDelegate* const delegate =
288 Shell::GetInstance()->accessibility_delegate();
289 base::TimeDelta sound_duration = delegate->PlayShutdownSound();
290 sound_duration =
291 std::min(sound_duration,
292 base::TimeDelta::FromMilliseconds(kMaxShutdownSoundDurationMs));
293 duration = std::max(duration, sound_duration);
294 #endif
296 real_shutdown_timer_.Start(
297 FROM_HERE, duration, base::Bind(&LockStateController::OnRealPowerTimeout,
298 base::Unretained(this), shutdown_mode));
301 void LockStateController::OnRealPowerTimeout(ShutdownMode shutdown_mode) {
302 VLOG(1) << "OnRealPowerTimeout";
303 DCHECK(shutting_down_);
304 #if defined(OS_CHROMEOS)
305 if (!base::SysInfo::IsRunningOnChromeOS()) {
306 ShellDelegate* delegate = Shell::GetInstance()->delegate();
307 if (delegate) {
308 delegate->Exit();
309 return;
312 #endif
313 if (shutdown_mode == POWER_OFF) {
314 Shell::GetInstance()->metrics()->RecordUserMetricsAction(
315 UMA_ACCEL_SHUT_DOWN_POWER_BUTTON);
316 delegate_->RequestShutdown();
317 return;
319 Shell::GetInstance()->metrics()->RecordUserMetricsAction(
320 UMA_ACCEL_RESTART_POWER_BUTTON);
321 delegate_->RequestRestart();
324 void LockStateController::StartCancellableShutdownAnimation() {
325 Shell* shell = ash::Shell::GetInstance();
326 // Hide cursor, but let it reappear if the mouse moves.
327 shell->cursor_manager()->HideCursor();
329 animator_->StartAnimation(
330 SessionStateAnimator::ROOT_CONTAINER,
331 SessionStateAnimator::ANIMATION_GRAYSCALE_BRIGHTNESS,
332 SessionStateAnimator::ANIMATION_SPEED_SHUTDOWN);
333 StartPreShutdownAnimationTimer();
336 void LockStateController::StartImmediatePreLockAnimation(
337 bool request_lock_on_completion) {
338 VLOG(1) << "StartImmediatePreLockAnimation " << request_lock_on_completion;
339 animating_lock_ = true;
340 StoreUnlockedProperties();
342 base::Closure next_animation_starter =
343 base::Bind(&LockStateController::PreLockAnimationFinished,
344 weak_ptr_factory_.GetWeakPtr(),
345 request_lock_on_completion);
346 SessionStateAnimator::AnimationSequence* animation_sequence =
347 animator_->BeginAnimationSequence(next_animation_starter);
349 animation_sequence->StartAnimation(
350 SessionStateAnimator::NON_LOCK_SCREEN_CONTAINERS,
351 SessionStateAnimator::ANIMATION_LIFT,
352 SessionStateAnimator::ANIMATION_SPEED_MOVE_WINDOWS);
353 animation_sequence->StartAnimation(
354 SessionStateAnimator::LAUNCHER,
355 SessionStateAnimator::ANIMATION_FADE_OUT,
356 SessionStateAnimator::ANIMATION_SPEED_MOVE_WINDOWS);
357 // Hide the screen locker containers so we can raise them later.
358 animator_->StartAnimation(SessionStateAnimator::LOCK_SCREEN_CONTAINERS,
359 SessionStateAnimator::ANIMATION_HIDE_IMMEDIATELY,
360 SessionStateAnimator::ANIMATION_SPEED_IMMEDIATE);
361 AnimateBackgroundAppearanceIfNecessary(
362 SessionStateAnimator::ANIMATION_SPEED_MOVE_WINDOWS, animation_sequence);
364 animation_sequence->EndSequence();
366 DispatchCancelMode();
367 FOR_EACH_OBSERVER(LockStateObserver, observers_,
368 OnLockStateEvent(LockStateObserver::EVENT_LOCK_ANIMATION_STARTED));
371 void LockStateController::StartCancellablePreLockAnimation() {
372 animating_lock_ = true;
373 StoreUnlockedProperties();
374 VLOG(1) << "StartCancellablePreLockAnimation";
375 base::Closure next_animation_starter =
376 base::Bind(&LockStateController::PreLockAnimationFinished,
377 weak_ptr_factory_.GetWeakPtr(),
378 true /* request_lock */);
379 SessionStateAnimator::AnimationSequence* animation_sequence =
380 animator_->BeginAnimationSequence(next_animation_starter);
382 animation_sequence->StartAnimation(
383 SessionStateAnimator::NON_LOCK_SCREEN_CONTAINERS,
384 SessionStateAnimator::ANIMATION_LIFT,
385 SessionStateAnimator::ANIMATION_SPEED_UNDOABLE);
386 animation_sequence->StartAnimation(
387 SessionStateAnimator::LAUNCHER,
388 SessionStateAnimator::ANIMATION_FADE_OUT,
389 SessionStateAnimator::ANIMATION_SPEED_UNDOABLE);
390 // Hide the screen locker containers so we can raise them later.
391 animator_->StartAnimation(SessionStateAnimator::LOCK_SCREEN_CONTAINERS,
392 SessionStateAnimator::ANIMATION_HIDE_IMMEDIATELY,
393 SessionStateAnimator::ANIMATION_SPEED_IMMEDIATE);
394 AnimateBackgroundAppearanceIfNecessary(
395 SessionStateAnimator::ANIMATION_SPEED_UNDOABLE, animation_sequence);
397 DispatchCancelMode();
398 FOR_EACH_OBSERVER(LockStateObserver, observers_,
399 OnLockStateEvent(LockStateObserver::EVENT_PRELOCK_ANIMATION_STARTED));
400 animation_sequence->EndSequence();
403 void LockStateController::CancelPreLockAnimation() {
404 VLOG(1) << "CancelPreLockAnimation";
405 base::Closure next_animation_starter =
406 base::Bind(&LockStateController::LockAnimationCancelled,
407 weak_ptr_factory_.GetWeakPtr());
408 SessionStateAnimator::AnimationSequence* animation_sequence =
409 animator_->BeginAnimationSequence(next_animation_starter);
411 animation_sequence->StartAnimation(
412 SessionStateAnimator::NON_LOCK_SCREEN_CONTAINERS,
413 SessionStateAnimator::ANIMATION_UNDO_LIFT,
414 SessionStateAnimator::ANIMATION_SPEED_UNDO_MOVE_WINDOWS);
415 animation_sequence->StartAnimation(
416 SessionStateAnimator::LAUNCHER,
417 SessionStateAnimator::ANIMATION_FADE_IN,
418 SessionStateAnimator::ANIMATION_SPEED_UNDO_MOVE_WINDOWS);
419 AnimateBackgroundHidingIfNecessary(
420 SessionStateAnimator::ANIMATION_SPEED_UNDO_MOVE_WINDOWS,
421 animation_sequence);
423 animation_sequence->EndSequence();
426 void LockStateController::StartPostLockAnimation() {
427 VLOG(1) << "StartPostLockAnimation";
428 base::Closure next_animation_starter =
429 base::Bind(&LockStateController::PostLockAnimationFinished,
430 weak_ptr_factory_.GetWeakPtr());
431 SessionStateAnimator::AnimationSequence* animation_sequence =
432 animator_->BeginAnimationSequence(next_animation_starter);
434 animation_sequence->StartAnimation(
435 SessionStateAnimator::LOCK_SCREEN_CONTAINERS,
436 SessionStateAnimator::ANIMATION_RAISE_TO_SCREEN,
437 SessionStateAnimator::ANIMATION_SPEED_MOVE_WINDOWS);
438 animation_sequence->EndSequence();
441 void LockStateController::StartUnlockAnimationBeforeUIDestroyed(
442 base::Closure& callback) {
443 VLOG(1) << "StartUnlockAnimationBeforeUIDestroyed";
444 animator_->StartAnimationWithCallback(
445 SessionStateAnimator::LOCK_SCREEN_CONTAINERS,
446 SessionStateAnimator::ANIMATION_LIFT,
447 SessionStateAnimator::ANIMATION_SPEED_MOVE_WINDOWS,
448 callback);
451 void LockStateController::StartUnlockAnimationAfterUIDestroyed() {
452 VLOG(1) << "StartUnlockAnimationAfterUIDestroyed";
453 base::Closure next_animation_starter =
454 base::Bind(&LockStateController::UnlockAnimationAfterUIDestroyedFinished,
455 weak_ptr_factory_.GetWeakPtr());
456 SessionStateAnimator::AnimationSequence* animation_sequence =
457 animator_->BeginAnimationSequence(next_animation_starter);
459 animation_sequence->StartAnimation(
460 SessionStateAnimator::NON_LOCK_SCREEN_CONTAINERS,
461 SessionStateAnimator::ANIMATION_DROP,
462 SessionStateAnimator::ANIMATION_SPEED_MOVE_WINDOWS);
463 animation_sequence->StartAnimation(
464 SessionStateAnimator::LAUNCHER,
465 SessionStateAnimator::ANIMATION_FADE_IN,
466 SessionStateAnimator::ANIMATION_SPEED_MOVE_WINDOWS);
467 AnimateBackgroundHidingIfNecessary(
468 SessionStateAnimator::ANIMATION_SPEED_MOVE_WINDOWS, animation_sequence);
469 animation_sequence->EndSequence();
472 void LockStateController::LockAnimationCancelled() {
473 can_cancel_lock_animation_ = false;
474 RestoreUnlockedProperties();
477 void LockStateController::PreLockAnimationFinished(bool request_lock) {
478 VLOG(1) << "PreLockAnimationFinished";
479 can_cancel_lock_animation_ = false;
481 // Don't do anything (including starting the lock-fail timer) if the screen
482 // was already locked while the animation was going.
483 if (system_is_locked_) {
484 DCHECK(!request_lock) << "Got request to lock already-locked system "
485 << "at completion of pre-lock animation";
486 return;
489 if (request_lock) {
490 Shell::GetInstance()->metrics()->RecordUserMetricsAction(
491 shutdown_after_lock_ ?
492 UMA_ACCEL_LOCK_SCREEN_POWER_BUTTON :
493 UMA_ACCEL_LOCK_SCREEN_LOCK_BUTTON);
494 delegate_->RequestLockScreen();
497 base::TimeDelta timeout =
498 base::TimeDelta::FromMilliseconds(kLockFailTimeoutMs);
499 #if defined(OS_CHROMEOS)
500 // Increase lock timeout for slower hardware, see http://crbug.com/350628
501 const std::string board = base::SysInfo::GetLsbReleaseBoard();
502 if (board == "x86-mario" ||
503 StartsWithASCII(board, "x86-alex", true /* case_sensitive */) ||
504 StartsWithASCII(board, "x86-zgb", true /* case_sensitive */) ||
505 StartsWithASCII(board, "daisy", true /* case_sensitive */)) {
506 timeout *= 2;
508 #endif
509 lock_fail_timer_.Start(
510 FROM_HERE, timeout, this, &LockStateController::OnLockFailTimeout);
513 void LockStateController::PostLockAnimationFinished() {
514 animating_lock_ = false;
515 VLOG(1) << "PostLockAnimationFinished";
516 FOR_EACH_OBSERVER(LockStateObserver, observers_,
517 OnLockStateEvent(LockStateObserver::EVENT_LOCK_ANIMATION_FINISHED));
518 if (!lock_screen_displayed_callback_.is_null()) {
519 lock_screen_displayed_callback_.Run();
520 lock_screen_displayed_callback_.Reset();
522 CHECK(!views::MenuController::GetActiveInstance());
523 if (shutdown_after_lock_) {
524 shutdown_after_lock_ = false;
525 StartLockToShutdownTimer();
529 void LockStateController::UnlockAnimationAfterUIDestroyedFinished() {
530 RestoreUnlockedProperties();
533 void LockStateController::StoreUnlockedProperties() {
534 if (!unlocked_properties_) {
535 unlocked_properties_.reset(new UnlockedStateProperties());
536 unlocked_properties_->background_is_hidden =
537 animator_->IsBackgroundHidden();
539 if (unlocked_properties_->background_is_hidden) {
540 // Hide background so that it can be animated later.
541 animator_->StartAnimation(SessionStateAnimator::DESKTOP_BACKGROUND,
542 SessionStateAnimator::ANIMATION_HIDE_IMMEDIATELY,
543 SessionStateAnimator::ANIMATION_SPEED_IMMEDIATE);
544 animator_->ShowBackground();
548 void LockStateController::RestoreUnlockedProperties() {
549 if (!unlocked_properties_)
550 return;
551 if (unlocked_properties_->background_is_hidden) {
552 animator_->HideBackground();
553 // Restore background visibility.
554 animator_->StartAnimation(SessionStateAnimator::DESKTOP_BACKGROUND,
555 SessionStateAnimator::ANIMATION_FADE_IN,
556 SessionStateAnimator::ANIMATION_SPEED_IMMEDIATE);
558 unlocked_properties_.reset();
561 void LockStateController::AnimateBackgroundAppearanceIfNecessary(
562 SessionStateAnimator::AnimationSpeed speed,
563 SessionStateAnimator::AnimationSequence* animation_sequence) {
564 if (unlocked_properties_.get() &&
565 unlocked_properties_->background_is_hidden) {
566 animation_sequence->StartAnimation(
567 SessionStateAnimator::DESKTOP_BACKGROUND,
568 SessionStateAnimator::ANIMATION_FADE_IN,
569 speed);
573 void LockStateController::AnimateBackgroundHidingIfNecessary(
574 SessionStateAnimator::AnimationSpeed speed,
575 SessionStateAnimator::AnimationSequence* animation_sequence) {
576 if (unlocked_properties_.get() &&
577 unlocked_properties_->background_is_hidden) {
578 animation_sequence->StartAnimation(
579 SessionStateAnimator::DESKTOP_BACKGROUND,
580 SessionStateAnimator::ANIMATION_FADE_OUT,
581 speed);
585 } // namespace ash