OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "ash/wm/power_button_controller.h" | 5 #include "ash/wm/power_button_controller.h" |
6 | 6 |
7 #include "ash/ash_switches.h" | 7 #include "ash/ash_switches.h" |
8 #include "ash/shell.h" | 8 #include "ash/shell.h" |
9 #include "ash/shell_delegate.h" | 9 #include "ash/shell_delegate.h" |
10 #include "ash/shell_window_ids.h" | 10 #include "ash/shell_window_ids.h" |
11 #include "ash/wm/session_state_animator.h" | 11 #include "ash/wm/session_state_animator.h" |
| 12 #include "ash/wm/session_state_controller.h" |
12 #include "base/command_line.h" | 13 #include "base/command_line.h" |
13 #include "ui/aura/root_window.h" | 14 #include "ui/aura/root_window.h" |
14 #include "ui/aura/shared/compound_event_filter.h" | 15 #include "ui/aura/shared/compound_event_filter.h" |
15 | 16 |
16 #if defined(OS_CHROMEOS) | |
17 #include "base/chromeos/chromeos_version.h" | |
18 #endif | |
19 | |
20 namespace ash { | 17 namespace ash { |
21 | 18 |
22 namespace { | 19 PowerButtonController::PowerButtonController(SessionStateController* controller) |
23 | 20 : power_button_down_(false), |
24 // Amount of time that the power button needs to be held before we lock the | |
25 // screen. | |
26 const int kLockTimeoutMs = 400; | |
27 | |
28 // Amount of time that the power button needs to be held before we shut down. | |
29 const int kShutdownTimeoutMs = 400; | |
30 | |
31 // Amount of time to wait for our lock requests to be honored before giving up. | |
32 const int kLockFailTimeoutMs = 4000; | |
33 | |
34 // When the button has been held continuously from the unlocked state, amount of | |
35 // time that we wait after the screen locker window is shown before starting the | |
36 // pre-shutdown animation. | |
37 const int kLockToShutdownTimeoutMs = 150; | |
38 | |
39 // Amount of time taken to scale the snapshot of the screen down to a | |
40 // slightly-smaller size once the user starts holding the power button. Used | |
41 // for both the pre-lock and pre-shutdown animations. | |
42 const int kSlowCloseAnimMs = 400; | |
43 | |
44 // Amount of time taken to scale the snapshot of the screen back to its original | |
45 // size when the button is released. | |
46 const int kUndoSlowCloseAnimMs = 100; | |
47 | |
48 // Amount of time taken to scale the snapshot down to a point in the center of | |
49 // the screen once the screen has been locked or we've been notified that the | |
50 // system is shutting down. | |
51 const int kFastCloseAnimMs = 150; | |
52 | |
53 // Additional time (beyond kFastCloseAnimMs) to wait after starting the | |
54 // fast-close shutdown animation before actually requesting shutdown, to give | |
55 // the animation time to finish. | |
56 const int kShutdownRequestDelayMs = 50; | |
57 | |
58 } // namespace | |
59 | |
60 PowerButtonController::TestApi::TestApi(PowerButtonController* controller) | |
61 : controller_(controller), | |
62 animator_api_(new internal::SessionStateAnimator::TestApi( | |
63 controller->animator_.get())) { | |
64 } | |
65 | |
66 PowerButtonController::TestApi::~TestApi() { | |
67 } | |
68 | |
69 PowerButtonController::PowerButtonController() | |
70 : login_status_(user::LOGGED_IN_NONE), | |
71 unlocked_login_status_(user::LOGGED_IN_NONE), | |
72 power_button_down_(false), | |
73 lock_button_down_(false), | 21 lock_button_down_(false), |
74 screen_is_off_(false), | 22 screen_is_off_(false), |
75 shutting_down_(false), | |
76 has_legacy_power_button_( | 23 has_legacy_power_button_( |
77 CommandLine::ForCurrentProcess()->HasSwitch( | 24 CommandLine::ForCurrentProcess()->HasSwitch( |
78 switches::kAuraLegacyPowerButton)), | 25 switches::kAuraLegacyPowerButton)), |
79 animator_(new internal::SessionStateAnimator()) { | 26 controller_(controller) { |
80 Shell::GetPrimaryRootWindow()->AddRootWindowObserver(this); | |
81 } | 27 } |
82 | 28 |
83 PowerButtonController::~PowerButtonController() { | 29 PowerButtonController::~PowerButtonController() { |
84 Shell::GetPrimaryRootWindow()->RemoveRootWindowObserver(this); | |
85 } | |
86 | |
87 void PowerButtonController::OnLoginStateChanged(user::LoginStatus status) { | |
88 login_status_ = status; | |
89 unlocked_login_status_ = user::LOGGED_IN_NONE; | |
90 } | |
91 | |
92 void PowerButtonController::OnAppTerminating() { | |
93 // If we hear that Chrome is exiting but didn't request it ourselves, all we | |
94 // can really hope for is that we'll have time to clear the screen. | |
95 if (!shutting_down_) { | |
96 shutting_down_ = true; | |
97 Shell* shell = ash::Shell::GetInstance(); | |
98 shell->env_filter()->set_cursor_hidden_by_filter(false); | |
99 shell->cursor_manager()->ShowCursor(false); | |
100 animator_->ShowBlackLayer(); | |
101 animator_->StartAnimation( | |
102 internal::SessionStateAnimator::kAllContainersMask, | |
103 internal::SessionStateAnimator::ANIMATION_HIDE); | |
104 } | |
105 } | |
106 | |
107 void PowerButtonController::OnLockStateChanged(bool locked) { | |
108 if (shutting_down_ || (login_status_ == user::LOGGED_IN_LOCKED) == locked) | |
109 return; | |
110 | |
111 if (!locked && login_status_ == user::LOGGED_IN_LOCKED) { | |
112 login_status_ = unlocked_login_status_; | |
113 unlocked_login_status_ = user::LOGGED_IN_NONE; | |
114 } else { | |
115 unlocked_login_status_ = login_status_; | |
116 login_status_ = user::LOGGED_IN_LOCKED; | |
117 } | |
118 | |
119 if (locked) { | |
120 animator_->StartAnimation( | |
121 internal::SessionStateAnimator::LOCK_SCREEN_CONTAINERS, | |
122 internal::SessionStateAnimator::ANIMATION_FADE_IN); | |
123 lock_timer_.Stop(); | |
124 lock_fail_timer_.Stop(); | |
125 | |
126 if (!has_legacy_power_button_ && power_button_down_) { | |
127 lock_to_shutdown_timer_.Stop(); | |
128 lock_to_shutdown_timer_.Start( | |
129 FROM_HERE, | |
130 base::TimeDelta::FromMilliseconds(kLockToShutdownTimeoutMs), | |
131 this, &PowerButtonController::OnLockToShutdownTimeout); | |
132 } | |
133 } else { | |
134 animator_->StartAnimation( | |
135 internal::SessionStateAnimator::DESKTOP_BACKGROUND | | |
136 internal::SessionStateAnimator::LAUNCHER | | |
137 internal::SessionStateAnimator::NON_LOCK_SCREEN_CONTAINERS, | |
138 internal::SessionStateAnimator::ANIMATION_RESTORE); | |
139 animator_->DropBlackLayer(); | |
140 } | |
141 } | 30 } |
142 | 31 |
143 void PowerButtonController::OnScreenBrightnessChanged(double percent) { | 32 void PowerButtonController::OnScreenBrightnessChanged(double percent) { |
144 screen_is_off_ = percent <= 0.001; | 33 screen_is_off_ = percent <= 0.001; |
145 } | 34 } |
146 | 35 |
147 void PowerButtonController::OnStartingLock() { | |
148 if (shutting_down_ || login_status_ == user::LOGGED_IN_LOCKED) | |
149 return; | |
150 | |
151 // Ensure that the black layer is visible -- if the screen was locked via | |
152 // the wrench menu, we won't have already shown the black background | |
153 // as part of the slow-close animation. | |
154 animator_->ShowBlackLayer(); | |
155 | |
156 animator_->StartAnimation( | |
157 internal::SessionStateAnimator::LAUNCHER, | |
158 internal::SessionStateAnimator::ANIMATION_HIDE); | |
159 | |
160 animator_->StartAnimation( | |
161 internal::SessionStateAnimator::NON_LOCK_SCREEN_CONTAINERS, | |
162 internal::SessionStateAnimator::ANIMATION_FAST_CLOSE); | |
163 | |
164 // Hide the screen locker containers so we can make them fade in later. | |
165 animator_->StartAnimation( | |
166 internal::SessionStateAnimator::LOCK_SCREEN_CONTAINERS, | |
167 internal::SessionStateAnimator::ANIMATION_HIDE); | |
168 } | |
169 | |
170 void PowerButtonController::OnPowerButtonEvent( | 36 void PowerButtonController::OnPowerButtonEvent( |
171 bool down, const base::TimeTicks& timestamp) { | 37 bool down, const base::TimeTicks& timestamp) { |
172 power_button_down_ = down; | 38 power_button_down_ = down; |
173 | 39 |
174 if (shutting_down_) | 40 if (controller_->IsShuttingDown()) |
175 return; | 41 return; |
176 | 42 |
177 // Avoid starting the lock/shutdown sequence if the power button is pressed | 43 // Avoid starting the lock/shutdown sequence if the power button is pressed |
178 // while the screen is off (http://crbug.com/128451). | 44 // while the screen is off (http://crbug.com/128451). |
179 if (screen_is_off_) | 45 if (screen_is_off_) |
180 return; | 46 return; |
181 | 47 |
182 if (has_legacy_power_button_) { | 48 if (has_legacy_power_button_) { |
183 // If power button releases won't get reported correctly because we're not | 49 // If power button releases won't get reported correctly because we're not |
184 // running on official hardware, just lock the screen or shut down | 50 // running on official hardware, just lock the screen or shut down |
185 // immediately. | 51 // immediately. |
186 if (down) { | 52 if (down) { |
187 animator_->ShowBlackLayer(); | 53 if (controller_->IsEligibleForLock()) |
188 if (LoggedInAsNonGuest() && login_status_ != user::LOGGED_IN_LOCKED) { | 54 controller_->StartLockAnimationButLockImmediately(); |
189 animator_->StartAnimation( | 55 else |
190 internal::SessionStateAnimator::NON_LOCK_SCREEN_CONTAINERS, | 56 controller_->ShutdownImmediately(); |
191 internal::SessionStateAnimator::ANIMATION_SLOW_CLOSE); | |
192 OnLockTimeout(); | |
193 } else { | |
194 OnShutdownTimeout(); | |
195 } | |
196 } | 57 } |
197 } else { // !has_legacy_power_button_ | 58 } else { // !has_legacy_power_button_ |
198 if (down) { | 59 if (down) { |
199 // If we already have a pending request to lock the screen, wait. | 60 // If we already have a pending request to lock the screen, wait. |
200 if (lock_fail_timer_.IsRunning()) | 61 if (controller_->IsTryingToLock()) |
201 return; | 62 return; |
202 | 63 |
203 if (LoggedInAsNonGuest() && login_status_ != user::LOGGED_IN_LOCKED) | 64 if (controller_->IsEligibleForLock()) |
204 StartLockTimer(); | 65 controller_->StartCancellableLock(); |
205 else | 66 else |
206 StartShutdownTimer(); | 67 controller_->StartCancellableShutdown(); |
207 } else { // Button is up. | 68 } else { // Button is up. |
208 if (lock_timer_.IsRunning() || shutdown_timer_.IsRunning()) { | 69 if (controller_->CanCancelLock()) |
209 if (login_status_ == user::LOGGED_IN_LOCKED) { | 70 controller_->CancelLock(); |
210 // If we've already started shutdown transition at lock screen | 71 else if (controller_->CanCancelShutdown()) |
211 // desktop background needs to be restored immediately. | 72 controller_->CancelShutdown(); |
212 animator_->StartAnimation( | |
213 internal::SessionStateAnimator::DESKTOP_BACKGROUND, | |
214 internal::SessionStateAnimator::ANIMATION_RESTORE); | |
215 } | |
216 animator_->StartAnimation( | |
217 (login_status_ == user::LOGGED_IN_LOCKED) ? | |
218 internal::SessionStateAnimator::kAllLockScreenContainersMask : | |
219 internal::SessionStateAnimator::kAllContainersMask, | |
220 internal::SessionStateAnimator::ANIMATION_UNDO_SLOW_CLOSE); | |
221 } | |
222 | |
223 // Drop the black layer after the undo animation finishes. | |
224 if (lock_timer_.IsRunning() || | |
225 (shutdown_timer_.IsRunning() && !LoggedInAsNonGuest())) { | |
226 animator_->ScheduleDropBlackLayer(); | |
227 } | |
228 | |
229 lock_timer_.Stop(); | |
230 shutdown_timer_.Stop(); | |
231 lock_to_shutdown_timer_.Stop(); | |
232 } | 73 } |
233 } | 74 } |
234 } | 75 } |
235 | 76 |
236 void PowerButtonController::OnLockButtonEvent( | 77 void PowerButtonController::OnLockButtonEvent( |
237 bool down, const base::TimeTicks& timestamp) { | 78 bool down, const base::TimeTicks& timestamp) { |
238 lock_button_down_ = down; | 79 lock_button_down_ = down; |
239 | 80 |
240 if (shutting_down_ || !LoggedInAsNonGuest()) | 81 if (controller_->IsShuttingDown() || !controller_->IsEligibleForLock()) |
241 return; | 82 return; |
242 | 83 |
243 // Bail if we're already locked or are in the process of locking. Also give | 84 // Bail if we're already locked or are in the process of locking. Also give |
244 // the power button precedence over the lock button (we don't expect both | 85 // the power button precedence over the lock button (we don't expect both |
245 // buttons to be present, so this is just making sure that we don't do | 86 // buttons to be present, so this is just making sure that we don't do |
246 // something completely stupid if that assumption changes later). | 87 // something completely stupid if that assumption changes later). |
247 if (login_status_ == user::LOGGED_IN_LOCKED || | 88 if (power_button_down_) |
248 lock_fail_timer_.IsRunning() || power_button_down_) | |
249 return; | 89 return; |
250 | 90 |
251 if (down) { | 91 if (controller_->IsLocked() || controller_->IsTryingToLock()) |
252 StartLockTimer(); | 92 return; |
253 } else { | |
254 if (lock_timer_.IsRunning()) { | |
255 animator_->StartAnimation( | |
256 internal::SessionStateAnimator::NON_LOCK_SCREEN_CONTAINERS, | |
257 internal::SessionStateAnimator::ANIMATION_UNDO_SLOW_CLOSE); | |
258 animator_->ScheduleDropBlackLayer(); | |
259 lock_timer_.Stop(); | |
260 } | |
261 } | |
262 } | |
263 | 93 |
264 void PowerButtonController::RequestShutdown() { | 94 if (down) |
265 if (!shutting_down_) | 95 controller_->StartCancellableLock(); |
266 StartShutdownAnimationAndRequestShutdown(); | 96 else |
267 } | 97 controller_->CancelLockWithOtherAnimation(); |
268 | |
269 void PowerButtonController::OnRootWindowHostCloseRequested( | |
270 const aura::RootWindow*) { | |
271 if(Shell::GetInstance() && Shell::GetInstance()->delegate()) | |
272 Shell::GetInstance()->delegate()->Exit(); | |
273 } | |
274 | |
275 bool PowerButtonController::LoggedInAsNonGuest() const { | |
276 if (login_status_ == user::LOGGED_IN_NONE) | |
277 return false; | |
278 if (login_status_ == user::LOGGED_IN_GUEST) | |
279 return false; | |
280 // TODO(mukai): think about kiosk mode. | |
281 return true; | |
282 } | |
283 | |
284 void PowerButtonController::OnLockTimeout() { | |
285 delegate_->RequestLockScreen(); | |
286 lock_fail_timer_.Start( | |
287 FROM_HERE, | |
288 base::TimeDelta::FromMilliseconds(kLockFailTimeoutMs), | |
289 this, &PowerButtonController::OnLockFailTimeout); | |
290 } | |
291 | |
292 void PowerButtonController::OnLockFailTimeout() { | |
293 DCHECK_NE(login_status_, user::LOGGED_IN_LOCKED); | |
294 LOG(ERROR) << "Screen lock request timed out"; | |
295 animator_->StartAnimation( | |
296 internal::SessionStateAnimator::LAUNCHER | | |
297 internal::SessionStateAnimator::NON_LOCK_SCREEN_CONTAINERS, | |
298 internal::SessionStateAnimator::ANIMATION_RESTORE); | |
299 animator_->DropBlackLayer(); | |
300 } | |
301 | |
302 void PowerButtonController::OnLockToShutdownTimeout() { | |
303 DCHECK_EQ(login_status_, user::LOGGED_IN_LOCKED); | |
304 StartShutdownTimer(); | |
305 } | |
306 | |
307 void PowerButtonController::OnShutdownTimeout() { | |
308 if (!shutting_down_) | |
309 StartShutdownAnimationAndRequestShutdown(); | |
310 } | |
311 | |
312 void PowerButtonController::OnRealShutdownTimeout() { | |
313 DCHECK(shutting_down_); | |
314 #if defined(OS_CHROMEOS) | |
315 if (!base::chromeos::IsRunningOnChromeOS()) { | |
316 ShellDelegate* delegate = Shell::GetInstance()->delegate(); | |
317 if (delegate) | |
318 delegate->Exit(); | |
319 } | |
320 #endif | |
321 delegate_->RequestShutdown(); | |
322 } | |
323 | |
324 void PowerButtonController::StartLockTimer() { | |
325 animator_->ShowBlackLayer(); | |
326 animator_->StartAnimation( | |
327 internal::SessionStateAnimator::NON_LOCK_SCREEN_CONTAINERS, | |
328 internal::SessionStateAnimator::ANIMATION_SLOW_CLOSE); | |
329 lock_timer_.Stop(); | |
330 lock_timer_.Start(FROM_HERE, | |
331 base::TimeDelta::FromMilliseconds(kSlowCloseAnimMs), | |
332 this, &PowerButtonController::OnLockTimeout); | |
333 } | |
334 | |
335 void PowerButtonController::StartShutdownTimer() { | |
336 animator_->ShowBlackLayer(); | |
337 animator_->StartAnimation( | |
338 internal::SessionStateAnimator::kAllContainersMask, | |
339 internal::SessionStateAnimator::ANIMATION_SLOW_CLOSE); | |
340 shutdown_timer_.Stop(); | |
341 shutdown_timer_.Start( | |
342 FROM_HERE, | |
343 base::TimeDelta::FromMilliseconds(kShutdownTimeoutMs), | |
344 this, &PowerButtonController::OnShutdownTimeout); | |
345 } | |
346 | |
347 void PowerButtonController::StartShutdownAnimationAndRequestShutdown() { | |
348 DCHECK(!shutting_down_); | |
349 shutting_down_ = true; | |
350 | |
351 Shell* shell = ash::Shell::GetInstance(); | |
352 shell->env_filter()->set_cursor_hidden_by_filter(false); | |
353 shell->cursor_manager()->ShowCursor(false); | |
354 | |
355 animator_->ShowBlackLayer(); | |
356 if (login_status_ != user::LOGGED_IN_NONE) { | |
357 // Hide the other containers before starting the animation. | |
358 // ANIMATION_FAST_CLOSE will make the screen locker windows partially | |
359 // transparent, and we don't want the other windows to show through. | |
360 animator_->StartAnimation( | |
361 internal::SessionStateAnimator::NON_LOCK_SCREEN_CONTAINERS | | |
362 internal::SessionStateAnimator::LAUNCHER, | |
363 internal::SessionStateAnimator::ANIMATION_HIDE); | |
364 animator_->StartAnimation( | |
365 internal::SessionStateAnimator::kAllLockScreenContainersMask, | |
366 internal::SessionStateAnimator::ANIMATION_FAST_CLOSE); | |
367 } else { | |
368 animator_->StartAnimation( | |
369 internal::SessionStateAnimator::kAllContainersMask, | |
370 internal::SessionStateAnimator::ANIMATION_FAST_CLOSE); | |
371 } | |
372 | |
373 real_shutdown_timer_.Start( | |
374 FROM_HERE, | |
375 base::TimeDelta::FromMilliseconds( | |
376 kFastCloseAnimMs + kShutdownRequestDelayMs), | |
377 this, &PowerButtonController::OnRealShutdownTimeout); | |
378 } | 98 } |
379 | 99 |
380 } // namespace ash | 100 } // namespace ash |
OLD | NEW |