animation1.Play();
application.SendNotification();
- application.Render(static_cast<unsigned int>(durationSeconds * 1000.0f) - 1u /*just less than the animation duration*/);
+ application.Render(static_cast<unsigned int>(durationSeconds * 1000.0f) - 100u /*just less than the animation duration*/);
// The event side property should be set the current value immediately
DALI_TEST_EQUALS(actor.GetProperty(Actor::Property::POSITION).Get<Vector3>(), targetPosition1, VECTOR3_EPSILON, TEST_LOCATION);
application.SendNotification();
- application.Render(2u /*just beyond the animation duration*/);
+ application.Render(200u /*just beyond the animation duration*/);
// Build a new animation
Animation animation2 = Animation::New(durationSeconds);
animation2.Play();
application.SendNotification();
- application.Render(static_cast<unsigned int>(durationSeconds * 1000.0f) - 1u /*just less than the animation duration*/);
+ application.Render(static_cast<unsigned int>(durationSeconds * 1000.0f) - 100u /*just less than the animation duration*/);
// The event side property should be set the current value immediately
DALI_TEST_EQUALS(actor.GetProperty(Actor::Property::POSITION).Get<Vector3>(), targetPosition2, VECTOR3_EPSILON, TEST_LOCATION);
animation1.Clear();
application.SendNotification();
- application.Render(static_cast<unsigned int>(durationSeconds * 1000.0f) - 1u /*just less than the animation duration*/);
+ application.Render(static_cast<unsigned int>(durationSeconds * 1000.0f) - 100u /*just less than the animation duration*/);
// The property should not be changed.
DALI_TEST_EQUALS(actor.GetProperty(Actor::Property::POSITION).Get<Vector3>(), targetPosition2, VECTOR3_EPSILON, TEST_LOCATION);
};
} // namespace
+
int UtcDaliAnimationClearDuringAnimationFinished(void)
{
tet_infoline("UtcDaliAnimationClearDuringAnimationFinished");
finish2Check.CheckSignalReceived();
finish3Check.CheckSignalNotReceived();
+ END_TEST;
+}
+
+int UtcDaliAnimationPlayAfterStopGetState(void)
+{
+ TestApplication application;
+
+ Actor actor = Actor::New();
+ application.GetScene().Add(actor);
+
+ // Build the animation
+ float durationSeconds(1.0f);
+ Animation animation = Animation::New(durationSeconds);
+ Vector3 initialPosition(0.0f, 0.0f, 0.0f);
+ Vector3 targetPosition(100.0f, 100.0f, 100.0f);
+ actor.SetProperty(Actor::Property::POSITION, initialPosition);
+ animation.AnimateTo(Property(actor, Actor::Property::POSITION), targetPosition, AlphaFunction::LINEAR);
+
+ Vector3 fiftyPercentProgress = (initialPosition + targetPosition) * 0.5f;
+
+ bool signalReceived(false);
+ AnimationFinishCheck finishCheck(signalReceived);
+ animation.FinishedSignal().Connect(&application, finishCheck);
+
+ // Stop and Play.
+ {
+ tet_printf("Play, than Stop and Play immediately. Check the current value and animation state\n");
+ // Start the animation.
+ animation.Play();
+
+ DALI_TEST_EQUALS(animation.GetState(), Dali::Animation::State::PLAYING, TEST_LOCATION);
+ DALI_TEST_EQUALS(actor.GetCurrentProperty<Vector3>(Actor::Property::POSITION), initialPosition, TEST_LOCATION);
+
+ finishCheck.CheckSignalNotReceived();
+ application.SendNotification();
+ application.Render(500);
+
+ DALI_TEST_EQUALS(animation.GetState(), Dali::Animation::State::PLAYING, TEST_LOCATION);
+ DALI_TEST_EQUALS(actor.GetCurrentProperty<Vector3>(Actor::Property::POSITION), fiftyPercentProgress, TEST_LOCATION);
+
+ // Stop, and Play immediately
+ animation.Stop();
+ DALI_TEST_EQUALS(animation.GetState(), Dali::Animation::State::STOPPED, TEST_LOCATION);
+ actor.SetProperty(Actor::Property::POSITION, initialPosition);
+ animation.Play();
+ DALI_TEST_EQUALS(animation.GetState(), Dali::Animation::State::PLAYING, TEST_LOCATION);
+
+ DALI_TEST_EQUALS(actor.GetCurrentProperty<Vector3>(Actor::Property::POSITION), fiftyPercentProgress, TEST_LOCATION);
+
+ finishCheck.CheckSignalNotReceived();
+ application.SendNotification();
+
+ // Re-play the animation. So the position value changed after Render execute.
+ DALI_TEST_EQUALS(actor.GetCurrentProperty<Vector3>(Actor::Property::POSITION), fiftyPercentProgress, TEST_LOCATION);
+ application.Render(0);
+ DALI_TEST_EQUALS(actor.GetCurrentProperty<Vector3>(Actor::Property::POSITION), initialPosition, TEST_LOCATION);
+
+ application.SendNotification();
+
+ // expect finished signal recieved due to Stop API.
+ finishCheck.CheckSignalReceived();
+ finishCheck.Reset();
+
+ // Even if finished signal recieved, animation state should be playing for now.
+ DALI_TEST_EQUALS(animation.GetState(), Dali::Animation::State::PLAYING, TEST_LOCATION);
+
+ application.Render(500);
+ DALI_TEST_EQUALS(actor.GetCurrentProperty<Vector3>(Actor::Property::POSITION), fiftyPercentProgress, TEST_LOCATION);
+
+ DALI_TEST_EQUALS(animation.GetState(), Dali::Animation::State::PLAYING, TEST_LOCATION);
+
+ finishCheck.CheckSignalNotReceived();
+
+ application.SendNotification();
+ application.Render(550);
+ DALI_TEST_EQUALS(actor.GetCurrentProperty<Vector3>(Actor::Property::POSITION), targetPosition, TEST_LOCATION);
+
+ // Still Playing since animation finished signal not comming yet.
+ DALI_TEST_EQUALS(animation.GetState(), Dali::Animation::State::PLAYING, TEST_LOCATION);
+
+ // expect finished signal recieved due to Stop API.
+ application.SendNotification();
+ finishCheck.CheckSignalReceived();
+
+ // And now animation state is stopped.
+ DALI_TEST_EQUALS(animation.GetState(), Dali::Animation::State::STOPPED, TEST_LOCATION);
+
+ // Reset test status
+ finishCheck.Reset();
+ application.SendNotification();
+ application.Render(0);
+ actor.SetProperty(Actor::Property::POSITION, initialPosition);
+ application.SendNotification();
+ application.Render(0);
+ }
+
+ // Stop and Pause.
+ {
+ tet_printf("Play, than Stop and Pause immediately. Check the current value and animation state\n");
+ // Start the animation.
+ animation.Play();
+
+ DALI_TEST_EQUALS(animation.GetState(), Dali::Animation::State::PLAYING, TEST_LOCATION);
+ DALI_TEST_EQUALS(actor.GetCurrentProperty<Vector3>(Actor::Property::POSITION), initialPosition, TEST_LOCATION);
+
+ finishCheck.CheckSignalNotReceived();
+ application.SendNotification();
+ application.Render(500);
+
+ DALI_TEST_EQUALS(animation.GetState(), Dali::Animation::State::PLAYING, TEST_LOCATION);
+ DALI_TEST_EQUALS(actor.GetCurrentProperty<Vector3>(Actor::Property::POSITION), fiftyPercentProgress, TEST_LOCATION);
+
+ // Stop, and Pause immediately
+ animation.Stop();
+ DALI_TEST_EQUALS(animation.GetState(), Dali::Animation::State::STOPPED, TEST_LOCATION);
+ actor.SetProperty(Actor::Property::POSITION, initialPosition);
+ animation.Pause();
+ DALI_TEST_EQUALS(animation.GetState(), Dali::Animation::State::PAUSED, TEST_LOCATION);
+
+ DALI_TEST_EQUALS(actor.GetCurrentProperty<Vector3>(Actor::Property::POSITION), fiftyPercentProgress, TEST_LOCATION);
+
+ finishCheck.CheckSignalNotReceived();
+ application.SendNotification();
+
+ // Animation is stopped. So the position value not be changed after Render execute.
+ DALI_TEST_EQUALS(actor.GetCurrentProperty<Vector3>(Actor::Property::POSITION), fiftyPercentProgress, TEST_LOCATION);
+ application.Render(0);
+ DALI_TEST_EQUALS(actor.GetCurrentProperty<Vector3>(Actor::Property::POSITION), initialPosition, TEST_LOCATION);
+
+ application.SendNotification();
+
+ // expect finished signal recieved due to Stop API.
+ finishCheck.CheckSignalReceived();
+ finishCheck.Reset();
+
+ // Even if finished signal recieved, animation state should be paused for now.
+ DALI_TEST_EQUALS(animation.GetState(), Dali::Animation::State::PAUSED, TEST_LOCATION);
+
+ application.Render(500);
+ DALI_TEST_EQUALS(actor.GetCurrentProperty<Vector3>(Actor::Property::POSITION), initialPosition, TEST_LOCATION);
+
+ DALI_TEST_EQUALS(animation.GetState(), Dali::Animation::State::PAUSED, TEST_LOCATION);
+
+ application.SendNotification();
+ finishCheck.CheckSignalNotReceived();
+
+ // Reset test status
+ finishCheck.Reset();
+ application.SendNotification();
+ application.Render(0);
+ actor.SetProperty(Actor::Property::POSITION, initialPosition);
+ application.SendNotification();
+ application.Render(0);
+ }
+
+ // Stop and Play and Stop.
+ {
+ tet_printf("Play, than Stop / Play / Stop immediately. Check the current value and animation state\n");
+ // Start the animation.
+ animation.Play();
+
+ DALI_TEST_EQUALS(animation.GetState(), Dali::Animation::State::PLAYING, TEST_LOCATION);
+ DALI_TEST_EQUALS(actor.GetCurrentProperty<Vector3>(Actor::Property::POSITION), initialPosition, TEST_LOCATION);
+
+ finishCheck.CheckSignalNotReceived();
+ application.SendNotification();
+ application.Render(500);
+
+ DALI_TEST_EQUALS(animation.GetState(), Dali::Animation::State::PLAYING, TEST_LOCATION);
+ DALI_TEST_EQUALS(actor.GetCurrentProperty<Vector3>(Actor::Property::POSITION), fiftyPercentProgress, TEST_LOCATION);
+
+ // Stop, and Play and Stop immediately
+ animation.Stop();
+ DALI_TEST_EQUALS(animation.GetState(), Dali::Animation::State::STOPPED, TEST_LOCATION);
+ actor.SetProperty(Actor::Property::POSITION, initialPosition);
+ animation.Play();
+ DALI_TEST_EQUALS(animation.GetState(), Dali::Animation::State::PLAYING, TEST_LOCATION);
+ animation.Stop();
+ DALI_TEST_EQUALS(animation.GetState(), Dali::Animation::State::STOPPED, TEST_LOCATION);
+
+ DALI_TEST_EQUALS(actor.GetCurrentProperty<Vector3>(Actor::Property::POSITION), fiftyPercentProgress, TEST_LOCATION);
+
+ finishCheck.CheckSignalNotReceived();
+ application.SendNotification();
+
+ // Animation is stopped. So the position value not be changed after Render execute.
+ DALI_TEST_EQUALS(actor.GetCurrentProperty<Vector3>(Actor::Property::POSITION), fiftyPercentProgress, TEST_LOCATION);
+ application.Render(0);
+ DALI_TEST_EQUALS(actor.GetCurrentProperty<Vector3>(Actor::Property::POSITION), initialPosition, TEST_LOCATION);
+
+ application.SendNotification();
+
+ // expect finished signal recieved due to Stop API.
+ finishCheck.CheckSignalReceived();
+ finishCheck.Reset();
+
+ // Animation state should be stopped for now.
+ DALI_TEST_EQUALS(animation.GetState(), Dali::Animation::State::STOPPED, TEST_LOCATION);
+
+ application.Render(500);
+ DALI_TEST_EQUALS(actor.GetCurrentProperty<Vector3>(Actor::Property::POSITION), initialPosition, TEST_LOCATION);
+
+ DALI_TEST_EQUALS(animation.GetState(), Dali::Animation::State::STOPPED, TEST_LOCATION);
+
+ application.SendNotification();
+ finishCheck.CheckSignalNotReceived();
+
+ // Reset test status
+ finishCheck.Reset();
+ application.SendNotification();
+ application.Render(0);
+ actor.SetProperty(Actor::Property::POSITION, initialPosition);
+ application.SendNotification();
+ application.Render(0);
+ }
+
END_TEST;
}
\ No newline at end of file
DALI_ASSERT_ALWAYS(period.durationSeconds >= 0 && "Duration must be >=0");
}
+/**
+ * @brief Converts the internal state to the target state.
+ * @param[in, out] currentState The current state of the animation.
+ * @param[in] targetState The target state of the animation.
+ * @return True if the animation state has been changed.
+ */
+bool InternalStateConverter(Internal::Animation::InternalState& currentState, Dali::Animation::State targetState)
+{
+ bool changed = false;
+ switch(targetState)
+ {
+ case Dali::Animation::PLAYING:
+ {
+ switch(currentState)
+ {
+ case Internal::Animation::CLEARED:
+ case Internal::Animation::STOPPED:
+ case Internal::Animation::PAUSED:
+ {
+ currentState = Internal::Animation::InternalState::PLAYING;
+ changed = true;
+ break;
+ }
+ case Internal::Animation::STOPPING:
+ case Internal::Animation::PAUSED_DURING_STOPPING:
+ {
+ currentState = Internal::Animation::InternalState::PLAYING_DURING_STOPPING;
+ changed = true;
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+ break;
+ }
+ case Dali::Animation::PAUSED:
+ {
+ switch(currentState)
+ {
+ case Internal::Animation::CLEARED:
+ case Internal::Animation::STOPPED:
+ case Internal::Animation::PLAYING:
+ {
+ currentState = Internal::Animation::InternalState::PAUSED;
+ changed = true;
+ break;
+ }
+ case Internal::Animation::STOPPING:
+ case Internal::Animation::PLAYING_DURING_STOPPING:
+ {
+ currentState = Internal::Animation::InternalState::PAUSED_DURING_STOPPING;
+ changed = true;
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+ break;
+ }
+ case Dali::Animation::STOPPED:
+ {
+ switch(currentState)
+ {
+ case Internal::Animation::PLAYING:
+ case Internal::Animation::PLAYING_DURING_STOPPING:
+ case Internal::Animation::PAUSED:
+ case Internal::Animation::PAUSED_DURING_STOPPING:
+ {
+ currentState = Internal::Animation::InternalState::STOPPING;
+ changed = true;
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+ break;
+ }
+ }
+ return changed;
+}
+
} // anonymous namespace
AnimationPtr Animation::New(float durationSeconds)
void Animation::Play()
{
- mPlayCalled = true;
-
// Update the current playlist
mPlaylist.OnPlay(*this);
- mState = Dali::Animation::PLAYING;
+ InternalStateConverter(mState, Dali::Animation::PLAYING);
NotifyObjects(Notify::USE_TARGET_VALUE);
{
if(progress >= mPlayRange.x && progress <= mPlayRange.y)
{
- mPlayCalled = true;
-
// Update the current playlist
mPlaylist.OnPlay(*this);
- mState = Dali::Animation::PLAYING;
+ InternalStateConverter(mState, Dali::Animation::PLAYING);
NotifyObjects(Notify::USE_TARGET_VALUE);
void Animation::PlayAfter(float delaySeconds)
{
- mPlayCalled = true;
-
// The negative delay means play immediately.
delaySeconds = std::max(0.f, delaySeconds);
// Update the current playlist
mPlaylist.OnPlay(*this);
- mState = Dali::Animation::PLAYING;
+ InternalStateConverter(mState, Dali::Animation::PLAYING);
NotifyObjects(Notify::USE_TARGET_VALUE);
void Animation::Pause()
{
- if(mState != Dali::Animation::PAUSED)
+ if(InternalStateConverter(mState, Dali::Animation::PAUSED))
{
- mState = Dali::Animation::PAUSED;
-
// mAnimation is being used in a separate thread; queue a Pause message
PauseAnimationMessage(mEventThreadServices, *mAnimation);
Dali::Animation::State Animation::GetState() const
{
- return mState;
+ Dali::Animation::State state = Dali::Animation::State::STOPPED;
+ switch(mState)
+ {
+ case Dali::Internal::Animation::InternalState::STOPPED:
+ case Dali::Internal::Animation::InternalState::CLEARED:
+ case Dali::Internal::Animation::InternalState::STOPPING:
+ {
+ state = Dali::Animation::State::STOPPED;
+ break;
+ }
+ case Dali::Internal::Animation::InternalState::PLAYING:
+ case Dali::Internal::Animation::InternalState::PLAYING_DURING_STOPPING:
+ {
+ state = Dali::Animation::State::PLAYING;
+ break;
+ }
+ case Dali::Internal::Animation::InternalState::PAUSED:
+ case Dali::Internal::Animation::InternalState::PAUSED_DURING_STOPPING:
+ {
+ state = Dali::Animation::State::PAUSED;
+ break;
+ }
+ }
+ return state;
}
void Animation::Stop()
{
- if(mState != Dali::Animation::STOPPED)
+ if(InternalStateConverter(mState, Dali::Animation::STOPPED))
{
- mState = Dali::Animation::STOPPED;
-
// mAnimation is being used in a separate thread; queue a Stop message
StopAnimationMessage(mEventThreadServices.GetUpdateManager(), *mAnimation);
{
DALI_ASSERT_DEBUG(mAnimation);
- if(mConnectors.Empty() && mState == Dali::Animation::STOPPED && !mPlayCalled)
+ if(mConnectors.Empty() && mState == Dali::Internal::Animation::CLEARED)
{
// Animation is empty. Fast-out
return;
}
// Only notify the objects with the current values if the end action is set to BAKE
- if(mEndAction == EndAction::BAKE && mState != Dali::Animation::STOPPED)
+ if(mEndAction == EndAction::BAKE && GetState() != Dali::Animation::STOPPED)
{
NotifyObjects(Notify::USE_CURRENT_VALUE);
}
// Reset the notification count and relative values, since the new scene-object has never been played
mNotificationCount = 0;
- mState = Dali::Animation::STOPPED;
- mPlayCalled = false;
+ mState = Dali::Internal::Animation::CLEARED;
// Update the current playlist
mPlaylist.OnClear(*this, true);
// Note that only one signal is emitted, if the animation has been played repeatedly
mNotificationCount = playedCount;
- hasFinished = true;
-
- mState = Dali::Animation::STOPPED;
+ switch(mState)
+ {
+ case Internal::Animation::InternalState::PLAYING:
+ case Internal::Animation::InternalState::STOPPING:
+ {
+ mState = Dali::Internal::Animation::STOPPED;
+ hasFinished = true;
+ break;
+ }
+ case Internal::Animation::InternalState::PLAYING_DURING_STOPPING:
+ {
+ mState = Dali::Internal::Animation::PLAYING;
+ hasFinished = true;
+ break;
+ }
+ case Internal::Animation::InternalState::PAUSED_DURING_STOPPING:
+ {
+ mState = Dali::Internal::Animation::PAUSED;
+ hasFinished = true;
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
}
return hasFinished;
BETWEEN ///< Animating BETWEEN key-frames
};
+ enum InternalState : uint8_t
+ {
+ STOPPED = Dali::Animation::State::STOPPED, ///< @copydoc Dali::Animation::State::STOPPED
+ PLAYING = Dali::Animation::State::PLAYING, ///< @copydoc Dali::Animation::State::PLAYING
+ PAUSED = Dali::Animation::State::PAUSED, ///< @copydoc Dali::Animation::State::PAUSED
+
+ CLEARED, ///< Animation is cleared.
+ STOPPING, ///< Stopping animation. It will be STOPPED when animation finisehd signal called.
+ PLAYING_DURING_STOPPING, ///< Play called during stopping. It will be PLAYING when animation finisehd signal called.
+ PAUSED_DURING_STOPPING, ///< Pause called during stopping. It will be PAUSED when animation finisehd signal called.
+ };
+
using EndAction = Dali::Animation::EndAction;
using Interpolation = Dali::Animation::Interpolation;
uint32_t mAnimationId{0u};
- AlphaFunction mDefaultAlpha;
- Vector2 mPlayRange{0.0f, 1.0f};
- float mBlendPoint{0.0f};
- float mDurationSeconds;
- float mSpeedFactor{1.0f};
- int32_t mNotificationCount{0}; ///< Keep track of how many Finished signals have been emitted.
- int32_t mLoopCount{1};
- float mProgressReachedMarker{0.0f};
- float mDelaySeconds{0.0f};
- EndAction mEndAction;
- EndAction mDisconnectAction;
- Dali::Animation::State mState{Dali::Animation::STOPPED};
- bool mAutoReverseEnabled{false}; ///< Flag to identify that the looping mode is auto reverse.
- bool mConnectorTargetValuesSortRequired{false}; ///< Flag to whether we need to sort mConnectorTargetValues or not
- bool mPlayCalled{false}; ///< Flag to whether we call Play at least 1 time after create, or clear.
+ AlphaFunction mDefaultAlpha;
+ Vector2 mPlayRange{0.0f, 1.0f};
+ float mBlendPoint{0.0f};
+ float mDurationSeconds;
+ float mSpeedFactor{1.0f};
+ int32_t mNotificationCount{0}; ///< Keep track of how many Finished signals have been emitted.
+ int32_t mLoopCount{1};
+ float mProgressReachedMarker{0.0f};
+ float mDelaySeconds{0.0f};
+ EndAction mEndAction;
+ EndAction mDisconnectAction;
+ InternalState mState{InternalState::CLEARED};
+ bool mAutoReverseEnabled{false}; ///< Flag to identify that the looping mode is auto reverse.
+ bool mConnectorTargetValuesSortRequired{false}; ///< Flag to whether we need to sort mConnectorTargetValues or not
};
} // namespace Internal