Chromium Code Reviews| Index: ash/wm/session_state_animator.cc | 
| diff --git a/ash/wm/session_state_animator.cc b/ash/wm/session_state_animator.cc | 
| new file mode 100644 | 
| index 0000000000000000000000000000000000000000..5b8311488e495c7b86f07396357969a73fbd504f | 
| --- /dev/null | 
| +++ b/ash/wm/session_state_animator.cc | 
| @@ -0,0 +1,304 @@ | 
| +// 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_animator.h" | 
| + | 
| +#include "ash/shell.h" | 
| +#include "ash/shell_delegate.h" | 
| +#include "ash/shell_window_ids.h" | 
| +#include "base/time.h" | 
| +#include "third_party/skia/include/core/SkColor.h" | 
| +#include "ui/aura/root_window.h" | 
| +#include "ui/aura/window.h" | 
| +#include "ui/compositor/layer.h" | 
| +#include "ui/compositor/layer_animation_element.h" | 
| +#include "ui/compositor/layer_animation_sequence.h" | 
| +#include "ui/compositor/layer_animator.h" | 
| +#include "ui/gfx/canvas.h" | 
| +#include "ui/gfx/rect.h" | 
| +#include "ui/gfx/size.h" | 
| +#include "ui/gfx/transform.h" | 
| + | 
| +namespace ash { | 
| + | 
| +namespace { | 
| + | 
| +// Amount of time taken to scale the snapshot of the screen down to a | 
| +// slightly-smaller size once the user starts holding the power button. Used | 
| +// for both the pre-lock and pre-shutdown animations. | 
| +const int kSlowCloseAnimMs = 400; | 
| + | 
| +// Amount of time taken to scale the snapshot of the screen back to its original | 
| +// size when the button is released. | 
| +const int kUndoSlowCloseAnimMs = 100; | 
| + | 
| +// Amount of time taken to scale the snapshot down to a point in the center of | 
| +// the screen once the screen has been locked or we've been notified that the | 
| +// system is shutting down. | 
| +const int kFastCloseAnimMs = 150; | 
| + | 
| +// Amount of time taken to make the lock window fade in when the screen is | 
| +// locked. | 
| +const int kLockFadeInAnimMs = 500; | 
| + | 
| +// Slightly-smaller size that we scale the screen down to for the pre-lock and | 
| +// pre-shutdown states. | 
| +const float kSlowCloseSizeRatio = 0.95f; | 
| + | 
| +// Returns the transform that should be applied to containers for the slow-close | 
| +// animation. | 
| +ui::Transform GetSlowCloseTransform() { | 
| + gfx::Size root_size = Shell::GetPrimaryRootWindow()->bounds().size(); | 
| + ui::Transform transform; | 
| + transform.SetScale(kSlowCloseSizeRatio, kSlowCloseSizeRatio); | 
| + transform.ConcatTranslate( | 
| + floor(0.5 * (1.0 - kSlowCloseSizeRatio) * root_size.width() + 0.5), | 
| + floor(0.5 * (1.0 - kSlowCloseSizeRatio) * root_size.height() + 0.5)); | 
| + return transform; | 
| +} | 
| + | 
| +// Returns the transform that should be applied to containers for the fast-close | 
| +// animation. | 
| +ui::Transform GetFastCloseTransform() { | 
| + gfx::Size root_size = Shell::GetPrimaryRootWindow()->bounds().size(); | 
| + ui::Transform transform; | 
| + transform.SetScale(0.0, 0.0); | 
| + transform.ConcatTranslate(floor(0.5 * root_size.width() + 0.5), | 
| + floor(0.5 * root_size.height() + 0.5)); | 
| + return transform; | 
| +} | 
| + | 
| +// Slowly shrinks |window| to a slightly-smaller size. | 
| +void StartSlowCloseAnimationForWindow(aura::Window* window) { | 
| + ui::LayerAnimator* animator = window->layer()->GetAnimator(); | 
| + animator->set_preemption_strategy( | 
| + ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); | 
| + animator->StartAnimation( | 
| + new ui::LayerAnimationSequence( | 
| + ui::LayerAnimationElement::CreateTransformElement( | 
| + GetSlowCloseTransform(), | 
| + base::TimeDelta::FromMilliseconds(kSlowCloseAnimMs)))); | 
| +} | 
| + | 
| +// Quickly undoes the effects of the slow-close animation on |window|. | 
| +void StartUndoSlowCloseAnimationForWindow(aura::Window* window) { | 
| + ui::LayerAnimator* animator = window->layer()->GetAnimator(); | 
| + animator->set_preemption_strategy( | 
| + ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); | 
| + animator->StartAnimation( | 
| + new ui::LayerAnimationSequence( | 
| + ui::LayerAnimationElement::CreateTransformElement( | 
| + ui::Transform(), | 
| + base::TimeDelta::FromMilliseconds(kUndoSlowCloseAnimMs)))); | 
| +} | 
| + | 
| +// Quickly shrinks |window| down to a point in the center of the screen and | 
| +// fades it out to 0 opacity. | 
| +void StartFastCloseAnimationForWindow(aura::Window* window) { | 
| + ui::LayerAnimator* animator = window->layer()->GetAnimator(); | 
| + animator->set_preemption_strategy( | 
| + ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); | 
| + animator->StartAnimation( | 
| + new ui::LayerAnimationSequence( | 
| + ui::LayerAnimationElement::CreateTransformElement( | 
| + GetFastCloseTransform(), | 
| + base::TimeDelta::FromMilliseconds(kFastCloseAnimMs)))); | 
| + animator->StartAnimation( | 
| + new ui::LayerAnimationSequence( | 
| + ui::LayerAnimationElement::CreateOpacityElement( | 
| + 0.0, base::TimeDelta::FromMilliseconds(kFastCloseAnimMs)))); | 
| +} | 
| + | 
| +// Fades |window| in to full opacity. | 
| +void FadeInWindow(aura::Window* window) { | 
| + ui::LayerAnimator* animator = window->layer()->GetAnimator(); | 
| + animator->set_preemption_strategy( | 
| + ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); | 
| + animator->StartAnimation( | 
| + new ui::LayerAnimationSequence( | 
| + ui::LayerAnimationElement::CreateOpacityElement( | 
| + 1.0, base::TimeDelta::FromMilliseconds(kLockFadeInAnimMs)))); | 
| +} | 
| + | 
| +// Makes |window| fully transparent instantaneously. | 
| +void HideWindow(aura::Window* window) { | 
| + window->layer()->SetOpacity(0.0); | 
| +} | 
| + | 
| +// Restores |window| to its original position and scale and full opacity | 
| +// instantaneously. | 
| +void RestoreWindow(aura::Window* window) { | 
| + window->layer()->SetTransform(ui::Transform()); | 
| + window->layer()->SetOpacity(1.0); | 
| +} | 
| + | 
| +} // namespace | 
| + | 
| +bool SessionStateAnimator::TestApi::ContainerGroupIsAnimated( | 
| + ContainerGroup group, AnimationType type) const { | 
| + aura::Window::Windows containers; | 
| + animator_->GetContainers(group, &containers); | 
| + for (aura::Window::Windows::const_iterator it = containers.begin(); | 
| + it != containers.end(); ++it) { | 
| + aura::Window* window = *it; | 
| + ui::Layer* layer = window->layer(); | 
| + | 
| + switch (type) { | 
| + case SLOW_CLOSE: | 
| + if (layer->GetTargetTransform() != GetSlowCloseTransform()) | 
| + return false; | 
| + break; | 
| + case UNDO_SLOW_CLOSE: | 
| + if (layer->GetTargetTransform() != ui::Transform()) | 
| + return false; | 
| + break; | 
| + case FAST_CLOSE: | 
| + if (layer->GetTargetTransform() != GetFastCloseTransform() || | 
| + layer->GetTargetOpacity() > 0.0001) | 
| + return false; | 
| + break; | 
| + case FADE_IN: | 
| + if (layer->GetTargetOpacity() < 0.9999) | 
| + return false; | 
| + break; | 
| + case HIDE: | 
| + if (layer->GetTargetOpacity() > 0.0001) | 
| + return false; | 
| + break; | 
| + case RESTORE: | 
| + if (layer->opacity() < 0.9999 || layer->transform() != ui::Transform()) | 
| + return false; | 
| + break; | 
| + default: | 
| + NOTREACHED() << "Unhandled animation type " << type; | 
| + return false; | 
| + } | 
| + } | 
| + return true; | 
| +} | 
| + | 
| +bool SessionStateAnimator::TestApi::BackgroundLayerIsVisible() const { | 
| + return animator_->background_layer_.get() && | 
| + animator_->background_layer_->visible(); | 
| +} | 
| + | 
| +gfx::Rect SessionStateAnimator::TestApi::GetBackgroundLayerBounds() const { | 
| + ui::Layer* layer = animator_->background_layer_.get(); | 
| + return layer ? layer->bounds() : gfx::Rect(); | 
| +} | 
| + | 
| +SessionStateAnimator::SessionStateAnimator() { | 
| + Shell::GetPrimaryRootWindow()->AddRootWindowObserver(this); | 
| +} | 
| + | 
| +SessionStateAnimator::~SessionStateAnimator() { | 
| + Shell::GetPrimaryRootWindow()->RemoveRootWindowObserver(this); | 
| +} | 
| + | 
| +// Fills |containers| with the containers described by |group|. | 
| +void SessionStateAnimator::GetContainers(ContainerGroup group, | 
| + aura::Window::Windows* containers) { | 
| 
 
Daniel Erat
2012/08/31 17:02:12
nit: fix indenting
 
Denis Kuznetsov (DE-MUC)
2012/09/28 11:52:43
Done.
 
 | 
| + aura::RootWindow* root_window = Shell::GetPrimaryRootWindow(); | 
| + | 
| + aura::Window* non_lock_screen_containers = Shell::GetContainer( | 
| + root_window, | 
| + internal::kShellWindowId_NonLockScreenContainersContainer); | 
| + aura::Window* lock_screen_containers = Shell::GetContainer( | 
| + root_window, | 
| + internal::kShellWindowId_LockScreenContainersContainer); | 
| + aura::Window* lock_screen_related_containers = Shell::GetContainer( | 
| + root_window, | 
| + internal::kShellWindowId_LockScreenRelatedContainersContainer); | 
| + | 
| + containers->clear(); | 
| + switch (group) { | 
| + case ALL_CONTAINERS: | 
| + containers->push_back(non_lock_screen_containers); | 
| + containers->push_back(lock_screen_containers); | 
| + containers->push_back(lock_screen_related_containers); | 
| + break; | 
| + case SCREEN_LOCKER_CONTAINERS: | 
| + containers->push_back(lock_screen_containers); | 
| + break; | 
| + case SCREEN_LOCKER_AND_RELATED_CONTAINERS: | 
| + containers->push_back(lock_screen_containers); | 
| + containers->push_back(lock_screen_related_containers); | 
| + break; | 
| + case ALL_BUT_SCREEN_LOCKER_AND_RELATED_CONTAINERS: | 
| + containers->push_back(non_lock_screen_containers); | 
| + break; | 
| + default: | 
| + NOTREACHED() << "Unhandled container group " << group; | 
| + } | 
| +} | 
| + | 
| +// Apply animation |type| to all containers described by |group|. | 
| +void SessionStateAnimator::StartAnimation(ContainerGroup group, | 
| + AnimationType type) { | 
| + aura::Window::Windows containers; | 
| + GetContainers(group, &containers); | 
| + | 
| + for (aura::Window::Windows::const_iterator it = containers.begin(); | 
| + it != containers.end(); ++it) { | 
| + aura::Window* window = *it; | 
| + switch (type) { | 
| + case SLOW_CLOSE: | 
| + StartSlowCloseAnimationForWindow(window); | 
| + break; | 
| + case UNDO_SLOW_CLOSE: | 
| + StartUndoSlowCloseAnimationForWindow(window); | 
| + break; | 
| + case FAST_CLOSE: | 
| + StartFastCloseAnimationForWindow(window); | 
| + break; | 
| + case FADE_IN: | 
| + FadeInWindow(window); | 
| + break; | 
| + case HIDE: | 
| + HideWindow(window); | 
| + break; | 
| + case RESTORE: | 
| + RestoreWindow(window); | 
| + break; | 
| + default: | 
| + NOTREACHED() << "Unhandled animation type " << type; | 
| + } | 
| + } | 
| +} | 
| + | 
| +void SessionStateAnimator::OnRootWindowResized(const aura::RootWindow* root, | 
| + const gfx::Size& new_size) { | 
| + if (background_layer_.get()) | 
| + background_layer_->SetBounds(gfx::Rect(root->bounds().size())); | 
| +} | 
| + | 
| +void SessionStateAnimator::ShowBackgroundLayer() { | 
| + if (hide_background_layer_timer_.IsRunning()) | 
| + hide_background_layer_timer_.Stop(); | 
| + | 
| + if (!background_layer_.get()) { | 
| + background_layer_.reset(new ui::Layer(ui::LAYER_SOLID_COLOR)); | 
| + background_layer_->SetColor(SK_ColorBLACK); | 
| + | 
| + ui::Layer* root_layer = Shell::GetPrimaryRootWindow()->layer(); | 
| + background_layer_->SetBounds(root_layer->bounds()); | 
| + root_layer->Add(background_layer_.get()); | 
| + root_layer->StackAtBottom(background_layer_.get()); | 
| + } | 
| + background_layer_->SetVisible(true); | 
| +} | 
| + | 
| +void SessionStateAnimator::HideBackgroundLayer() { | 
| + background_layer_.reset(); | 
| +} | 
| + | 
| +void SessionStateAnimator::DropBackgroundLayer() { | 
| 
 
Daniel Erat
2012/08/31 17:02:12
both this method and HideBackgroundLayer drop the
 
Denis Kuznetsov (DE-MUC)
2012/09/28 11:52:43
Done.
 
 | 
| + hide_background_layer_timer_.Stop(); | 
| + hide_background_layer_timer_.Start( | 
| + FROM_HERE, | 
| + base::TimeDelta::FromMilliseconds(kUndoSlowCloseAnimMs), | 
| + this, &SessionStateAnimator::HideBackgroundLayer); | 
| +} | 
| + | 
| +} // namespace ash |