Index: ash/test/test_session_state_animator.cc |
diff --git a/ash/test/test_session_state_animator.cc b/ash/test/test_session_state_animator.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..b1d5b47c4aa22b26ef46445b0759fa832f12200e |
--- /dev/null |
+++ b/ash/test/test_session_state_animator.cc |
@@ -0,0 +1,304 @@ |
+// Copyright 2014 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "ash/test/test_session_state_animator.h" |
+ |
+#include <vector> |
+ |
+#include "base/bind.h" |
+ |
+namespace ash { |
+namespace test { |
+ |
+namespace { |
+// A no-op callback that can be used when managing an animation that didn't |
+// actually have a callback given. |
+void DummyCallback() {} |
+} |
+ |
+const SessionStateAnimator::Container |
+ TestSessionStateAnimator::kAllContainers[] = { |
+ SessionStateAnimator::DESKTOP_BACKGROUND, |
+ SessionStateAnimator::LAUNCHER, |
+ SessionStateAnimator::NON_LOCK_SCREEN_CONTAINERS, |
+ SessionStateAnimator::LOCK_SCREEN_BACKGROUND, |
+ SessionStateAnimator::LOCK_SCREEN_CONTAINERS, |
+ SessionStateAnimator::LOCK_SCREEN_RELATED_CONTAINERS, |
+ SessionStateAnimator::ROOT_CONTAINER |
+ }; |
+ |
+// A simple SessionStateAnimator::AnimationSequence that tracks the number of |
+// attached sequences. The callback will be invoked if all animations complete |
+// successfully. |
+class TestSessionStateAnimator::AnimationSequence |
+ : public SessionStateAnimator::AnimationSequence { |
+ public: |
+ AnimationSequence(base::Closure callback, TestSessionStateAnimator* animator) |
+ : SessionStateAnimator::AnimationSequence(callback), |
+ sequence_count_(0), |
+ sequence_aborted_(false), |
+ animator_(animator) { |
+ } |
+ |
+ virtual ~AnimationSequence() {} |
+ |
+ virtual void SequenceAttached() { |
+ ++sequence_count_; |
+ } |
+ |
+ // Notify the sequence that is has completed. |
+ virtual void SequenceFinished(bool successfully) { |
+ DCHECK_GT(sequence_count_, 0); |
+ --sequence_count_; |
+ sequence_aborted_ |= !successfully; |
+ if (sequence_count_ == 0) { |
+ if (sequence_aborted_) |
+ OnAnimationAborted(); |
+ else |
+ OnAnimationCompleted(); |
+ } |
+ } |
+ |
+ // ash::SessionStateAnimator::AnimationSequence: |
+ virtual void StartAnimation(int container_mask, |
+ AnimationType type, |
+ AnimationSpeed speed) OVERRIDE { |
+ animator_->StartAnimationInSequence(container_mask, type, speed, this); |
+ } |
+ |
+ private: |
+ // Tracks the number of contained animations. |
+ int sequence_count_; |
+ |
+ // True if the sequence was aborted. |
+ bool sequence_aborted_; |
+ |
+ // The TestSessionAnimator that created this. Not owned. |
+ TestSessionStateAnimator* animator_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(AnimationSequence); |
+}; |
+ |
+TestSessionStateAnimator::ActiveAnimation::ActiveAnimation( |
+ int animation_epoch, |
+ base::TimeDelta duration, |
+ SessionStateAnimator::Container container, |
+ AnimationType type, |
+ AnimationSpeed speed, |
+ base::Closure success_callback, |
+ base::Closure failed_callback) |
+ : animation_epoch(animation_epoch), |
+ remaining_duration(duration), |
+ container(container), |
+ type(type), |
+ speed(speed), |
+ success_callback(success_callback), |
+ failed_callback(failed_callback) { |
+} |
+ |
+TestSessionStateAnimator::ActiveAnimation::~ActiveAnimation() { |
+} |
+ |
+TestSessionStateAnimator::TestSessionStateAnimator() |
+ : last_animation_epoch_(0), |
+ is_background_hidden_(false) { |
+} |
+ |
+TestSessionStateAnimator::~TestSessionStateAnimator() { |
+ CompleteAllAnimations(false); |
+} |
+ |
+void TestSessionStateAnimator::ResetAnimationEpoch() { |
+ CompleteAllAnimations(false); |
+ last_animation_epoch_ = 0; |
+} |
+ |
+void TestSessionStateAnimator::Advance(const base::TimeDelta& duration) { |
+ for (ActiveAnimationsMap::iterator container_iter = |
+ active_animations_.begin(); |
+ container_iter != active_animations_.end(); |
+ ++container_iter) { |
+ AnimationList::iterator animation_iter = (*container_iter).second.begin(); |
+ while (animation_iter != (*container_iter).second.end()) { |
+ ActiveAnimation& active_animation = *animation_iter; |
+ active_animation.remaining_duration -= duration; |
+ if (active_animation.remaining_duration <= base::TimeDelta()) { |
+ active_animation.success_callback.Run(); |
+ animation_iter = (*container_iter).second.erase(animation_iter); |
+ } else { |
+ ++animation_iter; |
+ } |
+ } |
+ } |
+} |
+ |
+void TestSessionStateAnimator::CompleteAnimations(int animation_epoch, |
+ bool completed_successfully) { |
+ for (ActiveAnimationsMap::iterator container_iter = |
+ active_animations_.begin(); |
+ container_iter != active_animations_.end(); |
+ ++container_iter) { |
+ AnimationList::iterator animation_iter = (*container_iter).second.begin(); |
+ while (animation_iter != (*container_iter).second.end()) { |
+ ActiveAnimation active_animation = *animation_iter; |
+ if (active_animation.animation_epoch <= animation_epoch) { |
+ if (completed_successfully) |
+ active_animation.success_callback.Run(); |
+ else |
+ active_animation.failed_callback.Run(); |
+ animation_iter = (*container_iter).second.erase(animation_iter); |
+ } else { |
+ ++animation_iter; |
+ } |
+ } |
+ } |
+} |
+ |
+void TestSessionStateAnimator::CompleteAllAnimations( |
+ bool completed_successfully) { |
+ CompleteAnimations(last_animation_epoch_, completed_successfully); |
+} |
+ |
+bool TestSessionStateAnimator::IsContainerAnimated( |
+ SessionStateAnimator::Container container, |
+ SessionStateAnimator::AnimationType type) const { |
+ ActiveAnimationsMap::const_iterator container_iter = |
+ active_animations_.find(container); |
+ if (container_iter != active_animations_.end()) { |
+ for (AnimationList::const_iterator animation_iter = |
+ (*container_iter).second.begin(); |
+ animation_iter != (*container_iter).second.end(); |
+ ++animation_iter) { |
+ const ActiveAnimation& active_animation = *animation_iter; |
+ if (active_animation.type == type) |
+ return true; |
+ } |
+ } |
+ return false; |
+} |
+ |
+bool TestSessionStateAnimator::AreContainersAnimated( |
+ int container_mask, SessionStateAnimator::AnimationType type) const { |
+ for (size_t i = 0; i < arraysize(kAllContainers); ++i) { |
+ if (container_mask & kAllContainers[i] && |
+ !IsContainerAnimated(kAllContainers[i], type)) { |
+ return false; |
+ } |
+ } |
+ return true; |
+} |
+ |
+size_t TestSessionStateAnimator::GetAnimationCount() const { |
+ size_t count = 0; |
+ for (ActiveAnimationsMap::const_iterator container_iter = |
+ active_animations_.begin(); |
+ container_iter != active_animations_.end(); |
+ ++container_iter) { |
+ count += (*container_iter).second.size(); |
+ } |
+ return count; |
+} |
+ |
+void TestSessionStateAnimator::StartAnimation(int container_mask, |
+ AnimationType type, |
+ AnimationSpeed speed) { |
+ ++last_animation_epoch_; |
+ for (size_t i = 0; i < arraysize(kAllContainers); ++i) { |
+ if (container_mask & kAllContainers[i]) { |
+ // Use a dummy no-op callback because one isn't required by the client |
+ // but one is required when completing or aborting animations. |
+ base::Closure callback = base::Bind(&DummyCallback); |
+ AddAnimation(kAllContainers[i], type, speed, callback, callback); |
+ } |
+ } |
+} |
+ |
+void TestSessionStateAnimator::StartAnimationWithCallback( |
+ int container_mask, |
+ AnimationType type, |
+ AnimationSpeed speed, |
+ base::Closure callback) { |
+ ++last_animation_epoch_; |
+ for (size_t i = 0; i < arraysize(kAllContainers); ++i) |
+ if (container_mask & kAllContainers[i]) { |
+ // ash::SessionStateAnimatorImpl invokes the callback whether or not the |
+ // animation was completed successfully or not. |
+ AddAnimation(kAllContainers[i], type, speed, callback, callback); |
+ } |
+} |
+ |
+ash::SessionStateAnimator::AnimationSequence* |
+ TestSessionStateAnimator::BeginAnimationSequence(base::Closure callback) { |
+ return new AnimationSequence(callback, this); |
+} |
+ |
+bool TestSessionStateAnimator::IsBackgroundHidden() const { |
+ return is_background_hidden_; |
+} |
+ |
+void TestSessionStateAnimator::ShowBackground() { |
+ is_background_hidden_ = false; |
+} |
+ |
+void TestSessionStateAnimator::HideBackground() { |
+ is_background_hidden_ = true; |
+} |
+ |
+void TestSessionStateAnimator::StartAnimationInSequence( |
+ int container_mask, |
+ AnimationType type, |
+ AnimationSpeed speed, |
+ AnimationSequence* animation_sequence) { |
+ ++last_animation_epoch_; |
+ for (size_t i = 0; i < arraysize(kAllContainers); ++i) { |
+ if (container_mask & kAllContainers[i]) { |
+ base::Closure success_callback = |
+ base::Bind(&AnimationSequence::SequenceFinished, |
+ base::Unretained(animation_sequence), true); |
+ base::Closure failed_callback = |
+ base::Bind(&AnimationSequence::SequenceFinished, |
+ base::Unretained(animation_sequence), false); |
+ animation_sequence->SequenceAttached(); |
+ AddAnimation(kAllContainers[i], type, speed, success_callback, |
+ failed_callback); |
+ } |
+ } |
+} |
+ |
+void TestSessionStateAnimator::AddAnimation( |
+ SessionStateAnimator::Container container, |
+ AnimationType type, |
+ AnimationSpeed speed, |
+ base::Closure success_callback, |
+ base::Closure failed_callback) { |
+ base::TimeDelta duration = GetDuration(speed); |
+ ActiveAnimation active_animation(last_animation_epoch_, |
+ duration, |
+ container, |
+ type, |
+ speed, |
+ success_callback, |
+ failed_callback); |
+ // This test double is limited to only have one animation active for a given |
+ // container at a time. |
+ AbortAnimation(container); |
+ active_animations_[container].push_back(active_animation); |
+} |
+ |
+void TestSessionStateAnimator::AbortAnimation( |
+ SessionStateAnimator::Container container) { |
+ ActiveAnimationsMap::iterator container_iter = |
+ active_animations_.find(container); |
+ if (container_iter != active_animations_.end()) { |
+ AnimationList::iterator animation_iter = (*container_iter).second.begin(); |
+ while (animation_iter != (*container_iter).second.end()) { |
+ ActiveAnimation active_animation = *animation_iter; |
+ active_animation.failed_callback.Run(); |
+ animation_iter = (*container_iter).second.erase(animation_iter); |
+ } |
+ } |
+} |
+ |
+} // namespace test |
+} // namespace ash |