blob: dbd97a7b75c173f2c0974bfc34621e2ed4ed94de [file] [log] [blame]
// 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