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: 29 WindowAnimationsTest() {} 30 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: 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 }; 49 base::TimeDelta duration() { return duration_; } 50 51 protected: 52 // ui::LayerAnimationObserver: 53 virtual void OnLayerAnimationScheduled( 54 ui::LayerAnimationSequence* sequence) OVERRIDE { 55 duration_ = animator_->GetTransitionDuration(); 56 animator_->RemoveObserver(this); 57 } 58 virtual void OnLayerAnimationEnded( 59 ui::LayerAnimationSequence* sequence) OVERRIDE {} 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 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 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 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 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