1 /*
2  * Copyright (c) 2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "animation_controller.h"
17 
18 #include <meta/api/make_callback.h>
19 #include <meta/ext/serialization/serializer.h>
20 #include <meta/interface/property/property_events.h>
21 
META_BEGIN_NAMESPACE()22 META_BEGIN_NAMESPACE()
23 
24 bool AnimationController::Build(const IMetadata::Ptr& data)
25 {
26     updateCallback_ = MakeCallback<IOnChanged>(this, &AnimationController::UpdateAnimations);
27     return true;
28 }
29 
AttachTo(const META_NS::IAttach::Ptr & target,const META_NS::IObject::Ptr & dataContext)30 bool AnimationController::AttachTo(const META_NS::IAttach::Ptr& target, const META_NS::IObject::Ptr& dataContext)
31 {
32     return true;
33 }
34 
DetachFrom(const META_NS::IAttach::Ptr & target)35 bool AnimationController::DetachFrom(const META_NS::IAttach::Ptr& target)
36 {
37     return true;
38 }
39 
UpdateAnimations()40 void AnimationController::UpdateAnimations()
41 {
42     uint32_t count = 0;
43     uint32_t running = 0;
44     {
45         std::unique_lock lock(mutex_);
46         auto it = animations_.begin();
47         running_.clear();
48         while (it != animations_.end()) {
49             auto& weak = *it;
50             if (auto animation = weak.lock()) {
51                 // Assuming here that getting the running property value cannot cause a recursive call back
52                 // to the animation controller
53                 if (GetValue(animation->Running())) {
54                     running_.push_back(weak);
55                 }
56                 it++;
57             } else {
58                 // Animation has died, clean up weak_ptr from our list
59                 it = animations_.erase(it);
60             }
61         }
62         count = animations_.size();
63         running = running_.size();
64     }
65 
66     SetValue(META_ACCESS_PROPERTY(Count), count);
67     SetValue(META_ACCESS_PROPERTY(RunningCount), running);
68 }
69 
UpdateRunningHandler(const IAnimation::Ptr & animation,bool addHandler)70 void AnimationController::UpdateRunningHandler(const IAnimation::Ptr& animation, bool addHandler)
71 {
72     if (!animation) {
73         return;
74     }
75     if (auto running = animation->Running()) {
76         if (addHandler) {
77             running->OnChanged()->AddHandler(updateCallback_, uintptr_t(this));
78         } else {
79             running->OnChanged()->RemoveHandler(uintptr_t(this));
80         }
81     }
82 }
83 
AddAnimation(const META_NS::IAnimation::Ptr & animation)84 bool AnimationController::AddAnimation(const META_NS::IAnimation::Ptr& animation)
85 {
86     if (!animation) {
87         return false;
88     }
89     {
90         std::unique_lock lock(mutex_);
91         for (auto& weak : animations_) {
92             if (weak.lock() == animation) {
93                 // Already there
94                 return true;
95             }
96         }
97         animations_.emplace_back(animation);
98     }
99 
100     UpdateRunningHandler(animation, true);
101     SetValue(animation->Controller(), GetSelf<IAnimationController>());
102     UpdateAnimations();
103     return true;
104 }
105 
RemoveAnimation(const META_NS::IAnimation::Ptr & animation)106 bool AnimationController::RemoveAnimation(const META_NS::IAnimation::Ptr& animation)
107 {
108     bool removed = false;
109     if (animation) {
110         std::unique_lock lock(mutex_);
111         for (auto it = animations_.begin(); it != animations_.end(); it++) {
112             if ((*it).lock() == animation) {
113                 animations_.erase(it);
114                 removed = true;
115                 break;
116             }
117         }
118     }
119     if (removed) {
120         UpdateRunningHandler(animation, false);
121         UpdateAnimations();
122     }
123     return removed;
124 }
125 
Clear()126 void AnimationController::Clear()
127 {
128     {
129         BASE_NS::vector<IAnimation::WeakPtr> all;
130         {
131             std::unique_lock lock(mutex_);
132             all.swap(animations_);
133             running_.clear();
134         }
135         for (auto& weak : all) {
136             UpdateRunningHandler(weak.lock(), false);
137         }
138     }
139     UpdateAnimations();
140 }
141 
Step(const IClock::ConstPtr & clock)142 IAnimationController::StepInfo AnimationController::Step(const IClock::ConstPtr& clock)
143 {
144     StepInfo info { 0, 0 };
145 
146     for (auto& anim : GetRunning()) {
147         if (auto animation = anim.lock()) {
148             animation->Step(clock);
149             info.stepped_++;
150         }
151     }
152 
153     // Step may end up starting/stopping some animations
154     std::shared_lock lock(mutex_);
155     info.running_ = running_.size();
156     return info;
157 }
158 
GetAnimations() const159 BASE_NS::vector<IAnimation::WeakPtr> AnimationController::GetAnimations() const
160 {
161     std::shared_lock lock(mutex_);
162     return animations_;
163 }
164 
GetRunning() const165 BASE_NS::vector<IAnimation::WeakPtr> AnimationController::GetRunning() const
166 {
167     std::shared_lock lock(mutex_);
168     return running_;
169 }
170 
Export(IExportContext & c) const171 ReturnError AnimationController::Export(IExportContext& c) const
172 {
173     return Serializer(c) & NamedValue("__animations", animations_);
174 }
Import(IImportContext & c)175 ReturnError AnimationController::Import(IImportContext& c)
176 {
177     return Serializer(c) & NamedValue("__animations", animations_);
178 }
Finalize(IImportFunctions &)179 ReturnError AnimationController::Finalize(IImportFunctions&)
180 {
181     // take the animations out and re-add by setting the animation controller
182     BASE_NS::vector<IAnimation::WeakPtr> vec = BASE_NS::move(animations_);
183     for (auto&& anim : vec) {
184         if (auto p = anim.lock()) {
185             p->Controller()->SetValue(GetSelf<IAnimationController>());
186         }
187     }
188     return GenericError::SUCCESS;
189 }
190 
191 META_END_NAMESPACE()
192