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 "ui/wm/core/window_animations.h" 6 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" 20 21 using aura::Window; 22 using ui::Layer; 23 24 namespace wm { 25 namespace { 26 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(); 34 } 35 36 int GetWindowZPosition(const aura::Window* child) { 37 return GetZPosition<aura::Window>(child); 38 } 39 40 int GetLayerZPosition(const ui::Layer* child) { 41 return GetZPosition<ui::Layer>(child); 42 } 43 44 } // namespace 45 46 class WindowAnimationsTest : public aura::test::AuraTestBase { 47 public: 48 WindowAnimationsTest() {} 49 50 virtual void TearDown() OVERRIDE { 51 AuraTestBase::TearDown(); 52 } 53 54 private: 55 DISALLOW_COPY_AND_ASSIGN(WindowAnimationsTest); 56 }; 57 58 TEST_F(WindowAnimationsTest, LayerTargetVisibility) { 59 scoped_ptr<aura::Window> window( 60 aura::test::CreateTestWindowWithId(0, NULL)); 61 62 // Layer target visibility changes according to Show/Hide. 63 window->Show(); 64 EXPECT_TRUE(window->layer()->GetTargetVisibility()); 65 window->Hide(); 66 EXPECT_FALSE(window->layer()->GetTargetVisibility()); 67 window->Show(); 68 EXPECT_TRUE(window->layer()->GetTargetVisibility()); 69 } 70 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. 77 78 scoped_ptr<aura::Window> window(aura::test::CreateTestWindowWithId(0, NULL)); 79 SetWindowVisibilityAnimationTransition(window.get(), ANIMATE_SHOW); 80 81 // Layer target visibility and opacity change according to Show/Hide. 82 window->Show(); 83 AnimateOnChildWindowVisibilityChanged(window.get(), true); 84 EXPECT_TRUE(window->layer()->GetTargetVisibility()); 85 EXPECT_EQ(1, window->layer()->opacity()); 86 87 window->Hide(); 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()); 92 93 window->Show(); 94 AnimateOnChildWindowVisibilityChanged(window.get(), true); 95 EXPECT_TRUE(window->layer()->GetTargetVisibility()); 96 EXPECT_EQ(1, window->layer()->opacity()); 97 } 98 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. 104 105 scoped_ptr<aura::Window> window(aura::test::CreateTestWindowWithId(0, NULL)); 106 SetWindowVisibilityAnimationTransition(window.get(), ANIMATE_HIDE); 107 108 // Layer target visibility and opacity change according to Show/Hide. 109 window->Show(); 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()); 114 115 window->Hide(); 116 AnimateOnChildWindowVisibilityChanged(window.get(), false); 117 EXPECT_FALSE(window->layer()->GetTargetVisibility()); 118 EXPECT_EQ(0, window->layer()->opacity()); 119 120 window->Show(); 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()); 125 } 126 127 TEST_F(WindowAnimationsTest, HideAnimationDetachLayers) { 128 scoped_ptr<aura::Window> parent(aura::test::CreateTestWindowWithId(0, NULL)); 129 130 scoped_ptr<aura::Window> other( 131 aura::test::CreateTestWindowWithId(1, parent.get())); 132 133 scoped_ptr<aura::Window> animating_window( 134 aura::test::CreateTestWindowWithId(2, parent.get())); 135 SetWindowVisibilityAnimationTransition(animating_window.get(), ANIMATE_HIDE); 136 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())); 141 142 { 143 ui::ScopedAnimationDurationScaleMode scale_mode( 144 ui::ScopedAnimationDurationScaleMode::FAST_DURATION); 145 ui::Layer* animating_layer = animating_window->layer(); 146 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()); 152 153 // Make sure the Hide animation create another layer, and both are in 154 // the parent layer. 155 EXPECT_NE(animating_window->layer(), animating_layer); 156 EXPECT_TRUE( 157 std::find(parent->layer()->children().begin(), 158 parent->layer()->children().end(), 159 animating_layer) != 160 parent->layer()->children().end()); 161 EXPECT_TRUE( 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()); 168 169 EXPECT_EQ(1, GetWindowZPosition(animating_window.get())); 170 EXPECT_EQ(1, GetLayerZPosition(animating_window->layer())); 171 EXPECT_EQ(2, GetLayerZPosition(animating_layer)); 172 173 parent->StackChildAtTop(other.get()); 174 EXPECT_EQ(0, GetWindowZPosition(animating_window.get())); 175 EXPECT_EQ(1, GetWindowZPosition(other.get())); 176 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)); 181 182 // Animating layer must be gone 183 animating_layer->GetAnimator()->StopAnimating(); 184 EXPECT_TRUE( 185 std::find(parent->layer()->children().begin(), 186 parent->layer()->children().end(), 187 animating_layer) == 188 parent->layer()->children().end()); 189 } 190 } 191 192 TEST_F(WindowAnimationsTest, HideAnimationDetachLayersWithTransientChildren) { 193 TransientWindowStackingClient transient_stacking_client; 194 195 scoped_ptr<aura::Window> parent(aura::test::CreateTestWindowWithId(0, NULL)); 196 197 scoped_ptr<aura::Window> other( 198 aura::test::CreateTestWindowWithId(1, parent.get())); 199 200 scoped_ptr<aura::Window> animating_window( 201 aura::test::CreateTestWindowWithId(2, parent.get())); 202 SetWindowVisibilityAnimationTransition(animating_window.get(), ANIMATE_HIDE); 203 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())); 208 209 TransientWindowManager::Get(animating_window.get()); 210 AddTransientChild(animating_window.get(), transient1.get()); 211 AddTransientChild(animating_window.get(), transient2.get()); 212 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())); 217 218 { 219 ui::ScopedAnimationDurationScaleMode scale_mode( 220 ui::ScopedAnimationDurationScaleMode::FAST_DURATION); 221 ui::Layer* animating_layer = animating_window->layer(); 222 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()); 228 229 EXPECT_EQ(1, GetWindowZPosition(animating_window.get())); 230 EXPECT_EQ(2, GetWindowZPosition(transient1.get())); 231 EXPECT_EQ(3, GetWindowZPosition(transient2.get())); 232 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)); 237 238 parent->StackChildAtTop(other.get()); 239 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())); 244 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)); 251 } 252 } 253 254 // A simple AnimationHost implementation for the NotifyHideCompleted test. 255 class NotifyHideCompletedAnimationHost : public aura::client::AnimationHost { 256 public: 257 NotifyHideCompletedAnimationHost() : hide_completed_(false) {} 258 virtual ~NotifyHideCompletedAnimationHost() {} 259 260 // Overridden from TestWindowDelegate: 261 virtual void OnWindowHidingAnimationCompleted() OVERRIDE { 262 hide_completed_ = true; 263 } 264 265 virtual void SetHostTransitionOffsets( 266 const gfx::Vector2d& top_left, 267 const gfx::Vector2d& bottom_right) OVERRIDE {} 268 269 bool hide_completed() const { return hide_completed_; } 270 271 private: 272 bool hide_completed_; 273 274 DISALLOW_COPY_AND_ASSIGN(NotifyHideCompletedAnimationHost); 275 }; 276 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()); 285 286 EXPECT_FALSE(animation_host.hide_completed()); 287 AnimateOnChildWindowVisibilityChanged(window.get(), false); 288 EXPECT_TRUE(animation_host.hide_completed()); 289 } 290 291 // The rotation animation for hiding a window should not leak the animation 292 // observer. 293 TEST_F(WindowAnimationsTest, RotateHideNoLeak) { 294 ui::ScopedAnimationDurationScaleMode scale_mode( 295 ui::ScopedAnimationDurationScaleMode::FAST_DURATION); 296 297 scoped_ptr<aura::Window> window(aura::test::CreateTestWindowWithId(0, NULL)); 298 ui::Layer* animating_layer = window->layer(); 299 wm::SetWindowVisibilityAnimationType(window.get(), 300 WINDOW_VISIBILITY_ANIMATION_TYPE_ROTATE); 301 302 AnimateOnChildWindowVisibilityChanged(window.get(), true); 303 AnimateOnChildWindowVisibilityChanged(window.get(), false); 304 305 animating_layer->GetAnimator()->StopAnimating(); 306 } 307 308 } // namespace wm 309