// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "ash/wm/session_state_controller_impl.h" #include "ash/ash_switches.h" #include "ash/cancel_mode.h" #include "ash/shell.h" #include "ash/shell_delegate.h" #include "ash/shell_window_ids.h" #include "ash/wm/session_state_animator.h" #include "base/command_line.h" #include "ui/aura/root_window.h" #include "ui/views/corewm/compound_event_filter.h" #if defined(OS_CHROMEOS) #include "base/chromeos/chromeos_version.h" #endif namespace ash { SessionStateControllerImpl::TestApi::TestApi( SessionStateControllerImpl* controller) : controller_(controller) { } SessionStateControllerImpl::TestApi::~TestApi() { } SessionStateControllerImpl::SessionStateControllerImpl() : login_status_(user::LOGGED_IN_NONE), system_is_locked_(false), shutting_down_(false), shutdown_after_lock_(false) { Shell::GetPrimaryRootWindow()->AddRootWindowObserver(this); } SessionStateControllerImpl::~SessionStateControllerImpl() { Shell::GetPrimaryRootWindow()->RemoveRootWindowObserver(this); } void SessionStateControllerImpl::OnLoginStateChanged(user::LoginStatus status) { if (status != user::LOGGED_IN_LOCKED) login_status_ = status; system_is_locked_ = (status == user::LOGGED_IN_LOCKED); } void SessionStateControllerImpl::OnAppTerminating() { // If we hear that Chrome is exiting but didn't request it ourselves, all we // can really hope for is that we'll have time to clear the screen. if (!shutting_down_) { shutting_down_ = true; Shell* shell = ash::Shell::GetInstance(); shell->env_filter()->set_cursor_hidden_by_filter(false); shell->cursor_manager()->HideCursor(); animator_->StartAnimation( internal::SessionStateAnimator::kAllContainersMask, internal::SessionStateAnimator::ANIMATION_HIDE_IMMEDIATELY, internal::SessionStateAnimator::ANIMATION_SPEED_IMMEDIATE); } } void SessionStateControllerImpl::OnLockStateChanged(bool locked) { if (shutting_down_ || (system_is_locked_ == locked)) return; system_is_locked_ = locked; if (locked) { animator_->StartAnimation( internal::SessionStateAnimator::LOCK_SCREEN_CONTAINERS, internal::SessionStateAnimator::ANIMATION_FADE_IN, internal::SessionStateAnimator::ANIMATION_SPEED_SHOW_LOCK_SCREEN); DispatchCancelMode(); FOR_EACH_OBSERVER(LockStateObserver, observers_, OnLockStateEvent(LockStateObserver::EVENT_LOCK_ANIMATION_STARTED)); lock_timer_.Stop(); lock_fail_timer_.Stop(); if (shutdown_after_lock_) { shutdown_after_lock_ = false; StartLockToShutdownTimer(); } } else { animator_->StartAnimation( internal::SessionStateAnimator::DESKTOP_BACKGROUND | internal::SessionStateAnimator::LAUNCHER | internal::SessionStateAnimator::NON_LOCK_SCREEN_CONTAINERS, internal::SessionStateAnimator::ANIMATION_RESTORE, internal::SessionStateAnimator::ANIMATION_SPEED_IMMEDIATE); } } void SessionStateControllerImpl::OnStartingLock() { if (shutting_down_ || system_is_locked_) return; animator_->StartAnimation( internal::SessionStateAnimator::LAUNCHER, internal::SessionStateAnimator::ANIMATION_HIDE_IMMEDIATELY, internal::SessionStateAnimator::ANIMATION_SPEED_IMMEDIATE); animator_->StartAnimation( internal::SessionStateAnimator::NON_LOCK_SCREEN_CONTAINERS, internal::SessionStateAnimator::ANIMATION_FULL_CLOSE, internal::SessionStateAnimator::ANIMATION_SPEED_FAST); DispatchCancelMode(); FOR_EACH_OBSERVER(LockStateObserver, observers_, OnLockStateEvent(LockStateObserver::EVENT_LOCK_ANIMATION_STARTED)); // Hide the screen locker containers so we can make them fade in later. animator_->StartAnimation( internal::SessionStateAnimator::LOCK_SCREEN_CONTAINERS, internal::SessionStateAnimator::ANIMATION_HIDE_IMMEDIATELY, internal::SessionStateAnimator::ANIMATION_SPEED_IMMEDIATE); } void SessionStateControllerImpl::StartLockAnimationAndLockImmediately() { animator_->StartAnimation( internal::SessionStateAnimator::NON_LOCK_SCREEN_CONTAINERS, internal::SessionStateAnimator::ANIMATION_PARTIAL_CLOSE, internal::SessionStateAnimator::ANIMATION_SPEED_UNDOABLE); DispatchCancelMode(); FOR_EACH_OBSERVER(LockStateObserver, observers_, OnLockStateEvent(LockStateObserver::EVENT_LOCK_ANIMATION_STARTED)); OnLockTimeout(); } void SessionStateControllerImpl::StartLockAnimation(bool shutdown_after_lock) { shutdown_after_lock_ = shutdown_after_lock; animator_->StartAnimation( internal::SessionStateAnimator::NON_LOCK_SCREEN_CONTAINERS, internal::SessionStateAnimator::ANIMATION_PARTIAL_CLOSE, internal::SessionStateAnimator::ANIMATION_SPEED_UNDOABLE); DispatchCancelMode(); FOR_EACH_OBSERVER(LockStateObserver, observers_, OnLockStateEvent(LockStateObserver::EVENT_PRELOCK_ANIMATION_STARTED)); StartLockTimer(); } void SessionStateControllerImpl::StartShutdownAnimation() { animator_->StartAnimation( internal::SessionStateAnimator::kAllContainersMask, internal::SessionStateAnimator::ANIMATION_PARTIAL_CLOSE, internal::SessionStateAnimator::ANIMATION_SPEED_UNDOABLE); StartPreShutdownAnimationTimer(); } bool SessionStateControllerImpl::LockRequested() { return lock_fail_timer_.IsRunning(); } bool SessionStateControllerImpl::ShutdownRequested() { return shutting_down_; } bool SessionStateControllerImpl::CanCancelLockAnimation() { return lock_timer_.IsRunning(); } void SessionStateControllerImpl::CancelLockAnimation() { if (!CanCancelLockAnimation()) return; shutdown_after_lock_ = false; animator_->StartAnimation( internal::SessionStateAnimator::NON_LOCK_SCREEN_CONTAINERS, internal::SessionStateAnimator::ANIMATION_UNDO_PARTIAL_CLOSE, internal::SessionStateAnimator::ANIMATION_SPEED_REVERT); lock_timer_.Stop(); } bool SessionStateControllerImpl::CanCancelShutdownAnimation() { return pre_shutdown_timer_.IsRunning() || shutdown_after_lock_ || lock_to_shutdown_timer_.IsRunning(); } void SessionStateControllerImpl::CancelShutdownAnimation() { if (!CanCancelShutdownAnimation()) return; if (lock_to_shutdown_timer_.IsRunning()) { lock_to_shutdown_timer_.Stop(); return; } if (shutdown_after_lock_) { shutdown_after_lock_ = false; return; } if (system_is_locked_) { // If we've already started shutdown transition at lock screen // desktop background needs to be restored immediately. animator_->StartAnimation( internal::SessionStateAnimator::DESKTOP_BACKGROUND, internal::SessionStateAnimator::ANIMATION_RESTORE, internal::SessionStateAnimator::ANIMATION_SPEED_IMMEDIATE); animator_->StartAnimation( internal::SessionStateAnimator::kAllLockScreenContainersMask, internal::SessionStateAnimator::ANIMATION_UNDO_PARTIAL_CLOSE, internal::SessionStateAnimator::ANIMATION_SPEED_REVERT); } else { animator_->StartAnimation( internal::SessionStateAnimator::kAllContainersMask, internal::SessionStateAnimator::ANIMATION_UNDO_PARTIAL_CLOSE, internal::SessionStateAnimator::ANIMATION_SPEED_REVERT); } pre_shutdown_timer_.Stop(); } void SessionStateControllerImpl::RequestShutdown() { if (!shutting_down_) RequestShutdownImpl(); } void SessionStateControllerImpl::RequestShutdownImpl() { DCHECK(!shutting_down_); shutting_down_ = true; Shell* shell = ash::Shell::GetInstance(); shell->env_filter()->set_cursor_hidden_by_filter(false); shell->cursor_manager()->HideCursor(); if (login_status_ != user::LOGGED_IN_NONE) { // Hide the other containers before starting the animation. // ANIMATION_FULL_CLOSE will make the screen locker windows partially // transparent, and we don't want the other windows to show through. animator_->StartAnimation( internal::SessionStateAnimator::NON_LOCK_SCREEN_CONTAINERS | internal::SessionStateAnimator::LAUNCHER, internal::SessionStateAnimator::ANIMATION_HIDE_IMMEDIATELY, internal::SessionStateAnimator::ANIMATION_SPEED_IMMEDIATE); animator_->StartAnimation( internal::SessionStateAnimator::kAllLockScreenContainersMask, internal::SessionStateAnimator::ANIMATION_FULL_CLOSE, internal::SessionStateAnimator::ANIMATION_SPEED_FAST); } else { animator_->StartAnimation( internal::SessionStateAnimator::kAllContainersMask, internal::SessionStateAnimator::ANIMATION_FULL_CLOSE, internal::SessionStateAnimator::ANIMATION_SPEED_FAST); } StartRealShutdownTimer(); } void SessionStateControllerImpl::OnRootWindowHostCloseRequested( const aura::RootWindow*) { Shell::GetInstance()->delegate()->Exit(); } void SessionStateControllerImpl::StartLockTimer() { lock_timer_.Stop(); lock_timer_.Start( FROM_HERE, animator_->GetDuration( internal::SessionStateAnimator::ANIMATION_SPEED_UNDOABLE), this, &SessionStateControllerImpl::OnLockTimeout); } void SessionStateControllerImpl::OnLockTimeout() { delegate_->RequestLockScreen(); lock_fail_timer_.Start( FROM_HERE, base::TimeDelta::FromMilliseconds(kLockFailTimeoutMs), this, &SessionStateControllerImpl::OnLockFailTimeout); } void SessionStateControllerImpl::OnLockFailTimeout() { DCHECK(!system_is_locked_); // Undo lock animation. animator_->StartAnimation( internal::SessionStateAnimator::LAUNCHER | internal::SessionStateAnimator::NON_LOCK_SCREEN_CONTAINERS, internal::SessionStateAnimator::ANIMATION_RESTORE, internal::SessionStateAnimator::ANIMATION_SPEED_IMMEDIATE); } void SessionStateControllerImpl::StartLockToShutdownTimer() { shutdown_after_lock_ = false; lock_to_shutdown_timer_.Stop(); lock_to_shutdown_timer_.Start( FROM_HERE, base::TimeDelta::FromMilliseconds(kLockToShutdownTimeoutMs), this, &SessionStateControllerImpl::OnLockToShutdownTimeout); } void SessionStateControllerImpl::OnLockToShutdownTimeout() { DCHECK(system_is_locked_); StartShutdownAnimation(); } void SessionStateControllerImpl::StartPreShutdownAnimationTimer() { pre_shutdown_timer_.Stop(); pre_shutdown_timer_.Start( FROM_HERE, base::TimeDelta::FromMilliseconds(kShutdownTimeoutMs), this, &SessionStateControllerImpl::OnPreShutdownAnimationTimeout); } void SessionStateControllerImpl::OnPreShutdownAnimationTimeout() { if (!shutting_down_) RequestShutdownImpl(); } void SessionStateControllerImpl::StartRealShutdownTimer() { base::TimeDelta duration = base::TimeDelta::FromMilliseconds(kShutdownRequestDelayMs); duration += animator_->GetDuration( internal::SessionStateAnimator::ANIMATION_SPEED_FAST); real_shutdown_timer_.Start( FROM_HERE, duration, this, &SessionStateControllerImpl::OnRealShutdownTimeout); } void SessionStateControllerImpl::OnRealShutdownTimeout() { DCHECK(shutting_down_); #if defined(OS_CHROMEOS) if (!base::chromeos::IsRunningOnChromeOS()) { ShellDelegate* delegate = Shell::GetInstance()->delegate(); if (delegate) { delegate->Exit(); return; } } #endif delegate_->RequestShutdown(); } void SessionStateControllerImpl::OnLockScreenHide(base::Closure& callback) { callback.Run(); } void SessionStateControllerImpl::SetLockScreenDisplayedCallback( base::Closure& callback) { NOTIMPLEMENTED(); } } // namespace ash