Home | History | Annotate | Download | only in core
      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 }  // namespace wm
    292