Skip to content

Commit

Permalink
Fill in more implementation of animation callbacks.
Browse files Browse the repository at this point in the history
Bug: 1236069
Change-Id: Ic76a7b974c510abbd8ed552a392a1736af87925d
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3071813
Commit-Queue: Allen Bauer (OOO - 8/5 - 8/8) <kylixrd@chromium.org>
Reviewed-by: Peter Kasting <pkasting@chromium.org>
Cr-Commit-Position: refs/heads/master@{#908702}
  • Loading branch information
Allen Bauer authored and Chromium LUCI CQ committed Aug 5, 2021
1 parent 2bb9c6f commit c2af794
Show file tree
Hide file tree
Showing 3 changed files with 168 additions and 16 deletions.
107 changes: 96 additions & 11 deletions ui/views/animation/animation_builder.cc
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include "ui/views/animation/animation_builder.h"

#include "base/containers/contains.h"
#include "base/ranges/algorithm.h"
#include "ui/compositor/layer.h"
#include "ui/compositor/layer_animation_sequence.h"
#include "ui/compositor/layer_animator.h"
Expand All @@ -26,11 +27,16 @@ AnimationBuilder::~AnimationBuilder() {
View* view = animation.first.view;
if (!view->layer())
view->SetPaintToLayer();
for (auto& s : animation.second)
for (auto& s : animation.second) {
if (animation_observer_)
animation_observer_->ObserveAnimationSequence(s.get());
all_animations[view].push_back(s.release());
}
}
for (auto& a : all_animations)
a.first->layer()->GetAnimator()->StartTogether(a.second);
if (animation_observer_)
animation_observer_.release();
}

AnimationBuilder& AnimationBuilder::NewSequence() {
Expand Down Expand Up @@ -93,15 +99,31 @@ AnimationBuilder& AnimationBuilder::SetRoundedCorners(
return *this;
}

void AnimationBuilder::OnStarted(base::OnceClosure callback) {}
AnimationBuilder& AnimationBuilder::OnStarted(base::OnceClosure callback) {
GetAnimationObserver()->SetOnStarted(std::move(callback));
return *this;
}

void AnimationBuilder::OnEnded(base::OnceClosure callback) {}
AnimationBuilder& AnimationBuilder::OnEnded(base::OnceClosure callback) {
GetAnimationObserver()->SetOnEnded(std::move(callback));
return *this;
}

void AnimationBuilder::OnWillRepeat(base::RepeatingClosure callback) {}
AnimationBuilder& AnimationBuilder::OnWillRepeat(
base::RepeatingClosure callback) {
GetAnimationObserver()->SetOnWillRepeat(std::move(callback));
return *this;
}

void AnimationBuilder::OnAborted(base::OnceClosure callback) {}
AnimationBuilder& AnimationBuilder::OnAborted(base::OnceClosure callback) {
GetAnimationObserver()->SetOnAborted(std::move(callback));
return *this;
}

void AnimationBuilder::OnScheduled(base::OnceClosure callback) {}
AnimationBuilder& AnimationBuilder::OnScheduled(base::OnceClosure callback) {
GetAnimationObserver()->SetOnScheduled(std::move(callback));
return *this;
}

void AnimationBuilder::CreateNewEntry(const AnimationKey& key) {
auto new_sequence = std::make_unique<ui::LayerAnimationSequence>();
Expand All @@ -120,6 +142,13 @@ void AnimationBuilder::AddAnimation(
animation_sequences_[key].back()->AddElement(std::move(element));
}

AnimationBuilder::AnimationBuilderObserver*
AnimationBuilder::GetAnimationObserver() {
if (!animation_observer_)
animation_observer_ = std::make_unique<AnimationBuilderObserver>();
return animation_observer_.get();
}

AnimationBuilder::AnimationBuilderObserver::AnimationBuilderObserver() =
default;

Expand All @@ -135,20 +164,76 @@ void AnimationBuilder::AnimationBuilderObserver::ObserveAnimationSequence(
sequences_.emplace_back(sequence->AsWeakPtr());
}

void AnimationBuilder::AnimationBuilderObserver::SetOnStarted(
base::OnceClosure callback) {
DCHECK(!on_started_);
on_started_ = std::move(callback);
}

void AnimationBuilder::AnimationBuilderObserver::SetOnEnded(
base::OnceClosure callback) {
DCHECK(!on_ended_);
on_ended_ = std::move(callback);
}

void AnimationBuilder::AnimationBuilderObserver::SetOnWillRepeat(
base::RepeatingClosure callback) {
DCHECK(!on_will_repeat_);
on_will_repeat_ = std::move(callback);
}

void AnimationBuilder::AnimationBuilderObserver::SetOnAborted(
base::OnceClosure callback) {
DCHECK(!on_aborted_);
on_aborted_ = std::move(callback);
}

void AnimationBuilder::AnimationBuilderObserver::SetOnScheduled(
base::OnceClosure callback) {
DCHECK(!on_scheduled_);
on_scheduled_ = std::move(callback);
}

void AnimationBuilder::AnimationBuilderObserver::OnLayerAnimationStarted(
ui::LayerAnimationSequence* sequence) {}
ui::LayerAnimationSequence* sequence) {
if (on_started_)
std::move(on_started_).Run();
}

void AnimationBuilder::AnimationBuilderObserver::OnLayerAnimationEnded(
ui::LayerAnimationSequence* sequence) {}
ui::LayerAnimationSequence* sequence) {
const auto running =
base::ranges::count_if(sequences_, [](const auto& sequence) {
return sequence && !sequence->IsFinished(base::TimeTicks::Now());
});
if (running <= 1) {
if (on_ended_)
std::move(on_ended_).Run();
// TODO(kylixrd): This needs more thought in light of repeating animations
// aborts, etc...
delete this;
}
}

void AnimationBuilder::AnimationBuilderObserver::OnLayerAnimationWillRepeat(
ui::LayerAnimationSequence* sequence) {}
ui::LayerAnimationSequence* sequence) {
// TODO(kylixrd): This should only be called once for each repeat sequence.
// Figure out how to limit this to one invocation.
}

void AnimationBuilder::AnimationBuilderObserver::OnLayerAnimationAborted(
ui::LayerAnimationSequence* sequence) {}
ui::LayerAnimationSequence* sequence) {
if (on_aborted_)
std::move(on_aborted_).Run();
// TODO(kylixrd): Probably should propagate the abort to the other
// LayerAnimationSequences.
}

void AnimationBuilder::AnimationBuilderObserver::OnLayerAnimationScheduled(
ui::LayerAnimationSequence* sequence) {}
ui::LayerAnimationSequence* sequence) {
if (on_scheduled_)
std::move(on_scheduled_).Run();
}

void AnimationBuilder::AnimationBuilderObserver::Reset() {
for (auto& sequence : sequences_) {
Expand Down
24 changes: 19 additions & 5 deletions ui/views/animation/animation_builder.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,17 +46,17 @@ class VIEWS_EXPORT AnimationBuilder {


// Called when the animation starts.
void OnStarted(base::OnceClosure callback);
AnimationBuilder& OnStarted(base::OnceClosure callback);
// Called when the animation ends. Not called if animation is aborted.
void OnEnded(base::OnceClosure callback);
AnimationBuilder& OnEnded(base::OnceClosure callback);
// Called when a sequence repetition ends and will repeat. Not called if
// sequence is aborted.
void OnWillRepeat(base::RepeatingClosure callback);
AnimationBuilder& OnWillRepeat(base::RepeatingClosure callback);
// Called if animation is aborted for any reason. Should never do anything
// that may cause another animation to be started.
void OnAborted(base::OnceClosure callback);
AnimationBuilder& OnAborted(base::OnceClosure callback);
// Called when the animation is scheduled.
void OnScheduled(base::OnceClosure callback);
AnimationBuilder& OnScheduled(base::OnceClosure callback);

private:
struct AnimationKey {
Expand All @@ -82,6 +82,13 @@ class VIEWS_EXPORT AnimationBuilder {

void ObserveAnimationSequence(ui::LayerAnimationSequence* sequence);

void SetOnStarted(base::OnceClosure callback);
void SetOnEnded(base::OnceClosure callback);
void SetOnWillRepeat(base::RepeatingClosure callback);
void SetOnAborted(base::OnceClosure callback);
void SetOnScheduled(base::OnceClosure callback);

// ui::LayerAnimationObserver
void OnLayerAnimationStarted(ui::LayerAnimationSequence* sequence) override;
void OnLayerAnimationEnded(ui::LayerAnimationSequence* sequence) override;
void OnLayerAnimationWillRepeat(
Expand All @@ -94,13 +101,20 @@ class VIEWS_EXPORT AnimationBuilder {
void Reset();

std::vector<base::WeakPtr<ui::LayerAnimationSequence>> sequences_;
base::OnceClosure on_started_;
base::OnceClosure on_ended_;
base::RepeatingClosure on_will_repeat_;
base::OnceClosure on_aborted_;
base::OnceClosure on_scheduled_;
};

void CreateNewEntry(const AnimationKey& key);

void AddAnimation(const AnimationKey& key,
std::unique_ptr<ui::LayerAnimationElement> element);

AnimationBuilderObserver* GetAnimationObserver();

base::flat_map<AnimationKey,
std::vector<std::unique_ptr<ui::LayerAnimationSequence>>>
animation_sequences_;
Expand Down
53 changes: 53 additions & 0 deletions ui/views/animation/animation_builder_unittest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

#include "ui/views/animation/animation_builder.h"

#include "base/bind.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/compositor/layer.h"
#include "ui/compositor/layer_animator.h"
Expand Down Expand Up @@ -103,4 +104,56 @@ TEST_F(AnimationBuilderTest, SimpleAnimation) {
EXPECT_FLOAT_EQ(second_delegate->GetOpacityForAnimation(), 0.9f);
}

TEST_F(AnimationBuilderTest, CheckStartEndCallbacks) {
auto first_animating_view = std::make_unique<View>();
auto second_animating_view = std::make_unique<View>();

first_animating_view->SetPaintToLayer();
second_animating_view->SetPaintToLayer();

ui::LayerAnimator* first_layer_animator =
first_animating_view->layer()->GetAnimator();
// TODO(kylixrd): Consider adding more test support to AnimationBuilder to
// avoid reaching behind the curtain for these things.
first_layer_animator->set_disable_timer_for_test(true);

ui::LayerAnimator* second_layer_animator =
second_animating_view->layer()->GetAnimator();
second_layer_animator->set_disable_timer_for_test(true);

ui::LayerAnimatorTestController first_test_controller(first_layer_animator);
ui::LayerAnimatorTestController second_test_controller(second_layer_animator);

constexpr auto kDelay = base::TimeDelta::FromSeconds(3);
bool started = false;
bool ended = false;

{
AnimationBuilder b;
b.OnStarted(
base::BindOnce([](bool* started) { *started = true; }, &started))
.OnEnded(base::BindOnce([](bool* ended) { *ended = true; }, &ended))
.NewSequence()
.SetDuration(kDelay)
.SetOpacity(first_animating_view.get(), 0.4f)
.EndSequence()
.NewSequence()
.SetDuration(kDelay * 2)
.SetOpacity(second_animating_view.get(), 0.9f)
.EndSequence();
}

first_test_controller.StartThreadedAnimationsIfNeeded();
second_test_controller.StartThreadedAnimationsIfNeeded();

EXPECT_TRUE(started);

first_animating_view->layer()->GetAnimator()->Step(base::TimeTicks::Now() +
kDelay * 2);
second_animating_view->layer()->GetAnimator()->Step(base::TimeTicks::Now() +
kDelay * 2);

EXPECT_TRUE(ended);
}

} // namespace views

0 comments on commit c2af794

Please sign in to comment.