#include "ash/ambient/ui/ambient_animation_progress_tracker.h"
#include <optional>
#include <utility>
#include "base/check.h"
#include "base/logging.h"
#include "base/memory/raw_ptr.h"
#include "base/notreached.h"
namespace ash {
namespace {
void MoveAnimation(
base::flat_set<raw_ptr<const lottie::Animation, CtnExperimental>>& from,
base::flat_set<raw_ptr<const lottie::Animation, CtnExperimental>>& to,
const lottie::Animation* animation) {
if (to.contains(animation)) {
CHECK(!from.contains(animation));
return;
}
CHECK_EQ(from.erase(animation), 1u);
to.insert(animation);
}
}
AmbientAnimationProgressTracker::ImmutableParams::ImmutableParams() = default;
AmbientAnimationProgressTracker::ImmutableParams::ImmutableParams(
const ImmutableParams& other) = default;
AmbientAnimationProgressTracker::ImmutableParams&
AmbientAnimationProgressTracker::ImmutableParams::operator=(
const ImmutableParams& other) = default;
AmbientAnimationProgressTracker::ImmutableParams::~ImmutableParams() = default;
AmbientAnimationProgressTracker::AmbientAnimationProgressTracker() = default;
AmbientAnimationProgressTracker::~AmbientAnimationProgressTracker() = default;
void AmbientAnimationProgressTracker::RegisterAnimation(
lottie::Animation* animation) {
DCHECK(animation);
if (animation_observations_.IsObservingSource(animation)) {
return;
}
animation_observations_.AddObservation(animation);
if (animation->GetPlaybackConfig()) {
VerifyAnimationImmutableParams(*animation);
started_animations_.insert(animation);
} else {
DVLOG(4) << "Animation has not been Start()ed yet. Will be verified in "
"AnimationWillStartPlaying() later.";
inactive_animations_.insert(animation);
}
}
bool AmbientAnimationProgressTracker::HasActiveAnimations() const {
for (const lottie::Animation* animation : started_animations_) {
if (animation->GetCurrentProgress())
return true;
}
return false;
}
AmbientAnimationProgressTracker::Progress
AmbientAnimationProgressTracker::GetGlobalProgress() const {
for (const lottie::Animation* animation : started_animations_) {
if (animation->GetCurrentProgress()) {
DCHECK(animation->GetNumCompletedCycles());
return {*animation->GetNumCompletedCycles(),
*animation->GetCurrentProgress()};
}
}
NOTREACHED() << "HasActiveAnimations() must be true before calling "
"GetGlobalProgress()";
}
AmbientAnimationProgressTracker::ImmutableParams
AmbientAnimationProgressTracker::GetImmutableParams() const {
DCHECK(HasActiveAnimations());
const lottie::Animation* animation = *started_animations_.begin();
auto playback_config = animation->GetPlaybackConfig();
ImmutableParams params;
params.total_duration = animation->GetAnimationDuration();
params.scheduled_cycles = playback_config->scheduled_cycles;
params.style = playback_config->style;
return params;
}
void AmbientAnimationProgressTracker::AnimationWillStartPlaying(
const lottie::Animation* animation) {
DCHECK(animation_observations_.IsObservingSource(
const_cast<lottie::Animation*>(animation)));
VerifyAnimationImmutableParams(*animation);
MoveAnimation(inactive_animations_, started_animations_,
animation);
}
void AmbientAnimationProgressTracker::AnimationStopped(
const lottie::Animation* animation) {
CHECK(animation_observations_.IsObservingSource(
const_cast<lottie::Animation*>(animation)));
MoveAnimation(started_animations_, inactive_animations_,
animation);
}
void AmbientAnimationProgressTracker::AnimationIsDeleting(
const lottie::Animation* animation) {
DCHECK(animation_observations_.IsObservingSource(
const_cast<lottie::Animation*>(animation)));
animation_observations_.RemoveObservation(
const_cast<lottie::Animation*>(animation));
started_animations_.erase(animation);
inactive_animations_.erase(animation);
}
void AmbientAnimationProgressTracker::VerifyAnimationImmutableParams(
const lottie::Animation& animation) const {
DCHECK(!started_animations_.contains(&animation));
if (started_animations_.empty()) {
DVLOG(4) << "Incoming animation is the first started in the session. No "
"need to verify against other animations";
return;
}
const lottie::Animation* existing_animation = *started_animations_.begin();
DCHECK_EQ(animation.GetAnimationDuration(),
existing_animation->GetAnimationDuration());
auto incoming_playback_config = animation.GetPlaybackConfig();
auto existing_playback_config = animation.GetPlaybackConfig();
DCHECK(incoming_playback_config);
DCHECK(existing_playback_config);
DCHECK_EQ(incoming_playback_config->scheduled_cycles.size(),
existing_playback_config->scheduled_cycles.size());
for (size_t i = 0; i < incoming_playback_config->scheduled_cycles.size();
++i) {
DCHECK_EQ(incoming_playback_config->scheduled_cycles[i].start_offset,
existing_playback_config->scheduled_cycles[i].start_offset);
DCHECK_EQ(incoming_playback_config->scheduled_cycles[i].end_offset,
existing_playback_config->scheduled_cycles[i].end_offset);
}
DCHECK_EQ(incoming_playback_config->style, existing_playback_config->style);
}
}