1 /*
2 * Copyright 2020 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "AnimationModule.h"
18 #include "MathHelp.h"
19
20 #include <android-base/logging.h>
21 #include <algorithm>
22
23 namespace android {
24 namespace hardware {
25 namespace automotive {
26 namespace sv {
27 namespace V1_0 {
28 namespace implementation {
29 namespace {
operator *(std::array<float,3> lvector,float scalar)30 std::array<float, 3> operator*(std::array<float, 3> lvector, float scalar) {
31 return std::array<float, 3>{
32 lvector[0] * scalar,
33 lvector[1] * scalar,
34 lvector[2] * scalar,
35 };
36 }
37
getRationalNumber(const Range & mappedRange,float percentage)38 inline float getRationalNumber(const Range& mappedRange, float percentage) {
39 return mappedRange.start + (mappedRange.end - mappedRange.start) * percentage;
40 }
41
getRationalNumber(const Range & mappedRange,const Range & rawRange,float rawValue)42 inline float getRationalNumber(const Range& mappedRange, const Range& rawRange, float rawValue) {
43 if (0 == rawRange.end - rawRange.start) {
44 return mappedRange.start;
45 }
46 const float percentage = (rawValue - rawRange.start) / (rawRange.end - rawRange.start);
47 return mappedRange.start + (mappedRange.end - mappedRange.start) * percentage > 1
48 ? 1
49 : percentage < 0 ? 0 : percentage;
50 }
51
getCombinedId(const VehiclePropValue & vhalValueFloat)52 inline uint64_t getCombinedId(const VehiclePropValue& vhalValueFloat) {
53 return static_cast<uint64_t>(vhalValueFloat.prop) << 32 | vhalValueFloat.areaId;
54 }
55
getVhalValueFloat(const VehiclePropValue & vhalValue)56 float getVhalValueFloat(const VehiclePropValue& vhalValue) {
57 int32_t type = vhalValue.prop & 0x00FF0000;
58 switch (type) {
59 case (int32_t)VehiclePropertyType::BOOLEAN:
60 return 0 == vhalValue.value.int32Values[0] ? 0.0f : 1.0f;
61 case (int32_t)VehiclePropertyType::FLOAT:
62 return vhalValue.value.floatValues[0];
63 case (int32_t)VehiclePropertyType::INT32:
64 return (float)vhalValue.value.int32Values[0];
65 case (int32_t)VehiclePropertyType::INT64:
66 return (float)vhalValue.value.int64Values[0];
67 default:
68 return 0;
69 }
70 }
71 } // namespace
72
AnimationModule(const std::map<std::string,CarPart> & partsMap,const std::map<std::string,CarTexture> & texturesMap,const std::vector<AnimationInfo> & animations)73 AnimationModule::AnimationModule(const std::map<std::string, CarPart>& partsMap,
74 const std::map<std::string, CarTexture>& texturesMap,
75 const std::vector<AnimationInfo>& animations) :
76 mIsCalled(false), mPartsMap(partsMap), mTexturesMap(texturesMap), mAnimations(animations) {
77 mapVhalToParts();
78 initCarPartStatus();
79 }
80
mapVhalToParts()81 void AnimationModule::mapVhalToParts() {
82 for (const auto& animationInfo : mAnimations) {
83 auto partId = animationInfo.partId;
84 for (const auto& gammaOp : animationInfo.gammaOpsMap) {
85 if (mVhalToPartsMap.find(gammaOp.first) != mVhalToPartsMap.end()) {
86 mVhalToPartsMap.at(gammaOp.first).insert(partId);
87 } else {
88 mVhalToPartsMap.emplace(
89 std::make_pair(gammaOp.first, std::set<std::string>{partId}));
90 }
91 }
92 for (const auto& textureOp : animationInfo.textureOpsMap) {
93 if (mVhalToPartsMap.find(textureOp.first) != mVhalToPartsMap.end()) {
94 mVhalToPartsMap.at(textureOp.first).insert(partId);
95 } else {
96 mVhalToPartsMap.emplace(
97 std::make_pair(textureOp.first, std::set<std::string>{partId}));
98 }
99 }
100 for (const auto& rotationOp : animationInfo.rotationOpsMap) {
101 if (mVhalToPartsMap.find(rotationOp.first) != mVhalToPartsMap.end()) {
102 mVhalToPartsMap.at(rotationOp.first).insert(partId);
103 } else {
104 mVhalToPartsMap.emplace(
105 std::make_pair(rotationOp.first, std::set<std::string>{partId}));
106 }
107 }
108 for (const auto& translationOp : animationInfo.translationOpsMap) {
109 if (mVhalToPartsMap.find(translationOp.first) != mVhalToPartsMap.end()) {
110 mVhalToPartsMap.at(translationOp.first).insert(partId);
111 } else {
112 mVhalToPartsMap.emplace(
113 std::make_pair(translationOp.first, std::set<std::string>{partId}));
114 }
115 }
116 mPartsToAnimationMap.emplace(std::make_pair(partId, animationInfo));
117 }
118 }
119
initCarPartStatus()120 void AnimationModule::initCarPartStatus() {
121 for (const auto& part : mPartsMap) {
122 // Get child parts list from mPartsToAnimationMap.
123 std::vector<std::string> childIds;
124 if (mPartsToAnimationMap.find(part.first) != mPartsToAnimationMap.end()) {
125 childIds = mPartsToAnimationMap.at(part.first).childIds;
126 }
127
128 mCarPartsStatusMap.emplace(std::make_pair(part.first,
129 CarPartStatus{
130 .partId = part.first,
131 .childIds = childIds,
132 .parentModel = gMat4Identity,
133 .localModel = gMat4Identity,
134 .currentModel = gMat4Identity,
135 .gamma = 1,
136 }));
137 }
138
139 for (const auto& eachVhalToParts : mVhalToPartsMap) {
140 for (const auto& part : eachVhalToParts.second) {
141 if (mCarPartsStatusMap.at(part).vhalProgressMap.find(eachVhalToParts.first) !=
142 mCarPartsStatusMap.at(part).vhalProgressMap.end()) {
143 mCarPartsStatusMap.at(part).vhalProgressMap.at(eachVhalToParts.first) = 0.0f;
144 } else {
145 mCarPartsStatusMap.at(part).vhalProgressMap.emplace(
146 std::make_pair(eachVhalToParts.first, 0.0f));
147 }
148 if (mCarPartsStatusMap.at(part).vhalOffMap.find(eachVhalToParts.first) !=
149 mCarPartsStatusMap.at(part).vhalOffMap.end()) {
150 mCarPartsStatusMap.at(part).vhalOffMap.at(eachVhalToParts.first) = true;
151 } else {
152 mCarPartsStatusMap.at(part).vhalOffMap.emplace(
153 std::make_pair(eachVhalToParts.first, true));
154 }
155 }
156 }
157 }
158
159 // This implementation assumes the tree level is small. If tree level is large,
160 // we may need to traverse the tree once and process each node(part) during
161 // the reaversal.
updateChildrenParts(const std::string & partId,const Mat4x4 & parentModel)162 void AnimationModule::updateChildrenParts(const std::string& partId, const Mat4x4& parentModel) {
163 for (auto& childPart : mCarPartsStatusMap.at(partId).childIds) {
164 mCarPartsStatusMap.at(childPart).parentModel = parentModel;
165 mCarPartsStatusMap.at(childPart).currentModel =
166 appendMat(mCarPartsStatusMap.at(childPart).localModel,
167 mCarPartsStatusMap.at(childPart).parentModel);
168 if (mUpdatedPartsMap.find(childPart) == mUpdatedPartsMap.end()) {
169 AnimationParam animationParam(childPart);
170 animationParam.SetModelMatrix(mCarPartsStatusMap.at(childPart).currentModel);
171 mUpdatedPartsMap.emplace(std::make_pair(childPart, animationParam));
172 } else { // existing part in the map
173 mUpdatedPartsMap.at(childPart).SetModelMatrix(
174 mCarPartsStatusMap.at(childPart).currentModel);
175 }
176 updateChildrenParts(childPart, mCarPartsStatusMap.at(childPart).currentModel);
177 }
178 }
179
performGammaOp(const std::string & partId,uint64_t vhalProperty,const GammaOp & gammaOp)180 void AnimationModule::performGammaOp(const std::string& partId, uint64_t vhalProperty,
181 const GammaOp& gammaOp) {
182 CarPartStatus& currentCarPartStatus = mCarPartsStatusMap.at(partId);
183 float& currentProgress = currentCarPartStatus.vhalProgressMap.at(vhalProperty);
184 if (currentCarPartStatus.vhalOffMap.at(vhalProperty)) { // process off signal
185 if (currentProgress > 0) { // part not rest
186 if (0 == gammaOp.animationTime) {
187 currentCarPartStatus.gamma = gammaOp.gammaRange.start;
188 currentProgress = 0.0f;
189 } else {
190 const float progressDelta =
191 (mCurrentCallTime - mLastCallTime) / gammaOp.animationTime;
192 if (progressDelta > currentProgress) {
193 currentCarPartStatus.gamma = gammaOp.gammaRange.start;
194 currentProgress = 0.0f;
195 } else {
196 currentCarPartStatus.gamma =
197 getRationalNumber(gammaOp.gammaRange, currentProgress - progressDelta);
198 currentProgress -= progressDelta;
199 }
200 }
201 } else {
202 return;
203 }
204 } else { // regular signal process
205 if (0 == gammaOp.animationTime) { // continuous value
206 currentCarPartStatus.gamma =
207 getRationalNumber(gammaOp.gammaRange, gammaOp.vhalRange,
208 mVhalStatusMap.at(vhalProperty).vhalValueFloat);
209 currentProgress = mVhalStatusMap.at(vhalProperty).vhalValueFloat;
210 } else { // non-continuous value
211 const float progressDelta = (mCurrentCallTime - mLastCallTime) / gammaOp.animationTime;
212 if (gammaOp.type == ADJUST_GAMMA_ONCE) {
213 if (progressDelta + currentCarPartStatus.vhalProgressMap.at(vhalProperty) > 1) {
214 currentCarPartStatus.gamma = gammaOp.gammaRange.end;
215 currentProgress = 1.0f;
216 } else {
217 currentCarPartStatus.gamma =
218 getRationalNumber(gammaOp.gammaRange, currentProgress + progressDelta);
219 currentProgress += progressDelta;
220 }
221 } else if (gammaOp.type == ADJUST_GAMMA_REPEAT) {
222 if (progressDelta + currentCarPartStatus.vhalProgressMap.at(vhalProperty) > 1) {
223 if (progressDelta + currentCarPartStatus.vhalProgressMap.at(vhalProperty) - 1 >
224 1) {
225 currentCarPartStatus.gamma =
226 currentCarPartStatus.vhalProgressMap.at(vhalProperty) > 0.5
227 ? gammaOp.gammaRange.start
228 : gammaOp.gammaRange.end;
229 currentProgress =
230 currentCarPartStatus.vhalProgressMap.at(vhalProperty) > 0.5 ? 0.0f
231 : 1.0f;
232 } else {
233 currentCarPartStatus.gamma =
234 getRationalNumber(gammaOp.gammaRange,
235 progressDelta +
236 currentCarPartStatus.vhalProgressMap.at(
237 vhalProperty) -
238 1);
239 currentProgress += progressDelta - 1;
240 }
241 } else {
242 currentCarPartStatus.gamma =
243 getRationalNumber(gammaOp.gammaRange, currentProgress + progressDelta);
244 currentProgress += progressDelta;
245 }
246 } else {
247 LOG(ERROR) << "Error type of gamma op: " << gammaOp.type;
248 }
249 }
250 }
251
252 if (mUpdatedPartsMap.find(partId) == mUpdatedPartsMap.end()) {
253 AnimationParam animationParam(partId);
254 animationParam.SetGamma(currentCarPartStatus.gamma);
255 mUpdatedPartsMap.emplace(std::make_pair(partId, animationParam));
256 } else { // existing part in the map
257 mUpdatedPartsMap.at(partId).SetGamma(currentCarPartStatus.gamma);
258 }
259 }
260
performTranslationOp(const std::string & partId,uint64_t vhalProperty,const TranslationOp & translationOp)261 void AnimationModule::performTranslationOp(const std::string& partId, uint64_t vhalProperty,
262 const TranslationOp& translationOp) {
263 CarPartStatus& currentCarPartStatus = mCarPartsStatusMap.at(partId);
264 float& currentProgress = currentCarPartStatus.vhalProgressMap.at(vhalProperty);
265 if (currentCarPartStatus.vhalOffMap.at(vhalProperty)) { // process off signal
266 if (currentProgress > 0) {
267 // part not rest
268 if (0 == translationOp.animationTime) {
269 currentCarPartStatus.localModel = gMat4Identity;
270 currentCarPartStatus.currentModel = currentCarPartStatus.parentModel;
271 currentProgress = 0.0f;
272 } else {
273 const float progressDelta =
274 (mCurrentCallTime - mLastCallTime) / translationOp.animationTime;
275 float translationUnit =
276 getRationalNumber(translationOp.translationRange,
277 std::max(currentProgress - progressDelta, 0.0f));
278 currentCarPartStatus.localModel =
279 translationMatrixToMat4x4(translationOp.direction * translationUnit);
280 currentCarPartStatus.currentModel = appendMatrix(currentCarPartStatus.localModel,
281 currentCarPartStatus.parentModel);
282 currentProgress = std::max(currentProgress - progressDelta, 0.0f);
283 }
284 } else {
285 return;
286 }
287 } else { // regular signal process
288 if (translationOp.type == TRANSLATION) {
289 if (0 == translationOp.animationTime) {
290 float translationUnit =
291 getRationalNumber(translationOp.translationRange, translationOp.vhalRange,
292 mVhalStatusMap.at(vhalProperty).vhalValueFloat);
293 currentCarPartStatus.localModel =
294 translationMatrixToMat4x4(translationOp.direction * translationUnit);
295 currentCarPartStatus.currentModel = appendMatrix(currentCarPartStatus.localModel,
296 currentCarPartStatus.parentModel);
297 currentProgress = mVhalStatusMap.at(vhalProperty).vhalValueFloat;
298 } else {
299 float progressDelta =
300 (mCurrentCallTime - mLastCallTime) / translationOp.animationTime;
301 if (progressDelta + currentCarPartStatus.vhalProgressMap.at(vhalProperty) > 1) {
302 float translationUnit = translationOp.translationRange.end;
303
304 currentCarPartStatus.localModel =
305 translationMatrixToMat4x4(translationOp.direction * translationUnit);
306 currentCarPartStatus.currentModel =
307 appendMatrix(currentCarPartStatus.localModel,
308 currentCarPartStatus.parentModel);
309 currentProgress = 1.0f;
310 } else {
311 float translationUnit = getRationalNumber(translationOp.translationRange,
312 progressDelta + currentProgress);
313 currentCarPartStatus.localModel =
314 translationMatrixToMat4x4(translationOp.direction * translationUnit);
315 currentCarPartStatus.currentModel =
316 appendMatrix(currentCarPartStatus.localModel,
317 currentCarPartStatus.parentModel);
318 currentProgress += progressDelta;
319 }
320 }
321 } else {
322 LOG(ERROR) << "Error type of translation op: " << translationOp.type;
323 }
324 }
325 if (mUpdatedPartsMap.find(partId) == mUpdatedPartsMap.end()) {
326 AnimationParam animationParam(partId);
327 animationParam.SetModelMatrix(currentCarPartStatus.currentModel);
328 mUpdatedPartsMap.emplace(std::make_pair(partId, animationParam));
329 } else { // existing part in the map
330 mUpdatedPartsMap.at(partId).SetModelMatrix(currentCarPartStatus.currentModel);
331 }
332 updateChildrenParts(partId, currentCarPartStatus.currentModel);
333 }
334
performRotationOp(const std::string & partId,uint64_t vhalProperty,const RotationOp & rotationOp)335 void AnimationModule::performRotationOp(const std::string& partId, uint64_t vhalProperty,
336 const RotationOp& rotationOp) {
337 CarPartStatus& currentCarPartStatus = mCarPartsStatusMap.at(partId);
338 float& currentProgress = currentCarPartStatus.vhalProgressMap.at(vhalProperty);
339 if (currentCarPartStatus.vhalOffMap.at(vhalProperty)) {
340 // process off signal
341 if (currentProgress > 0) { // part not rest
342 if (0 == rotationOp.animationTime) {
343 currentCarPartStatus.localModel = gMat4Identity;
344 currentCarPartStatus.currentModel = currentCarPartStatus.parentModel;
345 currentProgress = 0.0f;
346 } else {
347 const float progressDelta =
348 (mCurrentCallTime - mLastCallTime) / rotationOp.animationTime;
349 if (progressDelta > currentProgress) {
350 currentCarPartStatus.localModel = gMat4Identity;
351 currentCarPartStatus.currentModel = currentCarPartStatus.parentModel;
352 currentProgress = 0.0f;
353 } else {
354 float anlgeInDegree = getRationalNumber(rotationOp.rotationRange,
355 currentProgress - progressDelta);
356 currentCarPartStatus.localModel =
357 rotationAboutPoint(anlgeInDegree, rotationOp.axis.rotationPoint,
358 rotationOp.axis.axisVector);
359 currentCarPartStatus.currentModel =
360 appendMatrix(currentCarPartStatus.localModel,
361 currentCarPartStatus.parentModel);
362 currentProgress -= progressDelta;
363 }
364 }
365 } else {
366 return;
367 }
368 } else { // regular signal process
369 if (rotationOp.type == ROTATION_ANGLE) {
370 if (0 == rotationOp.animationTime) {
371 float angleInDegree =
372 getRationalNumber(rotationOp.rotationRange, rotationOp.vhalRange,
373 mVhalStatusMap.at(vhalProperty).vhalValueFloat);
374 currentCarPartStatus.localModel =
375 rotationAboutPoint(angleInDegree, rotationOp.axis.rotationPoint,
376 rotationOp.axis.axisVector);
377 currentCarPartStatus.currentModel = appendMatrix(currentCarPartStatus.localModel,
378 currentCarPartStatus.parentModel);
379 currentProgress = mVhalStatusMap.at(vhalProperty).vhalValueFloat;
380 } else {
381 float progressDelta = (mCurrentCallTime - mLastCallTime) / rotationOp.animationTime;
382 if (progressDelta + currentProgress > 1) {
383 float angleInDegree = rotationOp.rotationRange.end;
384 currentCarPartStatus.localModel =
385 rotationAboutPoint(angleInDegree, rotationOp.axis.rotationPoint,
386 rotationOp.axis.axisVector);
387 currentCarPartStatus.currentModel =
388 appendMatrix(currentCarPartStatus.localModel,
389 currentCarPartStatus.parentModel);
390 currentProgress = 1.0f;
391 } else {
392 float anlgeInDegree = getRationalNumber(rotationOp.rotationRange,
393 currentProgress + progressDelta);
394 currentCarPartStatus.localModel =
395 rotationAboutPoint(anlgeInDegree, rotationOp.axis.rotationPoint,
396 rotationOp.axis.axisVector);
397 currentCarPartStatus.currentModel =
398 appendMatrix(currentCarPartStatus.localModel,
399 currentCarPartStatus.parentModel);
400 currentProgress += progressDelta;
401 }
402 }
403 } else if (rotationOp.type == ROTATION_SPEED) {
404 float angleDelta = (mCurrentCallTime - mLastCallTime) *
405 getRationalNumber(rotationOp.rotationRange, rotationOp.vhalRange,
406 mVhalStatusMap.at(vhalProperty)
407 .vhalValueFloat); // here vhalValueFloat unit is
408 // radian/ms.
409 currentCarPartStatus.localModel =
410 appendMat(rotationAboutPoint(angleDelta, rotationOp.axis.rotationPoint,
411 rotationOp.axis.axisVector),
412 currentCarPartStatus.localModel);
413 currentCarPartStatus.currentModel =
414 appendMatrix(currentCarPartStatus.localModel, currentCarPartStatus.parentModel);
415 currentProgress = 1.0f;
416 } else {
417 LOG(ERROR) << "Error type of rotation op: " << rotationOp.type;
418 }
419 }
420 if (mUpdatedPartsMap.find(partId) == mUpdatedPartsMap.end()) {
421 AnimationParam animationParam(partId);
422 animationParam.SetModelMatrix(currentCarPartStatus.currentModel);
423 mUpdatedPartsMap.emplace(std::make_pair(partId, animationParam));
424 } else { // existing part in the map
425 mUpdatedPartsMap.at(partId).SetModelMatrix(currentCarPartStatus.currentModel);
426 }
427 updateChildrenParts(partId, currentCarPartStatus.currentModel);
428 }
429
getUpdatedAnimationParams(const std::vector<VehiclePropValue> & vehiclePropValue)430 std::vector<AnimationParam> AnimationModule::getUpdatedAnimationParams(
431 const std::vector<VehiclePropValue>& vehiclePropValue) {
432 mLastCallTime = mCurrentCallTime;
433 if (!mIsCalled) {
434 mIsCalled = true;
435 mLastCallTime = (float)elapsedRealtimeNano() / 1e6;
436 }
437
438 // get current time
439 mCurrentCallTime = (float)elapsedRealtimeNano() / 1e6;
440
441 // reset mUpdatedPartsMap
442 mUpdatedPartsMap.clear();
443
444 for (const auto& vhalSignal : vehiclePropValue) {
445 // existing vhal signal
446 const uint64_t combinedId = getCombinedId(vhalSignal);
447 if (mVhalToPartsMap.find(combinedId) != mVhalToPartsMap.end()) {
448 const float valueFloat = getVhalValueFloat(vhalSignal);
449 if (mVhalStatusMap.find(combinedId) != mVhalStatusMap.end()) {
450 mVhalStatusMap.at(combinedId).vhalValueFloat = valueFloat;
451 } else {
452 mVhalStatusMap.emplace(std::make_pair(combinedId,
453 VhalStatus{
454 .vhalValueFloat = valueFloat,
455 }));
456 }
457 bool offStatus = 0 == valueFloat;
458 for (const auto& eachPart : mVhalToPartsMap.at(combinedId)) {
459 mCarPartsStatusMap.at(eachPart).vhalOffMap.at(combinedId) = offStatus;
460 }
461 }
462 }
463
464 for (auto& vhalStatus : mVhalStatusMap) {
465 // VHAL signal not found in animation
466 uint64_t vhalProperty = vhalStatus.first;
467 if (mVhalToPartsMap.find(vhalProperty) == mVhalToPartsMap.end()) {
468 LOG(WARNING) << "VHAL " << vhalProperty << " not processed.";
469 } else { // VHAL signal found
470 const auto& partsSet = mVhalToPartsMap.at(vhalProperty);
471 for (const auto& partId : partsSet) {
472 const auto& animationInfo = mPartsToAnimationMap.at(partId);
473 if (animationInfo.gammaOpsMap.find(vhalProperty) !=
474 animationInfo.gammaOpsMap.end()) {
475 LOG(INFO) << "Processing VHAL " << vhalProperty << " for gamma op.";
476 // TODO(b/158244276): add priority check.
477 for (const auto& gammaOp : animationInfo.gammaOpsMap.at(vhalProperty)) {
478 performGammaOp(partId, vhalProperty, gammaOp);
479 }
480 }
481 if (animationInfo.textureOpsMap.find(vhalProperty) !=
482 animationInfo.textureOpsMap.end()) {
483 LOG(INFO) << "Processing VHAL " << vhalProperty << " for texture op.";
484 LOG(INFO) << "Texture op currently not supported. Skipped.";
485 // TODO(b158244721): do texture op.
486 }
487 if (animationInfo.rotationOpsMap.find(vhalProperty) !=
488 animationInfo.rotationOpsMap.end()) {
489 LOG(INFO) << "Processing VHAL " << vhalProperty << " for rotation op.";
490 for (const auto& rotationOp : animationInfo.rotationOpsMap.at(vhalProperty)) {
491 performRotationOp(partId, vhalProperty, rotationOp);
492 }
493 }
494 if (animationInfo.translationOpsMap.find(vhalProperty) !=
495 animationInfo.translationOpsMap.end()) {
496 LOG(INFO) << "Processing VHAL " << vhalProperty << " for translation op.";
497 for (const auto& translationOp :
498 animationInfo.translationOpsMap.at(vhalProperty)) {
499 performTranslationOp(partId, vhalProperty, translationOp);
500 }
501 }
502 }
503 }
504 }
505
506 std::vector<AnimationParam> output;
507 for (auto& updatedPart : mUpdatedPartsMap) {
508 output.push_back(updatedPart.second);
509 }
510 return output;
511 }
512
513 } // namespace implementation
514 } // namespace V1_0
515 } // namespace sv
516 } // namespace automotive
517 } // namespace hardware
518 } // namespace android
519