Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / ash / wm / lock_state_controller.cc
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.
4
5 #include "ash/wm/lock_state_controller.h"
6
7 #include <algorithm>
8 #include <string>
9
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_helpers.h"
20 #include "base/command_line.h"
21 #include "base/strings/string_util.h"
22 #include "base/timer/timer.h"
23 #include "ui/aura/window_tree_host.h"
24 #include "ui/views/controls/menu/menu_controller.h"
25 #include "ui/wm/core/compound_event_filter.h"
26
27 #if defined(OS_CHROMEOS)
28 #include "base/sys_info.h"
29 #include "media/audio/sounds/sounds_manager.h"
30 #endif
31
32 #if defined(OS_CHROMEOS)
33 using media::SoundsManager;
34 #endif
35
36 namespace ash {
37
38 namespace {
39
40 #if defined(OS_CHROMEOS)
41 const int kMaxShutdownSoundDurationMs = 1500;
42 #endif
43
44 }  // namespace
45
46 const int LockStateController::kLockTimeoutMs = 400;
47 const int LockStateController::kShutdownTimeoutMs = 400;
48 const int LockStateController::kLockFailTimeoutMs = 8000;
49 const int LockStateController::kLockToShutdownTimeoutMs = 150;
50 const int LockStateController::kShutdownRequestDelayMs = 50;
51
52 LockStateController::TestApi::TestApi(LockStateController* controller)
53     : controller_(controller) {
54 }
55
56 LockStateController::TestApi::~TestApi() {
57 }
58
59 LockStateController::LockStateController()
60     : animator_(new SessionStateAnimatorImpl()),
61       login_status_(user::LOGGED_IN_NONE),
62       system_is_locked_(false),
63       shutting_down_(false),
64       shutdown_after_lock_(false),
65       animating_lock_(false),
66       can_cancel_lock_animation_(false),
67       weak_ptr_factory_(this) {
68   Shell::GetPrimaryRootWindow()->GetHost()->AddObserver(this);
69 }
70
71 LockStateController::~LockStateController() {
72   Shell::GetPrimaryRootWindow()->GetHost()->RemoveObserver(this);
73 }
74
75 void LockStateController::SetDelegate(
76     scoped_ptr<LockStateControllerDelegate> delegate) {
77   delegate_ = delegate.Pass();
78 }
79
80 void LockStateController::AddObserver(LockStateObserver* observer) {
81   observers_.AddObserver(observer);
82 }
83
84 void LockStateController::RemoveObserver(LockStateObserver* observer) {
85   observers_.RemoveObserver(observer);
86 }
87
88 bool LockStateController::HasObserver(LockStateObserver* observer) {
89   return observers_.HasObserver(observer);
90 }
91
92 void LockStateController::StartLockAnimation(
93     bool shutdown_after_lock) {
94   if (animating_lock_)
95     return;
96   shutdown_after_lock_ = shutdown_after_lock;
97   can_cancel_lock_animation_ = true;
98
99   StartCancellablePreLockAnimation();
100 }
101
102 void LockStateController::StartShutdownAnimation() {
103   StartCancellableShutdownAnimation();
104 }
105
106 void LockStateController::StartLockAnimationAndLockImmediately(
107     bool shutdown_after_lock) {
108   if (animating_lock_)
109     return;
110   shutdown_after_lock_ = shutdown_after_lock;
111   StartImmediatePreLockAnimation(true /* request_lock_on_completion */);
112 }
113
114 bool LockStateController::LockRequested() {
115   return lock_fail_timer_.IsRunning();
116 }
117
118 bool LockStateController::ShutdownRequested() {
119   return shutting_down_;
120 }
121
122 bool LockStateController::CanCancelLockAnimation() {
123   return can_cancel_lock_animation_;
124 }
125
126 void LockStateController::CancelLockAnimation() {
127   if (!CanCancelLockAnimation())
128     return;
129   shutdown_after_lock_ = false;
130   animating_lock_ = false;
131   CancelPreLockAnimation();
132 }
133
134 bool LockStateController::CanCancelShutdownAnimation() {
135   return pre_shutdown_timer_.IsRunning() ||
136          shutdown_after_lock_ ||
137          lock_to_shutdown_timer_.IsRunning();
138 }
139
140 void LockStateController::CancelShutdownAnimation() {
141   if (!CanCancelShutdownAnimation())
142     return;
143   if (lock_to_shutdown_timer_.IsRunning()) {
144     lock_to_shutdown_timer_.Stop();
145     return;
146   }
147   if (shutdown_after_lock_) {
148     shutdown_after_lock_ = false;
149     return;
150   }
151
152   animator_->StartAnimation(
153       SessionStateAnimator::ROOT_CONTAINER,
154       SessionStateAnimator::ANIMATION_UNDO_GRAYSCALE_BRIGHTNESS,
155       SessionStateAnimator::ANIMATION_SPEED_REVERT_SHUTDOWN);
156   pre_shutdown_timer_.Stop();
157 }
158
159 void LockStateController::OnStartingLock() {
160   if (shutting_down_ || system_is_locked_)
161     return;
162   if (animating_lock_)
163     return;
164   StartImmediatePreLockAnimation(false /* request_lock_on_completion */);
165 }
166
167 void LockStateController::RequestShutdown() {
168   if (shutting_down_)
169     return;
170
171   shutting_down_ = true;
172
173   Shell* shell = ash::Shell::GetInstance();
174   shell->cursor_manager()->HideCursor();
175   shell->cursor_manager()->LockCursor();
176
177   animator_->StartAnimation(
178       SessionStateAnimator::ROOT_CONTAINER,
179       SessionStateAnimator::ANIMATION_GRAYSCALE_BRIGHTNESS,
180       SessionStateAnimator::ANIMATION_SPEED_SHUTDOWN);
181   StartRealShutdownTimer(true);
182 }
183
184 void LockStateController::OnLockScreenHide(
185   base::Callback<void(void)>& callback) {
186   StartUnlockAnimationBeforeUIDestroyed(callback);
187 }
188
189 void LockStateController::SetLockScreenDisplayedCallback(
190     const base::Closure& callback) {
191   lock_screen_displayed_callback_ = callback;
192 }
193
194 void LockStateController::OnHostCloseRequested(
195     const aura::WindowTreeHost* host) {
196   Shell::GetInstance()->delegate()->Exit();
197 }
198
199 void LockStateController::OnLoginStateChanged(
200     user::LoginStatus status) {
201   if (status != user::LOGGED_IN_LOCKED)
202     login_status_ = status;
203   system_is_locked_ = (status == user::LOGGED_IN_LOCKED);
204 }
205
206 void LockStateController::OnAppTerminating() {
207   // If we hear that Chrome is exiting but didn't request it ourselves, all we
208   // can really hope for is that we'll have time to clear the screen.
209   // This is also the case when the user signs off.
210   if (!shutting_down_) {
211     shutting_down_ = true;
212     Shell* shell = ash::Shell::GetInstance();
213     shell->cursor_manager()->HideCursor();
214     shell->cursor_manager()->LockCursor();
215     animator_->StartAnimation(SessionStateAnimator::kAllNonRootContainersMask,
216                               SessionStateAnimator::ANIMATION_HIDE_IMMEDIATELY,
217                               SessionStateAnimator::ANIMATION_SPEED_IMMEDIATE);
218   }
219 }
220
221 void LockStateController::OnLockStateChanged(bool locked) {
222   VLOG(1) << "OnLockStateChanged " << locked;
223   if (shutting_down_ || (system_is_locked_ == locked))
224     return;
225
226   system_is_locked_ = locked;
227
228   if (locked) {
229     StartPostLockAnimation();
230     lock_fail_timer_.Stop();
231   } else {
232     StartUnlockAnimationAfterUIDestroyed();
233   }
234 }
235
236 void LockStateController::OnLockFailTimeout() {
237   DCHECK(!system_is_locked_);
238   CHECK(false) << "We can not be sure about the lock state. Crash and let the "
239                << "SessionManager end the session";
240 }
241
242 void LockStateController::StartLockToShutdownTimer() {
243   shutdown_after_lock_ = false;
244   lock_to_shutdown_timer_.Stop();
245   lock_to_shutdown_timer_.Start(
246       FROM_HERE,
247       base::TimeDelta::FromMilliseconds(kLockToShutdownTimeoutMs),
248       this, &LockStateController::OnLockToShutdownTimeout);
249 }
250
251 void LockStateController::OnLockToShutdownTimeout() {
252   DCHECK(system_is_locked_);
253   StartCancellableShutdownAnimation();
254 }
255
256 void LockStateController::StartPreShutdownAnimationTimer() {
257   pre_shutdown_timer_.Stop();
258   pre_shutdown_timer_.Start(
259       FROM_HERE,
260       animator_->GetDuration(SessionStateAnimator::ANIMATION_SPEED_SHUTDOWN),
261       this,
262       &LockStateController::OnPreShutdownAnimationTimeout);
263 }
264
265 void LockStateController::OnPreShutdownAnimationTimeout() {
266   VLOG(1) << "OnPreShutdownAnimationTimeout";
267   shutting_down_ = true;
268
269   Shell* shell = ash::Shell::GetInstance();
270   shell->cursor_manager()->HideCursor();
271
272   StartRealShutdownTimer(false);
273 }
274
275 void LockStateController::StartRealShutdownTimer(bool with_animation_time) {
276   base::TimeDelta duration =
277       base::TimeDelta::FromMilliseconds(kShutdownRequestDelayMs);
278   if (with_animation_time) {
279     duration +=
280         animator_->GetDuration(SessionStateAnimator::ANIMATION_SPEED_SHUTDOWN);
281   }
282
283 #if defined(OS_CHROMEOS)
284   const AccessibilityDelegate* const delegate =
285       Shell::GetInstance()->accessibility_delegate();
286   base::TimeDelta sound_duration = delegate->PlayShutdownSound();
287   sound_duration =
288       std::min(sound_duration,
289                base::TimeDelta::FromMilliseconds(kMaxShutdownSoundDurationMs));
290   duration = std::max(duration, sound_duration);
291 #endif
292
293   real_shutdown_timer_.Start(
294       FROM_HERE, duration, this, &LockStateController::OnRealShutdownTimeout);
295 }
296
297 void LockStateController::OnRealShutdownTimeout() {
298   VLOG(1) << "OnRealShutdownTimeout";
299   DCHECK(shutting_down_);
300 #if defined(OS_CHROMEOS)
301   if (!base::SysInfo::IsRunningOnChromeOS()) {
302     ShellDelegate* delegate = Shell::GetInstance()->delegate();
303     if (delegate) {
304       delegate->Exit();
305       return;
306     }
307   }
308 #endif
309   Shell::GetInstance()->metrics()->RecordUserMetricsAction(
310       UMA_ACCEL_SHUT_DOWN_POWER_BUTTON);
311   delegate_->RequestShutdown();
312 }
313
314 void LockStateController::StartCancellableShutdownAnimation() {
315   Shell* shell = ash::Shell::GetInstance();
316   // Hide cursor, but let it reappear if the mouse moves.
317   shell->cursor_manager()->HideCursor();
318
319   animator_->StartAnimation(
320       SessionStateAnimator::ROOT_CONTAINER,
321       SessionStateAnimator::ANIMATION_GRAYSCALE_BRIGHTNESS,
322       SessionStateAnimator::ANIMATION_SPEED_SHUTDOWN);
323   StartPreShutdownAnimationTimer();
324 }
325
326 void LockStateController::StartImmediatePreLockAnimation(
327     bool request_lock_on_completion) {
328   VLOG(1) << "StartImmediatePreLockAnimation " << request_lock_on_completion;
329   animating_lock_ = true;
330   StoreUnlockedProperties();
331
332   base::Closure next_animation_starter =
333       base::Bind(&LockStateController::PreLockAnimationFinished,
334                  weak_ptr_factory_.GetWeakPtr(),
335                  request_lock_on_completion);
336   SessionStateAnimator::AnimationSequence* animation_sequence =
337       animator_->BeginAnimationSequence(next_animation_starter);
338
339   animation_sequence->StartAnimation(
340       SessionStateAnimator::NON_LOCK_SCREEN_CONTAINERS,
341       SessionStateAnimator::ANIMATION_LIFT,
342       SessionStateAnimator::ANIMATION_SPEED_MOVE_WINDOWS);
343   animation_sequence->StartAnimation(
344       SessionStateAnimator::LAUNCHER,
345       SessionStateAnimator::ANIMATION_FADE_OUT,
346       SessionStateAnimator::ANIMATION_SPEED_MOVE_WINDOWS);
347   // Hide the screen locker containers so we can raise them later.
348   animator_->StartAnimation(SessionStateAnimator::LOCK_SCREEN_CONTAINERS,
349                             SessionStateAnimator::ANIMATION_HIDE_IMMEDIATELY,
350                             SessionStateAnimator::ANIMATION_SPEED_IMMEDIATE);
351   AnimateBackgroundAppearanceIfNecessary(
352       SessionStateAnimator::ANIMATION_SPEED_MOVE_WINDOWS, animation_sequence);
353
354   animation_sequence->EndSequence();
355
356   DispatchCancelMode();
357   FOR_EACH_OBSERVER(LockStateObserver, observers_,
358       OnLockStateEvent(LockStateObserver::EVENT_LOCK_ANIMATION_STARTED));
359 }
360
361 void LockStateController::StartCancellablePreLockAnimation() {
362   animating_lock_ = true;
363   StoreUnlockedProperties();
364   VLOG(1) << "StartCancellablePreLockAnimation";
365   base::Closure next_animation_starter =
366       base::Bind(&LockStateController::PreLockAnimationFinished,
367                  weak_ptr_factory_.GetWeakPtr(),
368                  true /* request_lock */);
369   SessionStateAnimator::AnimationSequence* animation_sequence =
370       animator_->BeginAnimationSequence(next_animation_starter);
371
372   animation_sequence->StartAnimation(
373       SessionStateAnimator::NON_LOCK_SCREEN_CONTAINERS,
374       SessionStateAnimator::ANIMATION_LIFT,
375       SessionStateAnimator::ANIMATION_SPEED_UNDOABLE);
376   animation_sequence->StartAnimation(
377       SessionStateAnimator::LAUNCHER,
378       SessionStateAnimator::ANIMATION_FADE_OUT,
379       SessionStateAnimator::ANIMATION_SPEED_UNDOABLE);
380   // Hide the screen locker containers so we can raise them later.
381   animator_->StartAnimation(SessionStateAnimator::LOCK_SCREEN_CONTAINERS,
382                             SessionStateAnimator::ANIMATION_HIDE_IMMEDIATELY,
383                             SessionStateAnimator::ANIMATION_SPEED_IMMEDIATE);
384   AnimateBackgroundAppearanceIfNecessary(
385       SessionStateAnimator::ANIMATION_SPEED_UNDOABLE, animation_sequence);
386
387   DispatchCancelMode();
388   FOR_EACH_OBSERVER(LockStateObserver, observers_,
389       OnLockStateEvent(LockStateObserver::EVENT_PRELOCK_ANIMATION_STARTED));
390   animation_sequence->EndSequence();
391 }
392
393 void LockStateController::CancelPreLockAnimation() {
394   VLOG(1) << "CancelPreLockAnimation";
395   base::Closure next_animation_starter =
396       base::Bind(&LockStateController::LockAnimationCancelled,
397                  weak_ptr_factory_.GetWeakPtr());
398   SessionStateAnimator::AnimationSequence* animation_sequence =
399       animator_->BeginAnimationSequence(next_animation_starter);
400
401   animation_sequence->StartAnimation(
402       SessionStateAnimator::NON_LOCK_SCREEN_CONTAINERS,
403       SessionStateAnimator::ANIMATION_UNDO_LIFT,
404       SessionStateAnimator::ANIMATION_SPEED_UNDO_MOVE_WINDOWS);
405   animation_sequence->StartAnimation(
406       SessionStateAnimator::LAUNCHER,
407       SessionStateAnimator::ANIMATION_FADE_IN,
408       SessionStateAnimator::ANIMATION_SPEED_UNDO_MOVE_WINDOWS);
409   AnimateBackgroundHidingIfNecessary(
410       SessionStateAnimator::ANIMATION_SPEED_UNDO_MOVE_WINDOWS,
411       animation_sequence);
412
413   animation_sequence->EndSequence();
414 }
415
416 void LockStateController::StartPostLockAnimation() {
417   VLOG(1) << "StartPostLockAnimation";
418   base::Closure next_animation_starter =
419       base::Bind(&LockStateController::PostLockAnimationFinished,
420                  weak_ptr_factory_.GetWeakPtr());
421   SessionStateAnimator::AnimationSequence* animation_sequence =
422       animator_->BeginAnimationSequence(next_animation_starter);
423
424   animation_sequence->StartAnimation(
425       SessionStateAnimator::LOCK_SCREEN_CONTAINERS,
426       SessionStateAnimator::ANIMATION_RAISE_TO_SCREEN,
427       SessionStateAnimator::ANIMATION_SPEED_MOVE_WINDOWS);
428   animation_sequence->EndSequence();
429 }
430
431 void LockStateController::StartUnlockAnimationBeforeUIDestroyed(
432     base::Closure& callback) {
433   VLOG(1) << "StartUnlockAnimationBeforeUIDestroyed";
434   animator_->StartAnimationWithCallback(
435       SessionStateAnimator::LOCK_SCREEN_CONTAINERS,
436       SessionStateAnimator::ANIMATION_LIFT,
437       SessionStateAnimator::ANIMATION_SPEED_MOVE_WINDOWS,
438       callback);
439 }
440
441 void LockStateController::StartUnlockAnimationAfterUIDestroyed() {
442   VLOG(1) << "StartUnlockAnimationAfterUIDestroyed";
443   base::Closure next_animation_starter =
444       base::Bind(&LockStateController::UnlockAnimationAfterUIDestroyedFinished,
445                  weak_ptr_factory_.GetWeakPtr());
446   SessionStateAnimator::AnimationSequence* animation_sequence =
447       animator_->BeginAnimationSequence(next_animation_starter);
448
449   animation_sequence->StartAnimation(
450       SessionStateAnimator::NON_LOCK_SCREEN_CONTAINERS,
451       SessionStateAnimator::ANIMATION_DROP,
452       SessionStateAnimator::ANIMATION_SPEED_MOVE_WINDOWS);
453   animation_sequence->StartAnimation(
454       SessionStateAnimator::LAUNCHER,
455       SessionStateAnimator::ANIMATION_FADE_IN,
456       SessionStateAnimator::ANIMATION_SPEED_MOVE_WINDOWS);
457   AnimateBackgroundHidingIfNecessary(
458       SessionStateAnimator::ANIMATION_SPEED_MOVE_WINDOWS, animation_sequence);
459   animation_sequence->EndSequence();
460 }
461
462 void LockStateController::LockAnimationCancelled() {
463   can_cancel_lock_animation_ = false;
464   RestoreUnlockedProperties();
465 }
466
467 void LockStateController::PreLockAnimationFinished(bool request_lock) {
468   VLOG(1) << "PreLockAnimationFinished";
469   can_cancel_lock_animation_ = false;
470
471   // Don't do anything (including starting the lock-fail timer) if the screen
472   // was already locked while the animation was going.
473   if (system_is_locked_) {
474     DCHECK(!request_lock) << "Got request to lock already-locked system "
475                           << "at completion of pre-lock animation";
476     return;
477   }
478
479   if (request_lock) {
480     Shell::GetInstance()->metrics()->RecordUserMetricsAction(
481         shutdown_after_lock_ ?
482         UMA_ACCEL_LOCK_SCREEN_POWER_BUTTON :
483         UMA_ACCEL_LOCK_SCREEN_LOCK_BUTTON);
484     delegate_->RequestLockScreen();
485   }
486
487   base::TimeDelta timeout =
488       base::TimeDelta::FromMilliseconds(kLockFailTimeoutMs);
489 #if defined(OS_CHROMEOS)
490   // Increase lock timeout for slower hardware, see http://crbug.com/350628
491   const std::string board = base::SysInfo::GetLsbReleaseBoard();
492   if (board == "x86-mario" ||
493       StartsWithASCII(board, "x86-alex", true /* case_sensitive */) ||
494       StartsWithASCII(board, "x86-zgb", true /* case_sensitive */)) {
495     timeout *= 2;
496   }
497 #endif
498   lock_fail_timer_.Start(
499       FROM_HERE, timeout, this, &LockStateController::OnLockFailTimeout);
500 }
501
502 void LockStateController::PostLockAnimationFinished() {
503   animating_lock_ = false;
504   VLOG(1) << "PostLockAnimationFinished";
505   FOR_EACH_OBSERVER(LockStateObserver, observers_,
506       OnLockStateEvent(LockStateObserver::EVENT_LOCK_ANIMATION_FINISHED));
507   if (!lock_screen_displayed_callback_.is_null()) {
508     lock_screen_displayed_callback_.Run();
509     lock_screen_displayed_callback_.Reset();
510   }
511   CHECK(!views::MenuController::GetActiveInstance());
512   if (shutdown_after_lock_) {
513     shutdown_after_lock_ = false;
514     StartLockToShutdownTimer();
515   }
516 }
517
518 void LockStateController::UnlockAnimationAfterUIDestroyedFinished() {
519   RestoreUnlockedProperties();
520 }
521
522 void LockStateController::StoreUnlockedProperties() {
523   if (!unlocked_properties_) {
524     unlocked_properties_.reset(new UnlockedStateProperties());
525     unlocked_properties_->background_is_hidden =
526         animator_->IsBackgroundHidden();
527   }
528   if (unlocked_properties_->background_is_hidden) {
529     // Hide background so that it can be animated later.
530     animator_->StartAnimation(SessionStateAnimator::DESKTOP_BACKGROUND,
531                               SessionStateAnimator::ANIMATION_HIDE_IMMEDIATELY,
532                               SessionStateAnimator::ANIMATION_SPEED_IMMEDIATE);
533     animator_->ShowBackground();
534   }
535 }
536
537 void LockStateController::RestoreUnlockedProperties() {
538   if (!unlocked_properties_)
539     return;
540   if (unlocked_properties_->background_is_hidden) {
541     animator_->HideBackground();
542     // Restore background visibility.
543     animator_->StartAnimation(SessionStateAnimator::DESKTOP_BACKGROUND,
544                               SessionStateAnimator::ANIMATION_FADE_IN,
545                               SessionStateAnimator::ANIMATION_SPEED_IMMEDIATE);
546   }
547   unlocked_properties_.reset();
548 }
549
550 void LockStateController::AnimateBackgroundAppearanceIfNecessary(
551     SessionStateAnimator::AnimationSpeed speed,
552     SessionStateAnimator::AnimationSequence* animation_sequence) {
553   if (unlocked_properties_.get() &&
554       unlocked_properties_->background_is_hidden) {
555     animation_sequence->StartAnimation(
556         SessionStateAnimator::DESKTOP_BACKGROUND,
557         SessionStateAnimator::ANIMATION_FADE_IN,
558         speed);
559   }
560 }
561
562 void LockStateController::AnimateBackgroundHidingIfNecessary(
563     SessionStateAnimator::AnimationSpeed speed,
564     SessionStateAnimator::AnimationSequence* animation_sequence) {
565   if (unlocked_properties_.get() &&
566       unlocked_properties_->background_is_hidden) {
567     animation_sequence->StartAnimation(
568         SessionStateAnimator::DESKTOP_BACKGROUND,
569         SessionStateAnimator::ANIMATION_FADE_OUT,
570         speed);
571   }
572 }
573
574 }  // namespace ash