Chromium Code Reviews| 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 |