Home | History | Annotate | Download | only in test
      1 // Copyright 2014 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/test/test_session_state_animator.h"
      6 
      7 #include <vector>
      8 
      9 #include "base/bind.h"
     10 
     11 namespace ash {
     12 namespace test {
     13 
     14 namespace {
     15 // A no-op callback that can be used when managing an animation that didn't
     16 // actually have a callback given.
     17 void DummyCallback() {}
     18 }
     19 
     20 const SessionStateAnimator::Container
     21     TestSessionStateAnimator::kAllContainers[] = {
     22         SessionStateAnimator::DESKTOP_BACKGROUND,
     23         SessionStateAnimator::LAUNCHER,
     24         SessionStateAnimator::NON_LOCK_SCREEN_CONTAINERS,
     25         SessionStateAnimator::LOCK_SCREEN_BACKGROUND,
     26         SessionStateAnimator::LOCK_SCREEN_CONTAINERS,
     27         SessionStateAnimator::LOCK_SCREEN_RELATED_CONTAINERS,
     28         SessionStateAnimator::ROOT_CONTAINER
     29     };
     30 
     31 // A simple SessionStateAnimator::AnimationSequence that tracks the number of
     32 // attached sequences.  The callback will be invoked if all animations complete
     33 // successfully.
     34 class TestSessionStateAnimator::AnimationSequence
     35     : public SessionStateAnimator::AnimationSequence {
     36  public:
     37   AnimationSequence(base::Closure callback, TestSessionStateAnimator* animator)
     38       : SessionStateAnimator::AnimationSequence(callback),
     39         sequence_count_(0),
     40         sequence_aborted_(false),
     41         animator_(animator) {
     42   }
     43 
     44   virtual ~AnimationSequence() {}
     45 
     46   virtual void SequenceAttached() {
     47     ++sequence_count_;
     48   }
     49 
     50   // Notify the sequence that is has completed.
     51   virtual void SequenceFinished(bool successfully) {
     52     DCHECK_GT(sequence_count_, 0);
     53     --sequence_count_;
     54     sequence_aborted_ |= !successfully;
     55     if (sequence_count_ == 0) {
     56       if (sequence_aborted_)
     57         OnAnimationAborted();
     58       else
     59         OnAnimationCompleted();
     60     }
     61   }
     62 
     63   // ash::SessionStateAnimator::AnimationSequence:
     64   virtual void StartAnimation(int container_mask,
     65                               AnimationType type,
     66                               AnimationSpeed speed) OVERRIDE {
     67     animator_->StartAnimationInSequence(container_mask, type, speed, this);
     68   }
     69 
     70  private:
     71   // Tracks the number of contained animations.
     72   int sequence_count_;
     73 
     74   // True if the sequence was aborted.
     75   bool sequence_aborted_;
     76 
     77   // The TestSessionAnimator that created this.  Not owned.
     78   TestSessionStateAnimator* animator_;
     79 
     80   DISALLOW_COPY_AND_ASSIGN(AnimationSequence);
     81 };
     82 
     83 TestSessionStateAnimator::ActiveAnimation::ActiveAnimation(
     84     int animation_epoch,
     85     base::TimeDelta duration,
     86     SessionStateAnimator::Container container,
     87     AnimationType type,
     88     AnimationSpeed speed,
     89     base::Closure success_callback,
     90     base::Closure failed_callback)
     91     : animation_epoch(animation_epoch),
     92       remaining_duration(duration),
     93       container(container),
     94       type(type),
     95       speed(speed),
     96       success_callback(success_callback),
     97       failed_callback(failed_callback) {
     98 }
     99 
    100 TestSessionStateAnimator::ActiveAnimation::~ActiveAnimation() {
    101 }
    102 
    103 TestSessionStateAnimator::TestSessionStateAnimator()
    104     : last_animation_epoch_(0),
    105       is_background_hidden_(false) {
    106 }
    107 
    108 TestSessionStateAnimator::~TestSessionStateAnimator() {
    109   CompleteAllAnimations(false);
    110 }
    111 
    112 void TestSessionStateAnimator::ResetAnimationEpoch() {
    113   CompleteAllAnimations(false);
    114   last_animation_epoch_ = 0;
    115 }
    116 
    117 void TestSessionStateAnimator::Advance(const base::TimeDelta& duration) {
    118   for (ActiveAnimationsMap::iterator container_iter =
    119            active_animations_.begin();
    120        container_iter != active_animations_.end();
    121        ++container_iter) {
    122     AnimationList::iterator animation_iter = (*container_iter).second.begin();
    123     while (animation_iter != (*container_iter).second.end()) {
    124       ActiveAnimation& active_animation = *animation_iter;
    125       active_animation.remaining_duration -= duration;
    126       if (active_animation.remaining_duration <= base::TimeDelta()) {
    127         active_animation.success_callback.Run();
    128         animation_iter = (*container_iter).second.erase(animation_iter);
    129       } else {
    130         ++animation_iter;
    131       }
    132     }
    133   }
    134 }
    135 
    136 void TestSessionStateAnimator::CompleteAnimations(int animation_epoch,
    137                                                   bool completed_successfully) {
    138   for (ActiveAnimationsMap::iterator container_iter =
    139            active_animations_.begin();
    140        container_iter != active_animations_.end();
    141        ++container_iter) {
    142     AnimationList::iterator animation_iter = (*container_iter).second.begin();
    143     while (animation_iter != (*container_iter).second.end()) {
    144       ActiveAnimation active_animation = *animation_iter;
    145       if (active_animation.animation_epoch <= animation_epoch) {
    146         if (completed_successfully)
    147           active_animation.success_callback.Run();
    148         else
    149           active_animation.failed_callback.Run();
    150         animation_iter = (*container_iter).second.erase(animation_iter);
    151       } else {
    152         ++animation_iter;
    153       }
    154     }
    155   }
    156 }
    157 
    158 void TestSessionStateAnimator::CompleteAllAnimations(
    159     bool completed_successfully) {
    160   CompleteAnimations(last_animation_epoch_, completed_successfully);
    161 }
    162 
    163 bool TestSessionStateAnimator::IsContainerAnimated(
    164     SessionStateAnimator::Container container,
    165     SessionStateAnimator::AnimationType type) const {
    166   ActiveAnimationsMap::const_iterator container_iter =
    167       active_animations_.find(container);
    168   if (container_iter != active_animations_.end()) {
    169     for (AnimationList::const_iterator animation_iter =
    170           (*container_iter).second.begin();
    171          animation_iter != (*container_iter).second.end();
    172          ++animation_iter) {
    173       const ActiveAnimation& active_animation = *animation_iter;
    174       if (active_animation.type == type)
    175         return true;
    176     }
    177   }
    178   return false;
    179 }
    180 
    181 bool TestSessionStateAnimator::AreContainersAnimated(
    182     int container_mask, SessionStateAnimator::AnimationType type) const {
    183   for (size_t i = 0; i < arraysize(kAllContainers); ++i) {
    184     if (container_mask & kAllContainers[i] &&
    185         !IsContainerAnimated(kAllContainers[i], type)) {
    186       return false;
    187     }
    188   }
    189   return true;
    190 }
    191 
    192 size_t TestSessionStateAnimator::GetAnimationCount() const {
    193   size_t count = 0;
    194   for (ActiveAnimationsMap::const_iterator container_iter =
    195           active_animations_.begin();
    196        container_iter != active_animations_.end();
    197        ++container_iter) {
    198     count += (*container_iter).second.size();
    199   }
    200   return count;
    201 }
    202 
    203 void TestSessionStateAnimator::StartAnimation(int container_mask,
    204                                               AnimationType type,
    205                                               AnimationSpeed speed) {
    206   ++last_animation_epoch_;
    207   for (size_t i = 0; i < arraysize(kAllContainers); ++i) {
    208     if (container_mask & kAllContainers[i]) {
    209       // Use a dummy no-op callback because one isn't required by the client
    210       // but one is required when completing or aborting animations.
    211       base::Closure callback = base::Bind(&DummyCallback);
    212       AddAnimation(kAllContainers[i], type, speed, callback, callback);
    213     }
    214   }
    215 }
    216 
    217 void TestSessionStateAnimator::StartAnimationWithCallback(
    218     int container_mask,
    219     AnimationType type,
    220     AnimationSpeed speed,
    221     base::Closure callback) {
    222   ++last_animation_epoch_;
    223   for (size_t i = 0; i < arraysize(kAllContainers); ++i)
    224     if (container_mask & kAllContainers[i]) {
    225       // ash::SessionStateAnimatorImpl invokes the callback whether or not the
    226       // animation was completed successfully or not.
    227       AddAnimation(kAllContainers[i], type, speed, callback, callback);
    228     }
    229 }
    230 
    231 ash::SessionStateAnimator::AnimationSequence*
    232     TestSessionStateAnimator::BeginAnimationSequence(base::Closure callback) {
    233   return new AnimationSequence(callback, this);
    234 }
    235 
    236 bool TestSessionStateAnimator::IsBackgroundHidden() const {
    237   return is_background_hidden_;
    238 }
    239 
    240 void TestSessionStateAnimator::ShowBackground() {
    241   is_background_hidden_ = false;
    242 }
    243 
    244 void TestSessionStateAnimator::HideBackground() {
    245   is_background_hidden_ = true;
    246 }
    247 
    248 void TestSessionStateAnimator::StartAnimationInSequence(
    249     int container_mask,
    250     AnimationType type,
    251     AnimationSpeed speed,
    252     AnimationSequence* animation_sequence) {
    253   ++last_animation_epoch_;
    254   for (size_t i = 0; i < arraysize(kAllContainers); ++i) {
    255     if (container_mask & kAllContainers[i]) {
    256       base::Closure success_callback =
    257           base::Bind(&AnimationSequence::SequenceFinished,
    258                      base::Unretained(animation_sequence), true);
    259       base::Closure failed_callback =
    260           base::Bind(&AnimationSequence::SequenceFinished,
    261                      base::Unretained(animation_sequence), false);
    262       animation_sequence->SequenceAttached();
    263       AddAnimation(kAllContainers[i], type, speed, success_callback,
    264           failed_callback);
    265     }
    266   }
    267 }
    268 
    269 void TestSessionStateAnimator::AddAnimation(
    270     SessionStateAnimator::Container container,
    271     AnimationType type,
    272     AnimationSpeed speed,
    273     base::Closure success_callback,
    274     base::Closure failed_callback) {
    275   base::TimeDelta duration = GetDuration(speed);
    276   ActiveAnimation active_animation(last_animation_epoch_,
    277                                    duration,
    278                                    container,
    279                                    type,
    280                                    speed,
    281                                    success_callback,
    282                                    failed_callback);
    283   // This test double is limited to only have one animation active for a given
    284   // container at a time.
    285   AbortAnimation(container);
    286   active_animations_[container].push_back(active_animation);
    287 }
    288 
    289 void TestSessionStateAnimator::AbortAnimation(
    290     SessionStateAnimator::Container container) {
    291   ActiveAnimationsMap::iterator container_iter =
    292       active_animations_.find(container);
    293   if (container_iter != active_animations_.end()) {
    294     AnimationList::iterator animation_iter = (*container_iter).second.begin();
    295     while (animation_iter != (*container_iter).second.end()) {
    296       ActiveAnimation active_animation = *animation_iter;
    297       active_animation.failed_callback.Run();
    298       animation_iter = (*container_iter).second.erase(animation_iter);
    299     }
    300   }
    301 }
    302 
    303 }  // namespace test
    304 }  // namespace ash
    305