| 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 |