Home | History | Annotate | Download | only in wm
      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