1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "ash/wm/window_animations.h"
7 #include "ash/shell_window_ids.h"
8 #include "ash/test/ash_test_base.h"
9 #include "ash/wm/window_state.h"
10 #include "ash/wm/workspace_controller.h"
11 #include "base/time/time.h"
12 #include "ui/aura/test/test_windows.h"
13 #include "ui/aura/window.h"
14 #include "ui/compositor/layer.h"
15 #include "ui/compositor/layer_animation_observer.h"
16 #include "ui/compositor/layer_animator.h"
17 #include "ui/compositor/scoped_animation_duration_scale_mode.h"
18 #include "ui/compositor/scoped_layer_animation_settings.h"
24 class WindowAnimationsTest
: public ash::test::AshTestBase
{
26 WindowAnimationsTest() {}
28 virtual void TearDown() OVERRIDE
{
29 AshTestBase::TearDown();
33 DISALLOW_COPY_AND_ASSIGN(WindowAnimationsTest
);
36 // Listens to animation scheduled notifications. Remembers the transition
37 // duration of the first sequence.
38 class MinimizeAnimationObserver
: public ui::LayerAnimationObserver
{
40 explicit MinimizeAnimationObserver(ui::LayerAnimator
* animator
)
41 : animator_(animator
) {
42 animator_
->AddObserver(this);
43 // RemoveObserver is called when the first animation is scheduled and so
44 // there should be no need for now to remove it in destructor.
46 base::TimeDelta
duration() { return duration_
; }
49 // ui::LayerAnimationObserver:
50 virtual void OnLayerAnimationScheduled(
51 ui::LayerAnimationSequence
* sequence
) OVERRIDE
{
52 duration_
= animator_
->GetTransitionDuration();
53 animator_
->RemoveObserver(this);
55 virtual void OnLayerAnimationEnded(
56 ui::LayerAnimationSequence
* sequence
) OVERRIDE
{}
57 virtual void OnLayerAnimationAborted(
58 ui::LayerAnimationSequence
* sequence
) OVERRIDE
{}
61 ui::LayerAnimator
* animator_
;
62 base::TimeDelta duration_
;
64 DISALLOW_COPY_AND_ASSIGN(MinimizeAnimationObserver
);
67 TEST_F(WindowAnimationsTest
, HideShowBrightnessGrayscaleAnimation
) {
68 scoped_ptr
<aura::Window
> window(CreateTestWindowInShellWithId(0));
70 EXPECT_TRUE(window
->layer()->visible());
73 ::wm::SetWindowVisibilityAnimationType(
75 WINDOW_VISIBILITY_ANIMATION_TYPE_BRIGHTNESS_GRAYSCALE
);
76 AnimateOnChildWindowVisibilityChanged(window
.get(), false);
77 EXPECT_EQ(0.0f
, window
->layer()->GetTargetOpacity());
78 EXPECT_FALSE(window
->layer()->GetTargetVisibility());
79 EXPECT_FALSE(window
->layer()->visible());
82 ::wm::SetWindowVisibilityAnimationType(
84 WINDOW_VISIBILITY_ANIMATION_TYPE_BRIGHTNESS_GRAYSCALE
);
85 AnimateOnChildWindowVisibilityChanged(window
.get(), true);
86 EXPECT_EQ(0.0f
, window
->layer()->GetTargetBrightness());
87 EXPECT_EQ(0.0f
, window
->layer()->GetTargetGrayscale());
88 EXPECT_TRUE(window
->layer()->visible());
91 window
->layer()->GetAnimator()->Step(base::TimeTicks::Now() +
92 base::TimeDelta::FromSeconds(5));
93 EXPECT_EQ(0.0f
, window
->layer()->GetTargetBrightness());
94 EXPECT_EQ(0.0f
, window
->layer()->GetTargetGrayscale());
95 EXPECT_TRUE(window
->layer()->visible());
98 TEST_F(WindowAnimationsTest
, LayerTargetVisibility
) {
99 scoped_ptr
<aura::Window
> window(CreateTestWindowInShellWithId(0));
101 // Layer target visibility changes according to Show/Hide.
103 EXPECT_TRUE(window
->layer()->GetTargetVisibility());
105 EXPECT_FALSE(window
->layer()->GetTargetVisibility());
107 EXPECT_TRUE(window
->layer()->GetTargetVisibility());
112 TEST_F(WindowAnimationsTest
, CrossFadeToBounds
) {
113 ui::ScopedAnimationDurationScaleMode
normal_duration_mode(
114 ui::ScopedAnimationDurationScaleMode::NORMAL_DURATION
);
116 scoped_ptr
<Window
> window(CreateTestWindowInShellWithId(0));
117 window
->SetBounds(gfx::Rect(5, 10, 320, 240));
120 Layer
* old_layer
= window
->layer();
121 EXPECT_EQ(1.0f
, old_layer
->GetTargetOpacity());
123 // Cross fade to a larger size, as in a maximize animation.
124 GetWindowState(window
.get())->SetBoundsDirectCrossFade(
125 gfx::Rect(0, 0, 640, 480));
126 // Window's layer has been replaced.
127 EXPECT_NE(old_layer
, window
->layer());
128 // Original layer stays opaque and stretches to new size.
129 EXPECT_EQ(1.0f
, old_layer
->GetTargetOpacity());
130 EXPECT_EQ("5,10 320x240", old_layer
->bounds().ToString());
131 gfx::Transform grow_transform
;
132 grow_transform
.Translate(-5.f
, -10.f
);
133 grow_transform
.Scale(640.f
/ 320.f
, 480.f
/ 240.f
);
134 EXPECT_EQ(grow_transform
, old_layer
->GetTargetTransform());
135 // New layer animates in to the identity transform.
136 EXPECT_EQ(1.0f
, window
->layer()->GetTargetOpacity());
137 EXPECT_EQ(gfx::Transform(), window
->layer()->GetTargetTransform());
139 // Run the animations to completion.
140 old_layer
->GetAnimator()->Step(base::TimeTicks::Now() +
141 base::TimeDelta::FromSeconds(1));
142 window
->layer()->GetAnimator()->Step(base::TimeTicks::Now() +
143 base::TimeDelta::FromSeconds(1));
145 // Cross fade to a smaller size, as in a restore animation.
146 old_layer
= window
->layer();
147 GetWindowState(window
.get())->SetBoundsDirectCrossFade(
148 gfx::Rect(5, 10, 320, 240));
149 // Again, window layer has been replaced.
150 EXPECT_NE(old_layer
, window
->layer());
151 // Original layer fades out and stretches down to new size.
152 EXPECT_EQ(0.0f
, old_layer
->GetTargetOpacity());
153 EXPECT_EQ("0,0 640x480", old_layer
->bounds().ToString());
154 gfx::Transform shrink_transform
;
155 shrink_transform
.Translate(5.f
, 10.f
);
156 shrink_transform
.Scale(320.f
/ 640.f
, 240.f
/ 480.f
);
157 EXPECT_EQ(shrink_transform
, old_layer
->GetTargetTransform());
158 // New layer animates in to the identity transform.
159 EXPECT_EQ(1.0f
, window
->layer()->GetTargetOpacity());
160 EXPECT_EQ(gfx::Transform(), window
->layer()->GetTargetTransform());
162 old_layer
->GetAnimator()->Step(base::TimeTicks::Now() +
163 base::TimeDelta::FromSeconds(1));
164 window
->layer()->GetAnimator()->Step(base::TimeTicks::Now() +
165 base::TimeDelta::FromSeconds(1));
170 TEST_F(WindowAnimationsTest
, LockAnimationDuration
) {
171 ui::ScopedAnimationDurationScaleMode
normal_duration_mode(
172 ui::ScopedAnimationDurationScaleMode::NORMAL_DURATION
);
174 scoped_ptr
<Window
> window(CreateTestWindowInShellWithId(0));
175 Layer
* layer
= window
->layer();
176 window
->SetBounds(gfx::Rect(5, 10, 320, 240));
179 // Test that it is possible to override transition duration when it is not
182 ui::ScopedLayerAnimationSettings
settings1(layer
->GetAnimator());
183 settings1
.SetTransitionDuration(base::TimeDelta::FromMilliseconds(1000));
185 ui::ScopedLayerAnimationSettings
settings2(layer
->GetAnimator());
186 // Duration is not locked so it gets overridden.
187 settings2
.SetTransitionDuration(base::TimeDelta::FromMilliseconds(50));
188 wm::GetWindowState(window
.get())->Minimize();
189 EXPECT_TRUE(layer
->GetAnimator()->is_animating());
190 // Expect duration from the inner scope
192 layer
->GetAnimator()->GetTransitionDuration().InMilliseconds());
195 layer
->GetAnimator()->StopAnimating();
198 // Test that it is possible to lock transition duration
200 // Update layer as minimizing will replace the window's layer.
201 layer
= window
->layer();
202 ui::ScopedLayerAnimationSettings
settings1(layer
->GetAnimator());
203 settings1
.SetTransitionDuration(base::TimeDelta::FromMilliseconds(1000));
204 // Duration is locked in outer scope.
205 settings1
.LockTransitionDuration();
207 ui::ScopedLayerAnimationSettings
settings2(layer
->GetAnimator());
208 // Transition duration setting is ignored.
209 settings2
.SetTransitionDuration(base::TimeDelta::FromMilliseconds(50));
210 wm::GetWindowState(window
.get())->Minimize();
211 EXPECT_TRUE(layer
->GetAnimator()->is_animating());
212 // Expect duration from the outer scope
214 layer
->GetAnimator()->GetTransitionDuration().InMilliseconds());
217 layer
->GetAnimator()->StopAnimating();
220 // Test that duration respects default.
222 layer
= window
->layer();
223 // Query default duration.
224 MinimizeAnimationObserver
observer(layer
->GetAnimator());
225 wm::GetWindowState(window
.get())->Minimize();
226 EXPECT_TRUE(layer
->GetAnimator()->is_animating());
227 base::TimeDelta
default_duration(observer
.duration());
229 layer
->GetAnimator()->StopAnimating();
231 layer
= window
->layer();
232 ui::ScopedLayerAnimationSettings
settings(layer
->GetAnimator());
233 settings
.LockTransitionDuration();
234 // Setting transition duration is ignored since duration is locked
235 settings
.SetTransitionDuration(base::TimeDelta::FromMilliseconds(1000));
236 wm::GetWindowState(window
.get())->Minimize();
237 EXPECT_TRUE(layer
->GetAnimator()->is_animating());
238 // Expect default duration (200ms for stock ash minimizing animation).
239 EXPECT_EQ(default_duration
.InMilliseconds(),
240 layer
->GetAnimator()->GetTransitionDuration().InMilliseconds());
242 layer
->GetAnimator()->StopAnimating();