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.
4
5 #include "ash/wm/window_animations.h"
6
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"
19
20 using aura::Window;
21 using ui::Layer;
22
23 namespace ash {
24 class WindowAnimationsTest : public ash::test::AshTestBase {
25 public:
WindowAnimationsTest()26 WindowAnimationsTest() {}
27
TearDown()28 virtual void TearDown() OVERRIDE {
29 AshTestBase::TearDown();
30 }
31
32 private:
33 DISALLOW_COPY_AND_ASSIGN(WindowAnimationsTest);
34 };
35
36 // Listens to animation scheduled notifications. Remembers the transition
37 // duration of the first sequence.
38 class MinimizeAnimationObserver : public ui::LayerAnimationObserver {
39 public:
MinimizeAnimationObserver(ui::LayerAnimator * animator)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.
45 };
duration()46 base::TimeDelta duration() { return duration_; }
47
48 protected:
49 // ui::LayerAnimationObserver:
OnLayerAnimationScheduled(ui::LayerAnimationSequence * sequence)50 virtual void OnLayerAnimationScheduled(
51 ui::LayerAnimationSequence* sequence) OVERRIDE {
52 duration_ = animator_->GetTransitionDuration();
53 animator_->RemoveObserver(this);
54 }
OnLayerAnimationEnded(ui::LayerAnimationSequence * sequence)55 virtual void OnLayerAnimationEnded(
56 ui::LayerAnimationSequence* sequence) OVERRIDE {}
OnLayerAnimationAborted(ui::LayerAnimationSequence * sequence)57 virtual void OnLayerAnimationAborted(
58 ui::LayerAnimationSequence* sequence) OVERRIDE {}
59
60 private:
61 ui::LayerAnimator* animator_;
62 base::TimeDelta duration_;
63
64 DISALLOW_COPY_AND_ASSIGN(MinimizeAnimationObserver);
65 };
66
TEST_F(WindowAnimationsTest,HideShowBrightnessGrayscaleAnimation)67 TEST_F(WindowAnimationsTest, HideShowBrightnessGrayscaleAnimation) {
68 ui::ScopedAnimationDurationScaleMode test_duration_mode(
69 ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION);
70
71 scoped_ptr<aura::Window> window(CreateTestWindowInShellWithId(0));
72 window->Show();
73 EXPECT_TRUE(window->layer()->visible());
74
75 // Hiding.
76 ::wm::SetWindowVisibilityAnimationType(
77 window.get(),
78 WINDOW_VISIBILITY_ANIMATION_TYPE_BRIGHTNESS_GRAYSCALE);
79 AnimateOnChildWindowVisibilityChanged(window.get(), false);
80 EXPECT_EQ(0.0f, window->layer()->GetTargetOpacity());
81 EXPECT_FALSE(window->layer()->GetTargetVisibility());
82 EXPECT_FALSE(window->layer()->visible());
83
84 // Showing.
85 ::wm::SetWindowVisibilityAnimationType(
86 window.get(),
87 WINDOW_VISIBILITY_ANIMATION_TYPE_BRIGHTNESS_GRAYSCALE);
88 AnimateOnChildWindowVisibilityChanged(window.get(), true);
89 EXPECT_EQ(0.0f, window->layer()->GetTargetBrightness());
90 EXPECT_EQ(0.0f, window->layer()->GetTargetGrayscale());
91 EXPECT_TRUE(window->layer()->visible());
92
93 // Stays shown.
94 window->layer()->GetAnimator()->Step(base::TimeTicks::Now() +
95 base::TimeDelta::FromSeconds(5));
96 EXPECT_EQ(0.0f, window->layer()->GetTargetBrightness());
97 EXPECT_EQ(0.0f, window->layer()->GetTargetGrayscale());
98 EXPECT_TRUE(window->layer()->visible());
99 }
100
TEST_F(WindowAnimationsTest,LayerTargetVisibility)101 TEST_F(WindowAnimationsTest, LayerTargetVisibility) {
102 scoped_ptr<aura::Window> window(CreateTestWindowInShellWithId(0));
103
104 // Layer target visibility changes according to Show/Hide.
105 window->Show();
106 EXPECT_TRUE(window->layer()->GetTargetVisibility());
107 window->Hide();
108 EXPECT_FALSE(window->layer()->GetTargetVisibility());
109 window->Show();
110 EXPECT_TRUE(window->layer()->GetTargetVisibility());
111 }
112
113 namespace wm {
114
TEST_F(WindowAnimationsTest,CrossFadeToBounds)115 TEST_F(WindowAnimationsTest, CrossFadeToBounds) {
116 ui::ScopedAnimationDurationScaleMode test_duration_mode(
117 ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION);
118
119 scoped_ptr<Window> window(CreateTestWindowInShellWithId(0));
120 window->SetBounds(gfx::Rect(5, 10, 320, 240));
121 window->Show();
122
123 Layer* old_layer = window->layer();
124 EXPECT_EQ(1.0f, old_layer->GetTargetOpacity());
125
126 // Cross fade to a larger size, as in a maximize animation.
127 GetWindowState(window.get())->SetBoundsDirectCrossFade(
128 gfx::Rect(0, 0, 640, 480));
129 // Window's layer has been replaced.
130 EXPECT_NE(old_layer, window->layer());
131 // Original layer stays opaque and stretches to new size.
132 EXPECT_EQ(1.0f, old_layer->GetTargetOpacity());
133 EXPECT_EQ("5,10 320x240", old_layer->bounds().ToString());
134 gfx::Transform grow_transform;
135 grow_transform.Translate(-5.f, -10.f);
136 grow_transform.Scale(640.f / 320.f, 480.f / 240.f);
137 EXPECT_EQ(grow_transform, old_layer->GetTargetTransform());
138 // New layer animates in to the identity transform.
139 EXPECT_EQ(1.0f, window->layer()->GetTargetOpacity());
140 EXPECT_EQ(gfx::Transform(), window->layer()->GetTargetTransform());
141
142 // Run the animations to completion.
143 old_layer->GetAnimator()->Step(base::TimeTicks::Now() +
144 base::TimeDelta::FromSeconds(1));
145 window->layer()->GetAnimator()->Step(base::TimeTicks::Now() +
146 base::TimeDelta::FromSeconds(1));
147
148 // Cross fade to a smaller size, as in a restore animation.
149 old_layer = window->layer();
150 GetWindowState(window.get())->SetBoundsDirectCrossFade(
151 gfx::Rect(5, 10, 320, 240));
152 // Again, window layer has been replaced.
153 EXPECT_NE(old_layer, window->layer());
154 // Original layer fades out and stretches down to new size.
155 EXPECT_EQ(0.0f, old_layer->GetTargetOpacity());
156 EXPECT_EQ("0,0 640x480", old_layer->bounds().ToString());
157 gfx::Transform shrink_transform;
158 shrink_transform.Translate(5.f, 10.f);
159 shrink_transform.Scale(320.f / 640.f, 240.f / 480.f);
160 EXPECT_EQ(shrink_transform, old_layer->GetTargetTransform());
161 // New layer animates in to the identity transform.
162 EXPECT_EQ(1.0f, window->layer()->GetTargetOpacity());
163 EXPECT_EQ(gfx::Transform(), window->layer()->GetTargetTransform());
164
165 old_layer->GetAnimator()->Step(base::TimeTicks::Now() +
166 base::TimeDelta::FromSeconds(1));
167 window->layer()->GetAnimator()->Step(base::TimeTicks::Now() +
168 base::TimeDelta::FromSeconds(1));
169 }
170
171 } // namespace wm
172
TEST_F(WindowAnimationsTest,LockAnimationDuration)173 TEST_F(WindowAnimationsTest, LockAnimationDuration) {
174 ui::ScopedAnimationDurationScaleMode test_duration_mode(
175 ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION);
176
177 scoped_ptr<Window> window(CreateTestWindowInShellWithId(0));
178 Layer* layer = window->layer();
179 window->SetBounds(gfx::Rect(5, 10, 320, 240));
180 window->Show();
181
182 // Test that it is possible to override transition duration when it is not
183 // locked.
184 {
185 ui::ScopedLayerAnimationSettings settings1(layer->GetAnimator());
186 settings1.SetTransitionDuration(base::TimeDelta::FromMilliseconds(1000));
187 {
188 ui::ScopedLayerAnimationSettings settings2(layer->GetAnimator());
189 // Duration is not locked so it gets overridden.
190 settings2.SetTransitionDuration(base::TimeDelta::FromMilliseconds(50));
191 wm::GetWindowState(window.get())->Minimize();
192 EXPECT_TRUE(layer->GetAnimator()->is_animating());
193 // Expect duration from the inner scope
194 EXPECT_EQ(50,
195 layer->GetAnimator()->GetTransitionDuration().InMilliseconds());
196 }
197 window->Show();
198 layer->GetAnimator()->StopAnimating();
199 }
200
201 // Test that it is possible to lock transition duration
202 {
203 // Update layer as minimizing will replace the window's layer.
204 layer = window->layer();
205 ui::ScopedLayerAnimationSettings settings1(layer->GetAnimator());
206 settings1.SetTransitionDuration(base::TimeDelta::FromMilliseconds(1000));
207 // Duration is locked in outer scope.
208 settings1.LockTransitionDuration();
209 {
210 ui::ScopedLayerAnimationSettings settings2(layer->GetAnimator());
211 // Transition duration setting is ignored.
212 settings2.SetTransitionDuration(base::TimeDelta::FromMilliseconds(50));
213 wm::GetWindowState(window.get())->Minimize();
214 EXPECT_TRUE(layer->GetAnimator()->is_animating());
215 // Expect duration from the outer scope
216 EXPECT_EQ(1000,
217 layer->GetAnimator()->GetTransitionDuration().InMilliseconds());
218 }
219 window->Show();
220 layer->GetAnimator()->StopAnimating();
221 }
222
223 // Test that duration respects default.
224 {
225 layer = window->layer();
226 // Query default duration.
227 MinimizeAnimationObserver observer(layer->GetAnimator());
228 wm::GetWindowState(window.get())->Minimize();
229 EXPECT_TRUE(layer->GetAnimator()->is_animating());
230 base::TimeDelta default_duration(observer.duration());
231 window->Show();
232 layer->GetAnimator()->StopAnimating();
233
234 layer = window->layer();
235 ui::ScopedLayerAnimationSettings settings(layer->GetAnimator());
236 settings.LockTransitionDuration();
237 // Setting transition duration is ignored since duration is locked
238 settings.SetTransitionDuration(base::TimeDelta::FromMilliseconds(1000));
239 wm::GetWindowState(window.get())->Minimize();
240 EXPECT_TRUE(layer->GetAnimator()->is_animating());
241 // Expect default duration (200ms for stock ash minimizing animation).
242 EXPECT_EQ(default_duration.InMilliseconds(),
243 layer->GetAnimator()->GetTransitionDuration().InMilliseconds());
244 window->Show();
245 layer->GetAnimator()->StopAnimating();
246 }
247 }
248
249 } // namespace ash
250