Allow to send ResourceReady signal unlimited 16/298716/5
authorEunki Hong <eunkiki.hong@samsung.com>
Tue, 12 Sep 2023 23:57:23 +0000 (08:57 +0900)
committerEunki Hong <eunkiki.hong@samsung.com>
Tue, 19 Sep 2023 04:10:25 +0000 (04:10 +0000)
Previously we miss callback when ResourceReady called continusouly.
Let we use IdleCallbackManager system with return value, so we can
re-install Idle callback.

Change-Id: I56d73545ae7d8a122c8bead396affd4e962f7bb8
Signed-off-by: Eunki Hong <eunkiki.hong@samsung.com>
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-adaptor-impl.h
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-adaptor.cpp
automated-tests/src/dali-toolkit/utc-Dali-ImageView.cpp
dali-toolkit/internal/controls/control/control-data-impl.cpp
dali-toolkit/internal/controls/control/control-data-impl.h

index 4970dc4..126a67a 100644 (file)
@@ -99,6 +99,7 @@ public:
 private:
 
   Vector<CallbackBase*> mCallbacks;
+  Vector<CallbackBase*> mReturnCallbacks;
   std::vector<Internal::Adaptor::SceneHolder*> mWindows;
   Dali::Adaptor::AdaptorSignalType mResizedSignal;
   Dali::Adaptor::AdaptorSignalType mLanguageChangedSignal;
index ca52b18..7c887f8 100644 (file)
@@ -79,23 +79,42 @@ Integration::Scene Adaptor::GetScene(Dali::Window window)
 
 bool Adaptor::AddIdle(CallbackBase* callback, bool hasReturnValue)
 {
-  mCallbacks.PushBack(callback);
+  if(hasReturnValue)
+  {
+    mReturnCallbacks.PushBack(callback);
+  }
+  else
+  {
+    mCallbacks.PushBack(callback);
+  }
   return true;
 }
 
 void Adaptor::RemoveIdle(CallbackBase* callback)
 {
   mCallbacks.Erase(std::find_if(mCallbacks.Begin(), mCallbacks.End(), [&callback](CallbackBase* current) { return callback == current; }));
+  mReturnCallbacks.Erase(std::find_if(mReturnCallbacks.Begin(), mReturnCallbacks.End(), [&callback](CallbackBase* current) { return callback == current; }));
 }
 
 void Adaptor::RunIdles()
 {
+  Dali::Vector<CallbackBase*> reusedCallbacks;
+  for(auto& callback : mReturnCallbacks)
+  {
+    bool retValue = CallbackBase::ExecuteReturn<bool>(*callback);
+    if(retValue)
+    {
+      reusedCallbacks.PushBack(callback);
+    }
+  }
   for(auto& callback : mCallbacks)
   {
     CallbackBase::Execute(*callback);
   }
 
   mCallbacks.Clear();
+  mReturnCallbacks.Clear();
+  mReturnCallbacks.Swap(reusedCallbacks);
 }
 
 Dali::RenderSurfaceInterface& Adaptor::GetSurface()
index fe523a6..a162965 100644 (file)
@@ -3774,6 +3774,20 @@ void OnResourceReadySignal09(Control control)
     gImageView2.Reset();
   }
 }
+constexpr int gResourceReadySignal10MaxCounter = 5;
+
+void OnResourceReadySignal10(Control control)
+{
+  gResourceReadySignalCounter++;
+
+  tet_printf("OnResourceReadySignal10 comes!\n");
+  if(gResourceReadySignalCounter < gResourceReadySignal10MaxCounter)
+  {
+    tet_printf("OnResourceReadySignal10 Set image\n");
+    gImageView1.SetProperty(Toolkit::ImageView::Property::IMAGE, gImage_34_RGBA);
+    tet_printf("OnResourceReadySignal10 Set image done\n");
+  }
+}
 
 } // namespace
 
@@ -4544,6 +4558,81 @@ int UtcDaliImageViewSetImageOnResourceReadySignal09(void)
   END_TEST;
 }
 
+int UtcDaliImageViewSetImageOnResourceReadySignal10(void)
+{
+  tet_infoline("Test ResourceReady signal comes more than 2 times.");
+
+  ToolkitTestApplication application;
+
+  gResourceReadySignalCounter = 0;
+
+  // Clear image view for clear test
+
+  if(gImageView1)
+  {
+    gImageView1.Reset();
+  }
+
+  // Dummy view to cache image.
+  ImageView dummyView = ImageView::New(gImage_34_RGBA);
+  application.GetScene().Add(dummyView);
+
+  application.SendNotification();
+  application.Render();
+  DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1), true, TEST_LOCATION);
+  application.SendNotification();
+  application.Render();
+
+  try
+  {
+    gImageView1 = ImageView::New();
+    gImageView1.SetProperty(Toolkit::ImageView::Property::IMAGE, gImage_34_RGBA);
+    gImageView1.ResourceReadySignal().Connect(&OnResourceReadySignal10);
+    application.GetScene().Add(gImageView1); // It will call resourceReady signal 1 time.
+
+    tet_printf("ResourceReady called %d times\n", gResourceReadySignalCounter);
+
+    DALI_TEST_GREATER(gResourceReadySignal10MaxCounter, gResourceReadySignalCounter, TEST_LOCATION); // Check whether resource ready call too much.
+
+    for(int i = 0; i < gResourceReadySignal10MaxCounter; ++i)
+    {
+      tet_printf("RunIdles\n");
+      // Executes the idle callbacks.
+      application.RunIdles();
+      application.SendNotification();
+      application.Render();
+      tet_printf("RunIdles done\n");
+    }
+    tet_printf("ResourceReady called %d times\n", gResourceReadySignalCounter);
+
+    DALI_TEST_EQUALS(gResourceReadySignalCounter, gResourceReadySignal10MaxCounter, TEST_LOCATION);
+
+    DALI_TEST_CHECK(true);
+  }
+  catch(...)
+  {
+    // Exception should not happened
+    DALI_TEST_CHECK(false);
+  }
+
+  // Clear cache.
+  application.SendNotification();
+  application.Render();
+
+  gResourceReadySignalCounter = 0;
+
+  gResourceReadySignalCounter = 0;
+
+  // Clear image view for clear test
+
+  if(gImageView1)
+  {
+    gImageView1.Reset();
+  }
+
+  END_TEST;
+}
+
 int UtcDaliImageViewUseSameUrlWithAnimatedImageVisual(void)
 {
   tet_infoline("Test multiple views with same image in animated image visual");
index 0a19706..b8c811f 100644 (file)
@@ -556,7 +556,7 @@ Control::Impl::Impl(Control& controlImpl)
   mIsKeyboardNavigationSupported(false),
   mIsKeyboardFocusGroup(false),
   mIsEmittingResourceReadySignal(false),
-  mNeedToEmitResourceReady(false),
+  mIdleCallbackRegistered(false),
   mDispatchKeyEvents(true)
 {
   Dali::Accessibility::Accessible::RegisterExternalAccessibleGetter(&ExternalAccessibleGetter);
@@ -964,8 +964,6 @@ void Control::Impl::ResourceReady()
   // Emit signal if all enabled visuals registered by the control are ready or there are no visuals.
   if(IsResourceReady())
   {
-    // Reset the flag
-    mNeedToEmitResourceReady = false;
     EmitResourceReadySignal();
   }
 }
@@ -2132,48 +2130,51 @@ void Control::Impl::EmitResourceReadySignal()
     mIsEmittingResourceReadySignal = true;
 
     // If the signal handler changes visual, it may become ready during this call & therefore this method will
-    // get called again recursively. If so, mNeedToEmitResourceReady is set below, and we act on it after that secondary
+    // get called again recursively. If so, mIdleCallbackRegistered is set below, and we act on it after that secondary
     // invocation has completed by notifying in an Idle callback to prevent further recursion.
     Dali::Toolkit::Control handle(mControlImpl.GetOwner());
     mResourceReadySignal.Emit(handle);
 
-    if(mNeedToEmitResourceReady)
+    mIsEmittingResourceReadySignal = false;
+  }
+  else
+  {
+    if(!mIdleCallbackRegistered)
     {
+      mIdleCallbackRegistered = true;
+
       // Add idler to emit the signal again
       if(!mIdleCallback)
       {
         // The callback manager takes the ownership of the callback object.
         mIdleCallback = MakeCallback(this, &Control::Impl::OnIdleCallback);
-        Adaptor::Get().AddIdle(mIdleCallback, false);
+        Adaptor::Get().AddIdle(mIdleCallback, true);
       }
     }
-
-    mIsEmittingResourceReadySignal = false;
-  }
-  else
-  {
-    mNeedToEmitResourceReady = true;
   }
 }
 
-void Control::Impl::OnIdleCallback()
+bool Control::Impl::OnIdleCallback()
 {
-  if(mNeedToEmitResourceReady)
+  // Reset the flag
+  mIdleCallbackRegistered = false;
+
+  // A visual is ready so control may need relayouting if staged
+  if(mControlImpl.Self().GetProperty<bool>(Actor::Property::CONNECTED_TO_SCENE))
   {
-    // Reset the flag
-    mNeedToEmitResourceReady = false;
+    mControlImpl.RelayoutRequest();
+  }
 
-    // A visual is ready so control may need relayouting if staged
-    if(mControlImpl.Self().GetProperty<bool>(Actor::Property::CONNECTED_TO_SCENE))
-    {
-      mControlImpl.RelayoutRequest();
-    }
+  EmitResourceReadySignal();
 
-    EmitResourceReadySignal();
+  if(!mIdleCallbackRegistered)
+  {
+    // Set the pointer to null as the callback manager deletes the callback after execute it.
+    mIdleCallback = nullptr;
   }
 
-  // Set the pointer to null as the callback manager deletes the callback after execute it.
-  mIdleCallback = nullptr;
+  // Repeat idle if mIdleCallbackRegistered become true one more time.
+  return mIdleCallbackRegistered;
 }
 
 Toolkit::DevelControl::ControlAccessible* Control::Impl::GetAccessibleObject()
index 3a42718..bd7378f 100644 (file)
@@ -500,8 +500,10 @@ private:
 
   /**
    * @brief Callbacks called on idle.
+   *
+   * @return True if we need to call this idle callback one more time.
    */
-  void OnIdleCallback();
+  bool OnIdleCallback();
 
   /**
    * @brief Checks highlighted object geometry if it is showing or not
@@ -584,7 +586,7 @@ public:
   bool             mIsKeyboardNavigationSupported : 1;    ///< Stores whether keyboard navigation is supported by the control.
   bool             mIsKeyboardFocusGroup : 1;             ///< Stores whether the control is a focus group.
   bool             mIsEmittingResourceReadySignal : 1;    ///< True during ResourceReady().
-  bool             mNeedToEmitResourceReady : 1;          ///< True if need to emit the resource ready signal again.
+  bool             mIdleCallbackRegistered : 1;           ///< True if need to emit the resource ready signal again.
   bool             mDispatchKeyEvents : 1;                ///< Whether the actor emits key event signals
 
   RegisteredVisualContainer mRemoveVisuals; ///< List of visuals that are being replaced by another visual once ready