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 |