From dc9bd4bdaa399e772ef1435749f0f657d3f3ec64 Mon Sep 17 00:00:00 2001 From: "Eunki, Hong" Date: Mon, 3 Jun 2024 10:51:16 +0900 Subject: [PATCH] [Tizen] Ensure cleared animation not emit finished signal during finished signal emit Since we collect all finished animations and emit after, It is possible that finisehd signal emitted what we should not (e.g. Animation::Clear() called during another animation's finished signal) To avoid it, let we ensure to check whether given animation is ignored or not. Change-Id: I681c2c8e0f1624e0846409eb862862e5392ab7ec Signed-off-by: Eunki, Hong --- automated-tests/src/dali/utc-Dali-Animation.cpp | 143 +++++++++++++++++++++ .../event/animation/animation-playlist.cpp | 46 ++++--- 2 files changed, 170 insertions(+), 19 deletions(-) diff --git a/automated-tests/src/dali/utc-Dali-Animation.cpp b/automated-tests/src/dali/utc-Dali-Animation.cpp index 50c93ed..7293256 100644 --- a/automated-tests/src/dali/utc-Dali-Animation.cpp +++ b/automated-tests/src/dali/utc-Dali-Animation.cpp @@ -54,6 +54,7 @@ struct AnimationFinishCheck void operator()(Animation& animation) { + tet_printf("emitted animation [%u]\n", animation.GetAnimationId()); mSignalReceived = true; } @@ -16028,6 +16029,8 @@ int UtcDaliAnimationReferenceCountCheck01(void) animation.FinishedSignal().Connect(&application, finishCheck); animation.Play(); + animation.Play(); + animation.Play(); application.SendNotification(); application.Render(500); @@ -16078,6 +16081,8 @@ int UtcDaliAnimationReferenceCountCheck02(void) animation.FinishedSignal().Connect(&application, finishCheck); animation.Play(); + animation.Play(); + animation.Play(); application.SendNotification(); application.Render(500); @@ -16131,6 +16136,8 @@ int UtcDaliAnimationReferenceCountCheck03(void) animation.FinishedSignal().Connect(&application, finishCheck); animation.Play(); + animation.Play(); + animation.Play(); application.SendNotification(); application.Render(500); @@ -16164,4 +16171,140 @@ int UtcDaliAnimationReferenceCountCheck03(void) DALI_TEST_EQUALS(animationCount, 0, TEST_LOCATION); END_TEST; +} + +namespace +{ +// Functor to test clear another animation during animation finished signal. +struct AnimationClearCheck +{ + AnimationClearCheck(bool& signalReceived) + : mSignalReceived(signalReceived), + mClearRequiredAnimations() + { + } + + void AddClearAnimation(Animation animation) + { + mClearRequiredAnimations.emplace_back(animation); + tet_printf("Add clear animation [%u], clear?[%zu]\n", animation.GetAnimationId(), mClearRequiredAnimations.size()); + } + + void operator()(Animation& animation) + { + tet_printf("emitted animation [%u], clear?[%zu]\n", animation.GetAnimationId(), mClearRequiredAnimations.size()); + mSignalReceived = true; + for(auto clearRequiredAnimation : mClearRequiredAnimations) + { + if(clearRequiredAnimation) + { + tet_printf("clear animation [%u]\n", clearRequiredAnimation.GetAnimationId()); + clearRequiredAnimation.Clear(); + } + } + } + + void Reset() + { + mSignalReceived = false; + } + + void CheckSignalReceived() + { + if(!mSignalReceived) + { + tet_printf("Expected Finish signal was not received\n"); + tet_result(TET_FAIL); + } + else + { + tet_result(TET_PASS); + } + } + + void CheckSignalNotReceived() + { + if(mSignalReceived) + { + tet_printf("Unexpected Finish signal was received\n"); + tet_result(TET_FAIL); + } + else + { + tet_result(TET_PASS); + } + } + + bool& mSignalReceived; // owned by individual tests + + std::vector mClearRequiredAnimations; +}; + +} // namespace +int UtcDaliAnimationClearDuringAnimationFinished(void) +{ + tet_infoline("UtcDaliAnimationClearDuringAnimationFinished"); + + TestApplication application; + + auto actor = Actor::New(); + actor.SetProperty(Actor::Property::POSITION, Vector2(100.0f, 100.0f)); + application.GetScene().Add(actor); + + auto animation1 = Animation::New(1.0f); + auto animation2 = Animation::New(1.0f); + auto animation3 = Animation::New(1.0f); + animation1.AnimateTo(Property(actor, Actor::Property::POSITION_X), 150.0f); + animation2.AnimateTo(Property(actor, Actor::Property::POSITION_Y), 200.0f); + animation3.AnimateTo(Property(actor, Actor::Property::POSITION_Z), 250.0f); + + bool signal1Received(false); + AnimationFinishCheck finish1Check(signal1Received); + + bool signal2Received(false); + AnimationClearCheck finish2Check(signal2Received); + + bool signal3Received(false); + AnimationFinishCheck finish3Check(signal3Received); + + // Set clear finish signals. + finish2Check.AddClearAnimation(animation1); + finish2Check.AddClearAnimation(animation2); + finish2Check.AddClearAnimation(animation3); + + animation1.FinishedSignal().Connect(&application, finish1Check); + animation2.FinishedSignal().Connect(&application, finish2Check); + animation3.FinishedSignal().Connect(&application, finish3Check); + + animation1.Play(); + animation2.Play(); + animation3.Play(); + + application.SendNotification(); + application.Render(500); + + uint32_t animationCount = Dali::DevelAnimation::GetAnimationCount(); + DALI_TEST_EQUALS(animationCount, 3, TEST_LOCATION); + + application.SendNotification(); + application.Render(509); // Animation finished + + animationCount = Dali::DevelAnimation::GetAnimationCount(); + DALI_TEST_EQUALS(animationCount, 3, TEST_LOCATION); + + finish1Check.CheckSignalNotReceived(); + finish2Check.CheckSignalNotReceived(); + finish3Check.CheckSignalNotReceived(); + + // Notify animation finished signal. + application.SendNotification(); + + tet_printf("Check animation 1 and 2 receive, and 3 not.\n"); + tet_printf("Since current Animation finished signal emitted ordered by\n 1. Finished frame.\n 2. Creation time.\n"); + + finish1Check.CheckSignalReceived(); + finish2Check.CheckSignalReceived(); + finish3Check.CheckSignalNotReceived(); + + END_TEST; } \ No newline at end of file diff --git a/dali/internal/event/animation/animation-playlist.cpp b/dali/internal/event/animation/animation-playlist.cpp index 5889bd4..e1ba420 100644 --- a/dali/internal/event/animation/animation-playlist.cpp +++ b/dali/internal/event/animation/animation-playlist.cpp @@ -132,7 +132,7 @@ void AnimationPlaylist::NotifyCompleted(CompleteNotificationInterface::Parameter #endif DALI_TRACE_BEGIN_WITH_MESSAGE_GENERATOR(gTraceFilter, "DALI_ANIMATION_FINISHED", [&](std::ostringstream& oss) { - oss << "[n:" << notifierIdList.Count() << ", i:" << mIgnoredAnimations.size() << "]"; + oss << "[n:" << notifierIdList.Count() << ",i:" << mIgnoredAnimations.size() << "]"; }); for(const auto& notifierId : notifierIdList) @@ -161,33 +161,41 @@ void AnimationPlaylist::NotifyCompleted(CompleteNotificationInterface::Parameter // Now it's safe to emit the signals for(auto& animation : finishedAnimations) { -#ifdef TRACE_ENABLED - if(gTraceFilter && gTraceFilter->IsTraceEnabled()) + // Check whether given animation still available (Since it could be cleared during finished signal emitted). + if(DALI_LIKELY(mIgnoredAnimations.find(animation.GetAnimationId()) == mIgnoredAnimations.end())) { - start = GetNanoseconds(); - } +#ifdef TRACE_ENABLED + if(gTraceFilter && gTraceFilter->IsTraceEnabled()) + { + start = GetNanoseconds(); + } #endif - GetImplementation(animation).EmitSignalFinish(); + GetImplementation(animation).EmitSignalFinish(); #ifdef TRACE_ENABLED - if(gTraceFilter && gTraceFilter->IsTraceEnabled()) - { - end = GetNanoseconds(); - animationFinishedTimeChecker.emplace_back(end - start, GetImplementation(animation).GetSceneObject()->GetNotifyId()); - } + if(gTraceFilter && gTraceFilter->IsTraceEnabled()) + { + end = GetNanoseconds(); + animationFinishedTimeChecker.emplace_back(end - start, GetImplementation(animation).GetSceneObject()->GetNotifyId()); + } #endif + } } DALI_TRACE_END_WITH_MESSAGE_GENERATOR(gTraceFilter, "DALI_ANIMATION_FINISHED", [&](std::ostringstream& oss) { - oss << "[f:" << finishedAnimations.size() << ","; - - std::sort(animationFinishedTimeChecker.rbegin(), animationFinishedTimeChecker.rend()); - auto topCount = std::min(5u, static_cast(animationFinishedTimeChecker.size())); + oss << "[f:" << finishedAnimations.size() << ",i:" << mIgnoredAnimations.size(); - oss << "top" << topCount; - for(auto i = 0u; i < topCount; ++i) + if(finishedAnimations.size() > 0u) { - oss << "(" << static_cast(animationFinishedTimeChecker[i].first) / 1000000.0f << "ms,"; - oss << animationFinishedTimeChecker[i].second << ")"; + oss << ","; + std::sort(animationFinishedTimeChecker.rbegin(), animationFinishedTimeChecker.rend()); + auto topCount = std::min(5u, static_cast(animationFinishedTimeChecker.size())); + + oss << "top" << topCount; + for(auto i = 0u; i < topCount; ++i) + { + oss << "(" << static_cast(animationFinishedTimeChecker[i].first) / 1000000.0f << "ms,"; + oss << animationFinishedTimeChecker[i].second << ")"; + } } oss << "]"; }); -- 2.7.4