Ensure animation is not played when an actor is not on scene 98/243898/2
authorHeeyong Song <heeyong.song@samsung.com>
Fri, 11 Sep 2020 04:05:09 +0000 (13:05 +0900)
committerHeeyong Song <heeyong.song@samsung.com>
Fri, 11 Sep 2020 06:52:53 +0000 (15:52 +0900)
Change-Id: Iadfe60520ad14de6db2c1867bc6df223fa5bf10a

13 files changed:
automated-tests/src/dali/utc-Dali-Actor.cpp
automated-tests/src/dali/utc-Dali-Animation.cpp
automated-tests/src/dali/utc-Dali-CustomActor.cpp
automated-tests/src/dali/utc-Dali-TypeRegistry.cpp
dali/internal/event/actors/actor-impl.cpp
dali/internal/event/actors/actor-impl.h
dali/internal/event/animation/animation-impl.cpp
dali/internal/event/common/object-impl.h
dali/internal/update/animation/scene-graph-animator.h
dali/internal/update/common/property-owner.cpp
dali/internal/update/common/property-owner.h
dali/internal/update/nodes/node.cpp
dali/internal/update/nodes/node.h

index f0aef23..0b2a35b 100644 (file)
@@ -1296,6 +1296,8 @@ int UtcDaliActorGetCurrentSizeImmediate(void)
 
   DALI_TEST_CHECK(actor.GetTargetSize() == vector);
 
+  application.GetScene().Add(actor);
+
   // Start the animation
   animation.Play();
 
index 629d3e4..7c229c0 100644 (file)
@@ -2216,9 +2216,91 @@ int UtcDaliAnimationPlayP(void)
   END_TEST;
 }
 
+int UtcDaliAnimationPlayOffSceneP(void)
+{
+  // Test that an animation cannot be played, when the actor is off-stage.
+  // And the property value and the current property value should not be changed in the case.
+
+  TestApplication application;
+
+  Actor   actor = Actor::New();
+  Vector3 basePosition(Vector3::ZERO);
+  DALI_TEST_EQUALS(actor.GetCurrentProperty<Vector3>(Actor::Property::POSITION), basePosition, TEST_LOCATION);
+  // Not added to the stage yet!
+
+  // Build the animation
+  float     durationSeconds(1.0f);
+  Animation animation = Animation::New(durationSeconds);
+  Vector3   targetPosition(100.0f, 100.0f, 100.0f);
+  animation.AnimateTo(Property(actor, Actor::Property::POSITION), targetPosition, AlphaFunction::LINEAR);
+
+  // Start the animation
+  animation.Play();
+
+  bool                 signalReceived(false);
+  AnimationFinishCheck finishCheck(signalReceived);
+  animation.FinishedSignal().Connect(&application, finishCheck);
+
+  application.SendNotification();
+  application.Render(static_cast<unsigned int>(durationSeconds * 1000.0f) + 1u /*just beyond the animation duration*/);
+
+  application.SendNotification();
+  finishCheck.CheckSignalReceived();
+
+  // An animation can't be played. The position shouldn't be changed.
+  DALI_TEST_EQUALS(actor.GetCurrentProperty<Vector3>(Actor::Property::POSITION), basePosition, TEST_LOCATION);
+  DALI_TEST_EQUALS(actor.GetProperty<Vector3>(Actor::Property::POSITION), basePosition, TEST_LOCATION);
+
+  // Add to the stage
+  application.GetScene().Add(actor);
+
+  // Start the animation again
+  animation.Play();
+
+  application.SendNotification();
+  application.Render(static_cast<unsigned int>(durationSeconds * 1000.0f) + 1u /*just beyond the animation duration*/);
+
+  // We did expect the animation to finish
+  application.SendNotification();
+  finishCheck.CheckSignalReceived();
+
+  DALI_TEST_EQUALS(actor.GetCurrentProperty<Vector3>(Actor::Property::POSITION), targetPosition, TEST_LOCATION);
+  DALI_TEST_EQUALS(actor.GetProperty<Vector3>(Actor::Property::POSITION), targetPosition, TEST_LOCATION);
+
+  // Reset the position
+  actor[Actor::Property::POSITION] = basePosition;
+
+  application.SendNotification();
+  application.Render();
+
+  // Create an animator again
+  animation.Clear();
+  animation.AnimateTo(Property(actor, Actor::Property::POSITION), targetPosition, AlphaFunction::LINEAR);
+
+  // Remove from the stage
+  application.GetScene().Remove(actor);
+
+  signalReceived = false;
+
+  // Start the animation again
+  animation.Play();
+
+  application.SendNotification();
+  application.Render(static_cast<unsigned int>(durationSeconds * 1000.0f) + 1u /*just beyond the animation duration*/);
+
+  application.SendNotification();
+  finishCheck.CheckSignalReceived();
+
+  // An animation can't be played. The position shouldn't be changed.
+  DALI_TEST_EQUALS(actor.GetCurrentProperty<Vector3>(Actor::Property::POSITION), basePosition, TEST_LOCATION);
+  DALI_TEST_EQUALS(actor.GetProperty<Vector3>(Actor::Property::POSITION), basePosition, TEST_LOCATION);
+
+  END_TEST;
+}
+
 int UtcDaliAnimationPlayOffSceneDiscardP(void)
 {
-  // Test that an animation can be played, when the actor is off-stage.
+  // Test that an animation cannot be played, when the actor is off-stage.
   // When the actor is added to the stage, it should appear at the current position
   // i.e. where it would have been anyway, if on-stage from the beginning.
 
@@ -2249,7 +2331,9 @@ int UtcDaliAnimationPlayOffSceneDiscardP(void)
   // We didn't expect the animation to finish yet
   application.SendNotification();
   finishCheck.CheckSignalNotReceived();
-  DALI_TEST_EQUALS(actor.GetCurrentProperty<Vector3>(Actor::Property::POSITION), Vector3(20, 20, 20), TEST_LOCATION);
+
+  // An animation can't be played. The position shouldn't be changed.
+  DALI_TEST_EQUALS(actor.GetCurrentProperty<Vector3>(Actor::Property::POSITION), basePosition, TEST_LOCATION);
 
   // Add to the stage
   application.GetScene().Add(actor);
@@ -2310,7 +2394,7 @@ int UtcDaliAnimationPlayOffSceneDiscardP(void)
 
 int UtcDaliAnimationPlayOffSceneBakeFinalP(void)
 {
-  // Test that an animation can be played, when the actor is off-stage.
+  // Test that an animation cannot be played, when the actor is off-stage.
   // When the actor is added to the stage, it should appear at the current position
   // i.e. where it would have been anyway, if on-stage from the beginning.
 
@@ -2340,7 +2424,9 @@ int UtcDaliAnimationPlayOffSceneBakeFinalP(void)
   // We didn't expect the animation to finish yet
   application.SendNotification();
   finishCheck.CheckSignalNotReceived();
-  DALI_TEST_EQUALS(actor.GetCurrentProperty<Vector3>(Actor::Property::POSITION), Vector3(20, 20, 20), TEST_LOCATION);
+
+  // An animation can't be played. The position shouldn't be changed.
+  DALI_TEST_EQUALS(actor.GetCurrentProperty<Vector3>(Actor::Property::POSITION), basePosition, TEST_LOCATION);
 
   // Add to the stage
   application.GetScene().Add(actor);
@@ -2394,7 +2480,7 @@ int UtcDaliAnimationPlayOffSceneBakeFinalP(void)
 
 int UtcDaliAnimationPlayOffSceneBakeP(void)
 {
-  // Test that an animation can be played, when the actor is off-stage.
+  // Test that an animation cannot be played, when the actor is off-stage.
   // When the actor is added to the stage, it should appear at the current position
   // i.e. where it would have been anyway, if on-stage from the beginning.
 
@@ -2425,7 +2511,9 @@ int UtcDaliAnimationPlayOffSceneBakeP(void)
   // We didn't expect the animation to finish yet
   application.SendNotification();
   finishCheck.CheckSignalNotReceived();
-  DALI_TEST_EQUALS(actor.GetCurrentProperty<Vector3>(Actor::Property::POSITION), Vector3(20, 20, 20), TEST_LOCATION);
+
+  // An animation can't be played. The position shouldn't be changed.
+  DALI_TEST_EQUALS(actor.GetCurrentProperty<Vector3>(Actor::Property::POSITION), basePosition, TEST_LOCATION);
 
   // Add to the stage
   application.GetScene().Add(actor);
index 6dd051c..208f563 100644 (file)
@@ -950,6 +950,8 @@ int UtcDaliCustomActorOnSizeAnimation(void)
   Test::TestCustomActor custom = Test::TestCustomActor::New();
   DALI_TEST_EQUALS(0, (int)(custom.GetMethodsCalled().size()), TEST_LOCATION);
 
+  application.GetScene().Add(custom);
+
   Animation anim = Animation::New(1.0f);
   anim.AnimateTo(Property(custom, Actor::Property::SIZE), Vector3(8.0f, 9.0f, 10.0f));
   anim.Play();
@@ -957,8 +959,8 @@ int UtcDaliCustomActorOnSizeAnimation(void)
   application.SendNotification();
   application.Render(static_cast<unsigned int>(1000.0f));
 
-  DALI_TEST_EQUALS(1, (int)(custom.GetMethodsCalled().size()), TEST_LOCATION);
-  DALI_TEST_EQUALS("OnSizeAnimation", custom.GetMethodsCalled()[0], TEST_LOCATION);
+  DALI_TEST_EQUALS(2, (int)(custom.GetMethodsCalled().size()), TEST_LOCATION);
+  DALI_TEST_EQUALS("OnSizeAnimation", custom.GetMethodsCalled()[1], TEST_LOCATION);
   DALI_TEST_EQUALS(8.0f, custom.GetTargetSize().width, TEST_LOCATION);
   DALI_TEST_EQUALS(9.0f, custom.GetTargetSize().height, TEST_LOCATION);
   DALI_TEST_EQUALS(10.0f, custom.GetTargetSize().depth, TEST_LOCATION);
@@ -974,24 +976,26 @@ int UtcDaliCustomActorSizeComponentAnimation(void)
   float                 intialWidth(10.0f);
 
   DALI_TEST_EQUALS(0, (int)(custom.GetMethodsCalled().size()), TEST_LOCATION);
+
   custom.SetProperty(Actor::Property::SIZE, Vector2(intialWidth, 10.0f)); // First method
+  application.GetScene().Add(custom);
 
   Animation anim = Animation::New(1.0f);
 
-  DALI_TEST_EQUALS(2, (int)(custom.GetMethodsCalled().size()), TEST_LOCATION);
+  DALI_TEST_EQUALS(3, (int)(custom.GetMethodsCalled().size()), TEST_LOCATION);
 
   anim.AnimateTo(Property(custom, Actor::Property::SIZE_WIDTH), 20.0f);
 
-  DALI_TEST_EQUALS(2, (int)(custom.GetMethodsCalled().size()), TEST_LOCATION);
+  DALI_TEST_EQUALS(3, (int)(custom.GetMethodsCalled().size()), TEST_LOCATION);
 
   anim.Play(); // Triggers second method ( OnSizeAnimation )
 
   application.SendNotification();
   application.Render(static_cast<unsigned int>(1000.0f));
 
-  DALI_TEST_EQUALS(3, (int)(custom.GetMethodsCalled().size()), TEST_LOCATION);
+  DALI_TEST_EQUALS(4, (int)(custom.GetMethodsCalled().size()), TEST_LOCATION);
 
-  DALI_TEST_EQUALS("OnSizeAnimation", custom.GetMethodsCalled()[2], TEST_LOCATION);
+  DALI_TEST_EQUALS("OnSizeAnimation", custom.GetMethodsCalled()[3], TEST_LOCATION);
 
   END_TEST;
 }
index c971314..fd7f134 100644 (file)
@@ -1393,6 +1393,8 @@ int UtcDaliTypeRegistryAnimatablePropertyComponentRegistrationP(void)
   unsigned int customActorIndices = indices.Size();
   DALI_TEST_EQUALS(actorIndices + 3u, customActorIndices, TEST_LOCATION); // Custom property + registered property
 
+  application.GetScene().Add(customActor);
+
   // Attempt to animate component property, it should not crash
   Animation animation = Animation::New(1.0f);
   animation.AnimateTo(Property(customActor, animatablePropertyComponentIndex1), 200.0f);
@@ -1416,6 +1418,7 @@ int UtcDaliTypeRegistryAnimatablePropertyComponentRegistrationVector2AnimateByP(
   BaseHandle handle = typeInfo.CreateInstance();
   DALI_TEST_CHECK(handle);
   Actor customActor = Actor::DownCast(handle);
+  application.GetScene().Add(customActor);
   DALI_TEST_CHECK(customActor);
 
   const unsigned int index           = ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX;
@@ -1469,6 +1472,7 @@ int UtcDaliTypeRegistryAnimatablePropertyComponentRegistrationVector3AnimateByP(
   BaseHandle handle = typeInfo.CreateInstance();
   DALI_TEST_CHECK(handle);
   Actor customActor = Actor::DownCast(handle);
+  application.GetScene().Add(customActor);
   DALI_TEST_CHECK(customActor);
 
   const unsigned int index           = ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX;
@@ -1528,6 +1532,7 @@ int UtcDaliTypeRegistryAnimatablePropertyComponentRegistrationVector4AnimateByP(
   BaseHandle handle = typeInfo.CreateInstance();
   DALI_TEST_CHECK(handle);
   Actor customActor = Actor::DownCast(handle);
+  application.GetScene().Add(customActor);
   DALI_TEST_CHECK(customActor);
 
   const unsigned int index           = ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX;
index 4911842..6b3386a 100644 (file)
@@ -3496,6 +3496,11 @@ int32_t Actor::GetPropertyComponentIndex( Property::Index index ) const
   return componentIndex;
 }
 
+bool Actor::IsAnimationPossible() const
+{
+  return OnScene();
+}
+
 void Actor::SetParent( Actor* parent )
 {
   if( parent )
index 6573930..379667b 100644 (file)
@@ -1679,6 +1679,11 @@ public:
   int32_t GetPropertyComponentIndex( Property::Index index ) const override;
 
   /**
+   * @copydoc Dali::Internal::Object::IsAnimationPossible()
+   */
+  bool IsAnimationPossible() const override;
+
+  /**
    * Retrieve the actor's node.
    * @return The node used by this actor
    */
index 92791da..dde0a5a 100644 (file)
@@ -1108,7 +1108,7 @@ void Animation::NotifyObjects( Animation::Notify notifyValueType )
       AnimatorConnectorBase* connector = mConnectors[ iter->connectorIndex ];
 
       Object* object = connector->GetObject();
-      if( object )
+      if(object && object->IsAnimationPossible())
       {
         const auto propertyIndex = connector->GetPropertyIndex();
         object->NotifyPropertyAnimation(
index 5e3afb1..41abd4a 100644 (file)
@@ -349,6 +349,15 @@ public:
   virtual int32_t GetPropertyComponentIndex( Property::Index index ) const;
 
   /**
+   * Query whether playing an animation is possible or not.
+   * @return true if playing an animation is possible.
+   */
+  virtual bool IsAnimationPossible() const
+  {
+    return true;
+  }
+
+  /**
    * @copydoc Dali::Handle::PropertySetSignal()
    */
   Handle::PropertySetSignalType& PropertySetSignal();
index 1cc6ab6..120aa24 100644 (file)
@@ -222,6 +222,9 @@ public:
   {
     mConnectedToSceneGraph = true;
     mPropertyOwner->AddObserver(*this);
+
+    // Enable if the target object is valid and connected to the scene graph.
+    mEnabled = mPropertyOwner->IsAnimationPossible();
   }
 
   /**
index 0d915a1..8d560ca 100644 (file)
@@ -89,6 +89,8 @@ void PropertyOwner::Destroy()
 
 void PropertyOwner::ConnectToSceneGraph()
 {
+  mIsConnectedToSceneGraph = true;
+
   // Notification for observers
   const ConstObserverIter endIter = mObservers.End();
   for( ConstObserverIter iter = mObservers.Begin(); iter != endIter; ++iter)
@@ -99,6 +101,8 @@ void PropertyOwner::ConnectToSceneGraph()
 
 void PropertyOwner::DisconnectFromSceneGraph( BufferIndex updateBufferIndex )
 {
+  mIsConnectedToSceneGraph = false;
+
   // Notification for observers
   const ConstObserverIter endIter = mObservers.End();
   for( ConstObserverIter iter = mObservers.Begin(); iter != endIter; ++iter)
@@ -143,7 +147,8 @@ void PropertyOwner::RemoveConstraint( ConstraintBase* constraint )
 }
 
 PropertyOwner::PropertyOwner()
-: mUpdated( false )
+: mUpdated(false),
+  mIsConnectedToSceneGraph(false)
 {
 }
 
index c4dd922..5fbfc5a 100644 (file)
@@ -223,6 +223,14 @@ public:
    */
   void RemoveUniformMapObserver( UniformMap::Observer& observer );
 
+  /**
+   * Query whether playing an animation is possible or not.
+   * @return true if playing an animation is possible.
+   */
+  virtual bool IsAnimationPossible() const
+  {
+    return true;
+  }
 
 protected:
 
@@ -244,6 +252,7 @@ protected:
   OwnedPropertyContainer mCustomProperties; ///< Properties provided with InstallCustomProperty()
   UniformMap mUniformMaps; ///< Container of owned uniform maps
   bool mUpdated;
+  bool                   mIsConnectedToSceneGraph;
 
 private:
   using ObserverContainer = Dali::Vector<PropertyOwner::Observer*>;
index 189d18c..ae6dd7f 100755 (executable)
@@ -188,6 +188,11 @@ void Node::RemoveUniformMapping( const std::string& uniformName )
   mRegenerateUniformMap = 2;
 }
 
+bool Node::IsAnimationPossible() const
+{
+  return mIsConnectedToSceneGraph;
+}
+
 void Node::PrepareRender( BufferIndex bufferIndex )
 {
   if( mRegenerateUniformMap != 0 )
index c89c245..7e5a05d 100644 (file)
@@ -806,6 +806,11 @@ public:
   void RemoveUniformMapping( const std::string& uniformName ) override;
 
   /**
+   * @copydoc Dali::Internal::SceneGraph::PropertyOwner::IsAnimationPossible
+   */
+  bool IsAnimationPossible() const override;
+
+  /**
    * Prepare the node for rendering.
    * This is called by the UpdateManager when an object is due to be rendered in the current frame.
    * @param[in] updateBufferIndex The current update buffer index.