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 "ui/wm/core/window_animations.h"
7 #include "base/time/time.h"
8 #include "ui/aura/test/aura_test_base.h"
9 #include "ui/aura/test/test_windows.h"
10 #include "ui/aura/window.h"
11 #include "ui/compositor/layer.h"
12 #include "ui/compositor/layer_animator.h"
13 #include "ui/compositor/scoped_animation_duration_scale_mode.h"
14 #include "ui/gfx/animation/animation_container_element.h"
15 #include "ui/gfx/vector2d.h"
16 #include "ui/wm/core/transient_window_manager.h"
17 #include "ui/wm/core/transient_window_stacking_client.h"
18 #include "ui/wm/core/window_util.h"
19 #include "ui/wm/public/animation_host.h"
27 template<typename T
>int GetZPosition(const T
* child
) {
28 const T
* parent
= child
->parent();
29 const std::vector
<T
*> children
= parent
->children();
30 typename
std::vector
<T
*>::const_iterator iter
=
31 std::find(children
.begin(), children
.end(), child
);
32 DCHECK(iter
!= children
.end());
33 return iter
- children
.begin();
36 int GetWindowZPosition(const aura::Window
* child
) {
37 return GetZPosition
<aura::Window
>(child
);
40 int GetLayerZPosition(const ui::Layer
* child
) {
41 return GetZPosition
<ui::Layer
>(child
);
46 class WindowAnimationsTest
: public aura::test::AuraTestBase
{
48 WindowAnimationsTest() {}
50 virtual void TearDown() OVERRIDE
{
51 AuraTestBase::TearDown();
55 DISALLOW_COPY_AND_ASSIGN(WindowAnimationsTest
);
58 TEST_F(WindowAnimationsTest
, LayerTargetVisibility
) {
59 scoped_ptr
<aura::Window
> window(
60 aura::test::CreateTestWindowWithId(0, NULL
));
62 // Layer target visibility changes according to Show/Hide.
64 EXPECT_TRUE(window
->layer()->GetTargetVisibility());
66 EXPECT_FALSE(window
->layer()->GetTargetVisibility());
68 EXPECT_TRUE(window
->layer()->GetTargetVisibility());
71 TEST_F(WindowAnimationsTest
, LayerTargetVisibility_AnimateShow
) {
72 // Tests if opacity and transform are reset when only show animation is
73 // enabled. See also LayerTargetVisibility_AnimateHide.
74 // Since the window is not visible after Hide() is called, opacity and
75 // transform shouldn't matter in case of ANIMATE_SHOW, but we reset them
76 // to keep consistency.
78 scoped_ptr
<aura::Window
> window(aura::test::CreateTestWindowWithId(0, NULL
));
79 SetWindowVisibilityAnimationTransition(window
.get(), ANIMATE_SHOW
);
81 // Layer target visibility and opacity change according to Show/Hide.
83 AnimateOnChildWindowVisibilityChanged(window
.get(), true);
84 EXPECT_TRUE(window
->layer()->GetTargetVisibility());
85 EXPECT_EQ(1, window
->layer()->opacity());
88 AnimateOnChildWindowVisibilityChanged(window
.get(), false);
89 EXPECT_FALSE(window
->layer()->GetTargetVisibility());
90 EXPECT_EQ(0, window
->layer()->opacity());
91 EXPECT_EQ(gfx::Transform(), window
->layer()->transform());
94 AnimateOnChildWindowVisibilityChanged(window
.get(), true);
95 EXPECT_TRUE(window
->layer()->GetTargetVisibility());
96 EXPECT_EQ(1, window
->layer()->opacity());
99 TEST_F(WindowAnimationsTest
, LayerTargetVisibility_AnimateHide
) {
100 // Tests if opacity and transform are reset when only hide animation is
101 // enabled. Hide animation changes opacity and transform in addition to
102 // visibility, so we need to reset not only visibility but also opacity
103 // and transform to show the window.
105 scoped_ptr
<aura::Window
> window(aura::test::CreateTestWindowWithId(0, NULL
));
106 SetWindowVisibilityAnimationTransition(window
.get(), ANIMATE_HIDE
);
108 // Layer target visibility and opacity change according to Show/Hide.
110 AnimateOnChildWindowVisibilityChanged(window
.get(), true);
111 EXPECT_TRUE(window
->layer()->GetTargetVisibility());
112 EXPECT_EQ(1, window
->layer()->opacity());
113 EXPECT_EQ(gfx::Transform(), window
->layer()->transform());
116 AnimateOnChildWindowVisibilityChanged(window
.get(), false);
117 EXPECT_FALSE(window
->layer()->GetTargetVisibility());
118 EXPECT_EQ(0, window
->layer()->opacity());
121 AnimateOnChildWindowVisibilityChanged(window
.get(), true);
122 EXPECT_TRUE(window
->layer()->GetTargetVisibility());
123 EXPECT_EQ(1, window
->layer()->opacity());
124 EXPECT_EQ(gfx::Transform(), window
->layer()->transform());
127 TEST_F(WindowAnimationsTest
, HideAnimationDetachLayers
) {
128 scoped_ptr
<aura::Window
> parent(aura::test::CreateTestWindowWithId(0, NULL
));
130 scoped_ptr
<aura::Window
> other(
131 aura::test::CreateTestWindowWithId(1, parent
.get()));
133 scoped_ptr
<aura::Window
> animating_window(
134 aura::test::CreateTestWindowWithId(2, parent
.get()));
135 SetWindowVisibilityAnimationTransition(animating_window
.get(), ANIMATE_HIDE
);
137 EXPECT_EQ(0, GetWindowZPosition(other
.get()));
138 EXPECT_EQ(1, GetWindowZPosition(animating_window
.get()));
139 EXPECT_EQ(0, GetLayerZPosition(other
->layer()));
140 EXPECT_EQ(1, GetLayerZPosition(animating_window
->layer()));
143 ui::ScopedAnimationDurationScaleMode
scale_mode(
144 ui::ScopedAnimationDurationScaleMode::FAST_DURATION
);
145 ui::Layer
* animating_layer
= animating_window
->layer();
147 animating_window
->Hide();
148 EXPECT_TRUE(AnimateOnChildWindowVisibilityChanged(
149 animating_window
.get(), false));
150 EXPECT_TRUE(animating_layer
->GetAnimator()->is_animating());
151 EXPECT_FALSE(animating_layer
->delegate());
153 // Make sure the Hide animation create another layer, and both are in
155 EXPECT_NE(animating_window
->layer(), animating_layer
);
157 std::find(parent
->layer()->children().begin(),
158 parent
->layer()->children().end(),
160 parent
->layer()->children().end());
162 std::find(parent
->layer()->children().begin(),
163 parent
->layer()->children().end(),
164 animating_window
->layer()) !=
165 parent
->layer()->children().end());
166 // Current layer must be already hidden.
167 EXPECT_FALSE(animating_window
->layer()->visible());
169 EXPECT_EQ(1, GetWindowZPosition(animating_window
.get()));
170 EXPECT_EQ(1, GetLayerZPosition(animating_window
->layer()));
171 EXPECT_EQ(2, GetLayerZPosition(animating_layer
));
173 parent
->StackChildAtTop(other
.get());
174 EXPECT_EQ(0, GetWindowZPosition(animating_window
.get()));
175 EXPECT_EQ(1, GetWindowZPosition(other
.get()));
177 EXPECT_EQ(0, GetLayerZPosition(animating_window
->layer()));
178 EXPECT_EQ(1, GetLayerZPosition(other
->layer()));
179 // Make sure the animating layer is on top.
180 EXPECT_EQ(2, GetLayerZPosition(animating_layer
));
182 // Animating layer must be gone
183 animating_layer
->GetAnimator()->StopAnimating();
185 std::find(parent
->layer()->children().begin(),
186 parent
->layer()->children().end(),
188 parent
->layer()->children().end());
192 TEST_F(WindowAnimationsTest
, HideAnimationDetachLayersWithTransientChildren
) {
193 TransientWindowStackingClient transient_stacking_client
;
195 scoped_ptr
<aura::Window
> parent(aura::test::CreateTestWindowWithId(0, NULL
));
197 scoped_ptr
<aura::Window
> other(
198 aura::test::CreateTestWindowWithId(1, parent
.get()));
200 scoped_ptr
<aura::Window
> animating_window(
201 aura::test::CreateTestWindowWithId(2, parent
.get()));
202 SetWindowVisibilityAnimationTransition(animating_window
.get(), ANIMATE_HIDE
);
204 scoped_ptr
<aura::Window
> transient1(
205 aura::test::CreateTestWindowWithId(3, parent
.get()));
206 scoped_ptr
<aura::Window
> transient2(
207 aura::test::CreateTestWindowWithId(4, parent
.get()));
209 TransientWindowManager::Get(animating_window
.get());
210 AddTransientChild(animating_window
.get(), transient1
.get());
211 AddTransientChild(animating_window
.get(), transient2
.get());
213 EXPECT_EQ(0, GetWindowZPosition(other
.get()));
214 EXPECT_EQ(1, GetWindowZPosition(animating_window
.get()));
215 EXPECT_EQ(2, GetWindowZPosition(transient1
.get()));
216 EXPECT_EQ(3, GetWindowZPosition(transient2
.get()));
219 ui::ScopedAnimationDurationScaleMode
scale_mode(
220 ui::ScopedAnimationDurationScaleMode::FAST_DURATION
);
221 ui::Layer
* animating_layer
= animating_window
->layer();
223 animating_window
->Hide();
224 EXPECT_TRUE(AnimateOnChildWindowVisibilityChanged(
225 animating_window
.get(), false));
226 EXPECT_TRUE(animating_layer
->GetAnimator()->is_animating());
227 EXPECT_FALSE(animating_layer
->delegate());
229 EXPECT_EQ(1, GetWindowZPosition(animating_window
.get()));
230 EXPECT_EQ(2, GetWindowZPosition(transient1
.get()));
231 EXPECT_EQ(3, GetWindowZPosition(transient2
.get()));
233 EXPECT_EQ(1, GetLayerZPosition(animating_window
->layer()));
234 EXPECT_EQ(2, GetLayerZPosition(transient1
->layer()));
235 EXPECT_EQ(3, GetLayerZPosition(transient2
->layer()));
236 EXPECT_EQ(4, GetLayerZPosition(animating_layer
));
238 parent
->StackChildAtTop(other
.get());
240 EXPECT_EQ(0, GetWindowZPosition(animating_window
.get()));
241 EXPECT_EQ(1, GetWindowZPosition(transient1
.get()));
242 EXPECT_EQ(2, GetWindowZPosition(transient2
.get()));
243 EXPECT_EQ(3, GetWindowZPosition(other
.get()));
245 EXPECT_EQ(0, GetLayerZPosition(animating_window
->layer()));
246 EXPECT_EQ(1, GetLayerZPosition(transient1
->layer()));
247 EXPECT_EQ(2, GetLayerZPosition(transient2
->layer()));
248 EXPECT_EQ(3, GetLayerZPosition(other
->layer()));
249 // Make sure the animating layer is on top of all windows.
250 EXPECT_EQ(4, GetLayerZPosition(animating_layer
));
254 // A simple AnimationHost implementation for the NotifyHideCompleted test.
255 class NotifyHideCompletedAnimationHost
: public aura::client::AnimationHost
{
257 NotifyHideCompletedAnimationHost() : hide_completed_(false) {}
258 virtual ~NotifyHideCompletedAnimationHost() {}
260 // Overridden from TestWindowDelegate:
261 virtual void OnWindowHidingAnimationCompleted() OVERRIDE
{
262 hide_completed_
= true;
265 virtual void SetHostTransitionOffsets(
266 const gfx::Vector2d
& top_left
,
267 const gfx::Vector2d
& bottom_right
) OVERRIDE
{}
269 bool hide_completed() const { return hide_completed_
; }
272 bool hide_completed_
;
274 DISALLOW_COPY_AND_ASSIGN(NotifyHideCompletedAnimationHost
);
277 TEST_F(WindowAnimationsTest
, NotifyHideCompleted
) {
278 NotifyHideCompletedAnimationHost animation_host
;
279 scoped_ptr
<aura::Window
> window(aura::test::CreateTestWindowWithId(0, NULL
));
280 aura::client::SetAnimationHost(window
.get(), &animation_host
);
281 wm::SetWindowVisibilityAnimationType(
282 window
.get(), WINDOW_VISIBILITY_ANIMATION_TYPE_FADE
);
283 AnimateOnChildWindowVisibilityChanged(window
.get(), true);
284 EXPECT_TRUE(window
->layer()->visible());
286 EXPECT_FALSE(animation_host
.hide_completed());
287 AnimateOnChildWindowVisibilityChanged(window
.get(), false);
288 EXPECT_TRUE(animation_host
.hide_completed());