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..41a19961e075147a89b85dd7e44bb6fba7aa1e5b |
--- /dev/null |
+++ b/ash/wm/session_state_animator.cc |
@@ -0,0 +1,323 @@ |
+// 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_window_ids.h" |
+#include "ui/aura/root_window.h" |
+#include "ui/compositor/layer_animation_sequence.h" |
+ |
+namespace ash { |
+namespace internal { |
+ |
+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 = 200; |
+ |
+// 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 |
+ |
+void SessionStateAnimator::TestApi::TriggerHideBlackLayerTimeout() { |
+ animator_->DropBlackLayer(); |
+ animator_->hide_black_layer_timer_.Stop(); |
+} |
+ |
+bool SessionStateAnimator::TestApi::ContainersAreAnimated( |
+ int container_mask, AnimationType type) const { |
+ aura::Window::Windows containers; |
+ animator_->GetContainers(container_mask, &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 ANIMATION_SLOW_CLOSE: |
+ if (layer->GetTargetTransform() != GetSlowCloseTransform()) |
+ return false; |
+ break; |
+ case ANIMATION_UNDO_SLOW_CLOSE: |
+ if (layer->GetTargetTransform() != ui::Transform()) |
+ return false; |
+ break; |
+ case ANIMATION_FAST_CLOSE: |
+ if (layer->GetTargetTransform() != GetFastCloseTransform() || |
+ layer->GetTargetOpacity() > 0.0001) |
+ return false; |
+ break; |
+ case ANIMATION_FADE_IN: |
+ if (layer->GetTargetOpacity() < 0.9999) |
+ return false; |
+ break; |
+ case ANIMATION_HIDE: |
+ if (layer->GetTargetOpacity() > 0.0001) |
+ return false; |
+ break; |
+ case ANIMATION_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::BlackLayerIsVisible() const { |
+ return animator_->black_layer_.get() && |
+ animator_->black_layer_->visible(); |
+} |
+ |
+gfx::Rect SessionStateAnimator::TestApi::GetBlackLayerBounds() const { |
+ ui::Layer* layer = animator_->black_layer_.get(); |
+ return layer ? layer->bounds() : gfx::Rect(); |
+} |
+ |
+const int SessionStateAnimator::kAllLockScreenContainersMask = |
+ SessionStateAnimator::LOCK_SCREEN_BACKGROUND | |
+ SessionStateAnimator::LOCK_SCREEN_CONTAINERS | |
+ SessionStateAnimator::LOCK_SCREEN_RELATED_CONTAINERS; |
+ |
+const int SessionStateAnimator::kAllContainersMask = |
+ SessionStateAnimator::kAllLockScreenContainersMask | |
+ SessionStateAnimator::DESKTOP_BACKGROUND | |
+ SessionStateAnimator::LAUNCHER | |
+ SessionStateAnimator::NON_LOCK_SCREEN_CONTAINERS; |
+ |
+SessionStateAnimator::SessionStateAnimator() { |
+ Shell::GetPrimaryRootWindow()->AddRootWindowObserver(this); |
+} |
+ |
+SessionStateAnimator::~SessionStateAnimator() { |
+ Shell::GetPrimaryRootWindow()->RemoveRootWindowObserver(this); |
+} |
+ |
+// Fills |containers| with the containers described by |container_mask|. |
+void SessionStateAnimator::GetContainers(int container_mask, |
+ aura::Window::Windows* containers) { |
+ aura::RootWindow* root_window = Shell::GetPrimaryRootWindow(); |
+ containers->clear(); |
+ |
+ if (container_mask & DESKTOP_BACKGROUND) { |
+ containers->push_back(Shell::GetContainer( |
+ root_window, |
+ internal::kShellWindowId_DesktopBackgroundContainer)); |
+ } |
+ if (container_mask & LAUNCHER) { |
+ containers->push_back(Shell::GetContainer( |
+ root_window, |
+ internal::kShellWindowId_LauncherContainer)); |
+ } |
+ if (container_mask & NON_LOCK_SCREEN_CONTAINERS) { |
+ // TODO(antrim): Figure out a way to eliminate a need to exclude launcher |
+ // in such way. |
+ aura::Window* non_lock_screen_containers = Shell::GetContainer( |
+ root_window, |
+ internal::kShellWindowId_NonLockScreenContainersContainer); |
+ aura::Window::Windows children = non_lock_screen_containers->children(); |
+ |
+ for (aura::Window::Windows::const_iterator it = children.begin(); |
+ it != children.end(); ++it) { |
+ aura::Window* window = *it; |
+ if (window->id() == internal::kShellWindowId_LauncherContainer) |
+ continue; |
+ containers->push_back(window); |
+ } |
+ } |
+ if (container_mask & LOCK_SCREEN_BACKGROUND) { |
+ containers->push_back(Shell::GetContainer( |
+ root_window, |
+ internal::kShellWindowId_LockScreenBackgroundContainer)); |
+ } |
+ if (container_mask & LOCK_SCREEN_CONTAINERS) { |
+ containers->push_back(Shell::GetContainer( |
+ root_window, |
+ internal::kShellWindowId_LockScreenContainersContainer)); |
+ } |
+ if (container_mask & LOCK_SCREEN_RELATED_CONTAINERS) { |
+ containers->push_back(Shell::GetContainer( |
+ root_window, |
+ internal::kShellWindowId_LockScreenRelatedContainersContainer)); |
+ } |
+} |
+ |
+// Apply animation |type| to all containers described by |container_mask|. |
+void SessionStateAnimator::StartAnimation(int container_mask, |
+ AnimationType type) { |
+ aura::Window::Windows containers; |
+ GetContainers(container_mask, &containers); |
+ |
+ for (aura::Window::Windows::const_iterator it = containers.begin(); |
+ it != containers.end(); ++it) { |
+ aura::Window* window = *it; |
+ switch (type) { |
+ case ANIMATION_SLOW_CLOSE: |
+ StartSlowCloseAnimationForWindow(window); |
+ break; |
+ case ANIMATION_UNDO_SLOW_CLOSE: |
+ StartUndoSlowCloseAnimationForWindow(window); |
+ break; |
+ case ANIMATION_FAST_CLOSE: |
+ StartFastCloseAnimationForWindow(window); |
+ break; |
+ case ANIMATION_FADE_IN: |
+ FadeInWindow(window); |
+ break; |
+ case ANIMATION_HIDE: |
+ HideWindow(window); |
+ break; |
+ case ANIMATION_RESTORE: |
+ RestoreWindow(window); |
+ break; |
+ default: |
+ NOTREACHED() << "Unhandled animation type " << type; |
+ } |
+ } |
+} |
+ |
+void SessionStateAnimator::OnRootWindowResized(const aura::RootWindow* root, |
+ const gfx::Size& new_size) { |
+ if (black_layer_.get()) |
+ black_layer_->SetBounds(gfx::Rect(root->bounds().size())); |
+} |
+ |
+void SessionStateAnimator::ShowBlackLayer() { |
+ if (hide_black_layer_timer_.IsRunning()) |
+ hide_black_layer_timer_.Stop(); |
+ |
+ if (!black_layer_.get()) { |
+ black_layer_.reset(new ui::Layer(ui::LAYER_SOLID_COLOR)); |
+ black_layer_->SetColor(SK_ColorBLACK); |
+ |
+ ui::Layer* root_layer = Shell::GetPrimaryRootWindow()->layer(); |
+ black_layer_->SetBounds(root_layer->bounds()); |
+ root_layer->Add(black_layer_.get()); |
+ root_layer->StackAtBottom(black_layer_.get()); |
+ } |
+ black_layer_->SetVisible(true); |
+} |
+ |
+void SessionStateAnimator::DropBlackLayer() { |
+ black_layer_.reset(); |
+} |
+ |
+void SessionStateAnimator::ScheduleDropBlackLayer() { |
+ hide_black_layer_timer_.Stop(); |
+ hide_black_layer_timer_.Start( |
+ FROM_HERE, |
+ base::TimeDelta::FromMilliseconds(kUndoSlowCloseAnimMs), |
+ this, &SessionStateAnimator::DropBlackLayer); |
+} |
+ |
+} // namespace internal |
+} // namespace ash |