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