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 #include "ui/gfx/animation/animation_container_element.h"
20
21 using aura::Window;
22 using ui::Layer;
23
24 namespace ash {
25 namespace internal {
26
27 class WindowAnimationsTest : public ash::test::AshTestBase {
28 public:
WindowAnimationsTest()29 WindowAnimationsTest() {}
30
TearDown()31 virtual void TearDown() OVERRIDE {
32 AshTestBase::TearDown();
33 }
34
35 private:
36 DISALLOW_COPY_AND_ASSIGN(WindowAnimationsTest);
37 };
38
39 // Listens to animation scheduled notifications. Remembers the transition
40 // duration of the first sequence.
41 class MinimizeAnimationObserver : public ui::LayerAnimationObserver {
42 public:
MinimizeAnimationObserver(ui::LayerAnimator * animator)43 explicit MinimizeAnimationObserver(ui::LayerAnimator* animator)
44 : animator_(animator) {
45 animator_->AddObserver(this);
46 // RemoveObserver is called when the first animation is scheduled and so
47 // there should be no need for now to remove it in destructor.
48 };
duration()49 base::TimeDelta duration() { return duration_; }
50
51 protected:
52 // ui::LayerAnimationObserver:
OnLayerAnimationScheduled(ui::LayerAnimationSequence * sequence)53 virtual void OnLayerAnimationScheduled(
54 ui::LayerAnimationSequence* sequence) OVERRIDE {
55 duration_ = animator_->GetTransitionDuration();
56 animator_->RemoveObserver(this);
57 }
OnLayerAnimationEnded(ui::LayerAnimationSequence * sequence)58 virtual void OnLayerAnimationEnded(
59 ui::LayerAnimationSequence* sequence) OVERRIDE {}
OnLayerAnimationAborted(ui::LayerAnimationSequence * sequence)60 virtual void OnLayerAnimationAborted(
61 ui::LayerAnimationSequence* sequence) OVERRIDE {}
62
63 private:
64 ui::LayerAnimator* animator_;
65 base::TimeDelta duration_;
66
67 DISALLOW_COPY_AND_ASSIGN(MinimizeAnimationObserver);
68 };
69
TEST_F(WindowAnimationsTest,HideShowBrightnessGrayscaleAnimation)70 TEST_F(WindowAnimationsTest, HideShowBrightnessGrayscaleAnimation) {
71 scoped_ptr<aura::Window> window(CreateTestWindowInShellWithId(0));
72 window->Show();
73 EXPECT_TRUE(window->layer()->visible());
74
75 // Hiding.
76 views::corewm::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 views::corewm::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 gfx::AnimationContainerElement* element =
95 static_cast<gfx::AnimationContainerElement*>(
96 window->layer()->GetAnimator());
97 element->Step(base::TimeTicks::Now() +
98 base::TimeDelta::FromSeconds(5));
99 EXPECT_EQ(0.0f, window->layer()->GetTargetBrightness());
100 EXPECT_EQ(0.0f, window->layer()->GetTargetGrayscale());
101 EXPECT_TRUE(window->layer()->visible());
102 }
103
TEST_F(WindowAnimationsTest,LayerTargetVisibility)104 TEST_F(WindowAnimationsTest, LayerTargetVisibility) {
105 scoped_ptr<aura::Window> window(CreateTestWindowInShellWithId(0));
106
107 // Layer target visibility changes according to Show/Hide.
108 window->Show();
109 EXPECT_TRUE(window->layer()->GetTargetVisibility());
110 window->Hide();
111 EXPECT_FALSE(window->layer()->GetTargetVisibility());
112 window->Show();
113 EXPECT_TRUE(window->layer()->GetTargetVisibility());
114 }
115
TEST_F(WindowAnimationsTest,CrossFadeToBounds)116 TEST_F(WindowAnimationsTest, CrossFadeToBounds) {
117 ui::ScopedAnimationDurationScaleMode normal_duration_mode(
118 ui::ScopedAnimationDurationScaleMode::NORMAL_DURATION);
119
120 scoped_ptr<Window> window(CreateTestWindowInShellWithId(0));
121 window->SetBounds(gfx::Rect(5, 10, 320, 240));
122 window->Show();
123
124 Layer* old_layer = window->layer();
125 EXPECT_EQ(1.0f, old_layer->GetTargetOpacity());
126
127 // Cross fade to a larger size, as in a maximize animation.
128 CrossFadeToBounds(window.get(), 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 static_cast<gfx::AnimationContainerElement*>(old_layer->GetAnimator())->Step(
144 base::TimeTicks::Now() + base::TimeDelta::FromSeconds(1));
145 static_cast<gfx::AnimationContainerElement*>(window->layer()->GetAnimator())->
146 Step(base::TimeTicks::Now() + base::TimeDelta::FromSeconds(1));
147
148 // Cross fade to a smaller size, as in a restore animation.
149 old_layer = window->layer();
150 CrossFadeToBounds(window.get(), gfx::Rect(5, 10, 320, 240));
151 // Again, window layer has been replaced.
152 EXPECT_NE(old_layer, window->layer());
153 // Original layer fades out and stretches down to new size.
154 EXPECT_EQ(0.0f, old_layer->GetTargetOpacity());
155 EXPECT_EQ("0,0 640x480", old_layer->bounds().ToString());
156 gfx::Transform shrink_transform;
157 shrink_transform.Translate(5.f, 10.f);
158 shrink_transform.Scale(320.f / 640.f, 240.f / 480.f);
159 EXPECT_EQ(shrink_transform, old_layer->GetTargetTransform());
160 // New layer animates in to the identity transform.
161 EXPECT_EQ(1.0f, window->layer()->GetTargetOpacity());
162 EXPECT_EQ(gfx::Transform(), window->layer()->GetTargetTransform());
163
164 static_cast<gfx::AnimationContainerElement*>(old_layer->GetAnimator())->Step(
165 base::TimeTicks::Now() + base::TimeDelta::FromSeconds(1));
166 static_cast<gfx::AnimationContainerElement*>(window->layer()->GetAnimator())->
167 Step(base::TimeTicks::Now() + base::TimeDelta::FromSeconds(1));
168 }
169
TEST_F(WindowAnimationsTest,LockAnimationDuration)170 TEST_F(WindowAnimationsTest, LockAnimationDuration) {
171 ui::ScopedAnimationDurationScaleMode normal_duration_mode(
172 ui::ScopedAnimationDurationScaleMode::NORMAL_DURATION);
173
174 scoped_ptr<Window> window(CreateTestWindowInShellWithId(0));
175 Layer* layer = window->layer();
176 window->SetBounds(gfx::Rect(5, 10, 320, 240));
177 window->Show();
178
179 // Test that it is possible to override transition duration when it is not
180 // locked.
181 {
182 ui::ScopedLayerAnimationSettings settings1(layer->GetAnimator());
183 settings1.SetTransitionDuration(base::TimeDelta::FromMilliseconds(1000));
184 {
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
191 EXPECT_EQ(50,
192 layer->GetAnimator()->GetTransitionDuration().InMilliseconds());
193 }
194 window->Show();
195 layer->GetAnimator()->StopAnimating();
196 }
197
198 // Test that it is possible to lock transition duration
199 {
200 ui::ScopedLayerAnimationSettings settings1(layer->GetAnimator());
201 settings1.SetTransitionDuration(base::TimeDelta::FromMilliseconds(1000));
202 // Duration is locked in outer scope.
203 settings1.LockTransitionDuration();
204 {
205 ui::ScopedLayerAnimationSettings settings2(layer->GetAnimator());
206 // Transition duration setting is ignored.
207 settings2.SetTransitionDuration(base::TimeDelta::FromMilliseconds(50));
208 wm::GetWindowState(window.get())->Minimize();
209 EXPECT_TRUE(layer->GetAnimator()->is_animating());
210 // Expect duration from the outer scope
211 EXPECT_EQ(1000,
212 layer->GetAnimator()->GetTransitionDuration().InMilliseconds());
213 }
214 window->Show();
215 layer->GetAnimator()->StopAnimating();
216 }
217
218 // Test that duration respects default.
219 {
220 // Query default duration.
221 MinimizeAnimationObserver observer(layer->GetAnimator());
222 wm::GetWindowState(window.get())->Minimize();
223 EXPECT_TRUE(layer->GetAnimator()->is_animating());
224 base::TimeDelta default_duration(observer.duration());
225 window->Show();
226 layer->GetAnimator()->StopAnimating();
227
228 ui::ScopedLayerAnimationSettings settings(layer->GetAnimator());
229 settings.LockTransitionDuration();
230 // Setting transition duration is ignored since duration is locked
231 settings.SetTransitionDuration(base::TimeDelta::FromMilliseconds(1000));
232 wm::GetWindowState(window.get())->Minimize();
233 EXPECT_TRUE(layer->GetAnimator()->is_animating());
234 // Expect default duration (200ms for stock ash minimizing animation).
235 EXPECT_EQ(default_duration.InMilliseconds(),
236 layer->GetAnimator()->GetTransitionDuration().InMilliseconds());
237 window->Show();
238 layer->GetAnimator()->StopAnimating();
239 }
240 }
241
242 } // namespace internal
243 } // namespace ash
244