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 |