Add UI thread feature on Tizen 09/274609/21
authorDaekwang Ryu <dkdk.ryu@samsung.com>
Wed, 6 Jul 2022 06:51:22 +0000 (15:51 +0900)
committerDaekwang Ryu <dkdk.ryu@samsung.com>
Wed, 6 Jul 2022 06:51:22 +0000 (15:51 +0900)
The UiThread means that the application creates a thread for the UI events.
So the Dali::Adaptor is created on the UiThread, not the main thread.
When you enable UiThread,
the signals (Init, Terminate, Pause, Resume, Reset, AppControl, LanguageChanged, RegionChanged, LowBattery, LowMemory)
are emitted on the UiThread.
If you want to get the events on the main thread, you must connect the task signals(TaskInit, TaskTerminate, etc.).
When you don't enable the UiThread, the task signals aren't emitted.

Change-Id: I2cc57e85fa50f9b854531efa6048796aadbe6da9

18 files changed:
dali/devel-api/adaptor-framework/application-devel.cpp
dali/internal/adaptor/android/framework-android.cpp
dali/internal/adaptor/androidjni/framework-androidjni.cpp
dali/internal/adaptor/common/application-impl.cpp
dali/internal/adaptor/common/application-impl.h
dali/internal/adaptor/common/framework.h
dali/internal/adaptor/macos/framework-mac.mm
dali/internal/adaptor/tizen-wayland/component-application-impl.cpp
dali/internal/adaptor/tizen-wayland/framework-tizen.cpp
dali/internal/adaptor/tizen-wayland/tizen-wearable/watch-application-impl.cpp
dali/internal/adaptor/ubuntu/framework-ubuntu.cpp
dali/internal/adaptor/windows/framework-win.cpp
dali/internal/system/common/environment-variables.h
dali/internal/system/common/widget-application-impl.cpp
dali/internal/window-system/tizen-wayland/ecore-wl/window-base-ecore-wl.cpp
dali/internal/window-system/tizen-wayland/ecore-wl2/window-base-ecore-wl2.cpp
dali/public-api/adaptor-framework/application.cpp
dali/public-api/adaptor-framework/application.h

index 533a68c..8ce55e2 100644 (file)
@@ -48,7 +48,7 @@ Application New(int* argc, char** argv[], const std::string& stylesheet, Applica
     internal->StoreWindowPositionSize(positionSize);
   } else
   {
-    internal = Internal::Adaptor::Application::New(argc, argv, stylesheet, windowMode, positionSize, Internal::Adaptor::Framework::NORMAL, type);
+    internal = Internal::Adaptor::Application::New(argc, argv, stylesheet, windowMode, positionSize, Internal::Adaptor::Framework::NORMAL, type, false);
   }
   return Application(internal.Get());
 }
index e01ff71..8151ba8 100644 (file)
@@ -488,8 +488,9 @@ struct Framework::Impl
   }
 };
 
-Framework::Framework(Framework::Observer& observer, int* argc, char*** argv, Type type)
+Framework::Framework(Framework::Observer& observer, Framework::TaskObserver& taskObserver, int* argc, char*** argv, Type type, bool useUiThread)
 : mObserver(observer),
+  mTaskObserver(taskObserver),
   mInitialised(false),
   mPaused(false),
   mRunning(false),
index caa35be..649d281 100644 (file)
@@ -84,8 +84,9 @@ struct Framework::Impl
   std::string      mRegion;
 };
 
-Framework::Framework(Framework::Observer& observer, int* argc, char*** argv, Type type)
+Framework::Framework(Framework::Observer& observer, Framework::TaskObserver& taskObserver, int* argc, char*** argv, Type type, bool useUiThread)
 : mObserver(observer),
+  mTaskObserver(taskObserver),
   mInitialised(false),
   mPaused(false),
   mRunning(false),
index 97a23e0..13a3fbe 100644 (file)
@@ -26,6 +26,7 @@
 
 // INTERNAL INCLUDES
 #include <dali/devel-api/adaptor-framework/accessibility-bridge.h>
+#include <dali/devel-api/adaptor-framework/environment-variable.h>
 #include <dali/devel-api/adaptor-framework/style-monitor.h>
 #include <dali/devel-api/atspi-interfaces/accessible.h>
 #include <dali/devel-api/text-abstraction/font-client.h>
@@ -33,6 +34,7 @@
 #include <dali/internal/adaptor/common/framework.h>
 #include <dali/internal/adaptor/common/lifecycle-controller-impl.h>
 #include <dali/internal/system/common/command-line-options.h>
+#include <dali/internal/system/common/environment-variables.h>
 #include <dali/internal/window-system/common/render-surface-factory.h>
 #include <dali/internal/window-system/common/window-impl.h>
 #include <dali/internal/window-system/common/window-render-surface.h>
@@ -68,9 +70,10 @@ ApplicationPtr Application::New(
   Dali::Application::WINDOW_MODE windowMode,
   const PositionSize&            positionSize,
   Framework::Type                applicationType,
-  WindowType                     type)
+  WindowType                     type,
+  bool                           useUiThread)
 {
-  ApplicationPtr application(new Application(argc, argv, stylesheet, windowMode, positionSize, applicationType, type));
+  ApplicationPtr application(new Application(argc, argv, stylesheet, windowMode, positionSize, applicationType, type, useUiThread));
   return application;
 }
 
@@ -80,13 +83,13 @@ void Application::PreInitialize(int* argc, char** argv[])
   {
     Dali::TextAbstraction::FontClientPreInitialize();
 
-    gPreInitializedApplication = new Application(argc, argv, "", Dali::Application::OPAQUE, PositionSize(), Framework::NORMAL, WindowType::NORMAL);
+    gPreInitializedApplication = new Application(argc, argv, "", Dali::Application::OPAQUE, PositionSize(), Framework::NORMAL, WindowType::NORMAL, false);
     gPreInitializedApplication->CreateWindow(); // Only create window
     gPreInitializedApplication->mLaunchpadState = Launchpad::PRE_INITIALIZED;
   }
 }
 
-Application::Application(int* argc, char** argv[], const std::string& stylesheet, Dali::Application::WINDOW_MODE windowMode, const PositionSize& positionSize, Framework::Type applicationType, WindowType type)
+Application::Application(int* argc, char** argv[], const std::string& stylesheet, Dali::Application::WINDOW_MODE windowMode, const PositionSize& positionSize, Framework::Type applicationType, WindowType type, bool useUiThread)
 : mInitSignal(),
   mTerminateSignal(),
   mPauseSignal(),
@@ -108,6 +111,7 @@ Application::Application(int* argc, char** argv[], const std::string& stylesheet
   mWindowPositionSize(positionSize),
   mLaunchpadState(Launchpad::NONE),
   mDefaultWindowType(type),
+  mUseUiThread(useUiThread),
   mSlotDelegate(this)
 {
   // Get mName from environment options
@@ -118,8 +122,14 @@ Application::Application(int* argc, char** argv[], const std::string& stylesheet
     mMainWindowName = (*argv)[0];
   }
 
+  const char* uiThreadEnabled = Dali::EnvironmentVariable::GetEnvironmentVariable(DALI_ENV_ENABLE_UI_THREAD);
+  if(uiThreadEnabled && std::atoi(uiThreadEnabled) != 0)
+  {
+    mUseUiThread = true;
+  }
+
   mCommandLineOptions = new CommandLineOptions(argc, argv);
-  mFramework          = new Framework(*this, argc, argv, applicationType);
+  mFramework          = new Framework(*this, *this, argc, argv, applicationType, mUseUiThread);
   mUseRemoteSurface   = (applicationType == Framework::WATCH);
 }
 
@@ -169,7 +179,7 @@ void Application::ChangePreInitializedWindowSize()
   }
   else if(screenWidth != mWindowPositionSize.width || screenHeight != mWindowPositionSize.height)
   {
-    //Some apps can receive screen size differently after launching by specifying size in manifest.
+    // Some apps can receive screen size differently after launching by specifying size in manifest.
     mWindowPositionSize.width  = screenWidth;
     mWindowPositionSize.height = screenHeight;
     mMainWindow.SetSize(Dali::Window::WindowSize(mWindowPositionSize.width, mWindowPositionSize.height));
@@ -397,6 +407,48 @@ void Application::OnSurfaceDestroyed(Any surface)
 {
 }
 
+void Application::OnTaskInit()
+{
+  Dali::Application application(this);
+  mTaskInitSignal.Emit(application);
+}
+
+void Application::OnTaskTerminate()
+{
+  Dali::Application application(this);
+  mTaskTerminateSignal.Emit(application);
+}
+
+void Application::OnTaskAppControl(void* data)
+{
+  Dali::Application application(this);
+  mTaskAppControlSignal.Emit(application, data);
+}
+
+void Application::OnTaskLanguageChanged()
+{
+  Dali::Application application(this);
+  mTaskLanguageChangedSignal.Emit(application);
+}
+
+void Application::OnTaskRegionChanged()
+{
+  Dali::Application application(this);
+  mTaskRegionChangedSignal.Emit(application);
+}
+
+void Application::OnTaskBatteryLow(Dali::DeviceStatus::Battery::Status status)
+{
+  Dali::Application application(this);
+  mTaskLowBatterySignal.Emit(status);
+}
+
+void Application::OnTaskMemoryLow(Dali::DeviceStatus::Memory::Status status)
+{
+  Dali::Application application(this);
+  mTaskLowMemorySignal.Emit(status);
+}
+
 bool Application::AddIdle(CallbackBase* callback, bool hasReturnValue)
 {
   return mAdaptor->AddIdle(callback, hasReturnValue);
index ed03bfa..7a1f603 100644 (file)
@@ -64,7 +64,7 @@ typedef IntrusivePtr<Application> ApplicationPtr;
 /**
  * Implementation of the Application class.
  */
-class Application : public BaseObject, public Framework::Observer
+class Application : public BaseObject, public Framework::Observer, public Framework::TaskObserver
 {
 public:
   typedef Dali::Application::LowBatterySignalType LowBatterySignalType;
@@ -82,8 +82,9 @@ public:
    * @param[in]  positionSize      A position and a size of the window
    * @param[in]  applicationType   A member of Dali::Framework::Type
    * @param[in]  type              It is window type for default window.
+   * @param[in]  useUiThread       True if the application would create a UI thread
    */
-  static ApplicationPtr New(int* argc, char** argv[], const std::string& stylesheet, WINDOW_MODE windowMode, const PositionSize& positionSize, Framework::Type applicationType, WindowType type);
+  static ApplicationPtr New(int* argc, char** argv[], const std::string& stylesheet, WINDOW_MODE windowMode, const PositionSize& positionSize, Framework::Type applicationType, WindowType type, bool useUiThread);
 
   /**
    * @copydoc Dali::DevelApplication::PreInitialize()
@@ -180,9 +181,9 @@ public: // From Framework::Observer
   void OnResume() override;
 
   /**
-  * Called when the framework received AppControlSignal.
-  * @param[in] The bundle data of AppControl event.
-  */
+   * Called when the framework received AppControlSignal.
+   * @param[in] The bundle data of AppControl event.
+   */
   void OnAppControl(void* data) override;
 
   /**
@@ -196,18 +197,18 @@ public: // From Framework::Observer
   void OnLanguageChanged() override;
 
   /**
-  * Called when the framework informs the application that the region of the device has changed.
-  */
+   * Called when the framework informs the application that the region of the device has changed.
+   */
   void OnRegionChanged() override;
 
   /**
-  * Called when the framework informs the application that the battery level of the device is low.
-  */
+   * Called when the framework informs the application that the battery level of the device is low.
+   */
   void OnBatteryLow(Dali::DeviceStatus::Battery::Status status) override;
 
   /**
-  * Called when the framework informs the application that the memory level of the device is low.
-  */
+   * Called when the framework informs the application that the memory level of the device is low.
+   */
   void OnMemoryLow(Dali::DeviceStatus::Memory::Status status) override;
 
   /**
@@ -220,6 +221,43 @@ public: // From Framework::Observer
    */
   void OnSurfaceDestroyed(Any newSurface) override;
 
+public: // From Framework::TaskObserver
+  /**
+   * Called when the framework is initialised.
+   */
+  void OnTaskInit() override;
+
+  /**
+   * Called when the framework is terminated.
+   */
+  void OnTaskTerminate() override;
+
+  /**
+   * Called when the framework received AppControlSignal.
+   * @param[in] The bundle data of AppControl event.
+   */
+  void OnTaskAppControl(void* data) override;
+
+  /**
+   * Called when the framework informs the application that the language of the device has changed.
+   */
+  void OnTaskLanguageChanged() override;
+
+  /**
+   * Called when the framework informs the application that the region of the device has changed.
+   */
+  void OnTaskRegionChanged() override;
+
+  /**
+   * Called when the framework informs the application that the battery level of the device is low.
+   */
+  void OnTaskBatteryLow(Dali::DeviceStatus::Battery::Status status) override;
+
+  /**
+   * Called when the framework informs the application that the memory level of the device is low.
+   */
+  void OnTaskMemoryLow(Dali::DeviceStatus::Memory::Status status) override;
+
 public:
   /**
    * Sets a user defined theme file.
@@ -285,8 +323,8 @@ public: // Signals
   }
 
   /**
-  * @copydoc Dali::Application::AppControlSignal()
-  */
+   * @copydoc Dali::Application::AppControlSignal()
+   */
   Dali::Application::AppControlSignalType& AppControlSignal()
   {
     return mAppControlSignal;
@@ -301,29 +339,85 @@ public: // Signals
   }
 
   /**
-  * @copydoc Dali::Application::RegionChangedSignal()
-  */
+   * @copydoc Dali::Application::RegionChangedSignal()
+   */
   Dali::Application::AppSignalType& RegionChangedSignal()
   {
     return mRegionChangedSignal;
   }
 
   /**
-  * @copydoc Dali::Application::LowBatterySignal()
-  */
+   * @copydoc Dali::Application::LowBatterySignal()
+   */
   Dali::Application::LowBatterySignalType& LowBatterySignal()
   {
     return mLowBatterySignal;
   }
 
   /**
-  * @copydoc Dali::Application:::LowMemorySignal()
-  */
+   * @copydoc Dali::Application:::LowMemorySignal()
+   */
   Dali::Application::LowMemorySignalType& LowMemorySignal()
   {
     return mLowMemorySignal;
   }
 
+  /**
+   * @copydoc Dali::Application::TaskInitSignal()
+   */
+  Dali::Application::AppSignalType& TaskInitSignal()
+  {
+    return mTaskInitSignal;
+  }
+
+  /**
+   * @copydoc Dali::Application::TaskTerminateSignal()
+   */
+  Dali::Application::AppSignalType& TaskTerminateSignal()
+  {
+    return mTaskTerminateSignal;
+  }
+
+  /**
+   * @copydoc Dali::Application::TaskAppControlSignal()
+   */
+  Dali::Application::AppControlSignalType& TaskAppControlSignal()
+  {
+    return mTaskAppControlSignal;
+  }
+
+  /**
+   * @copydoc Dali::Application::TaskLanguageChangedSignal()
+   */
+  Dali::Application::AppSignalType& TaskLanguageChangedSignal()
+  {
+    return mTaskLanguageChangedSignal;
+  }
+
+  /**
+   * @copydoc Dali::Application::TaskRegionChangedSignal()
+   */
+  Dali::Application::AppSignalType& TaskRegionChangedSignal()
+  {
+    return mTaskRegionChangedSignal;
+  }
+
+  /**
+   * @copydoc Dali::Application::TaskLowBatterySignal()
+   */
+  Dali::Application::LowBatterySignalType& TaskLowBatterySignal()
+  {
+    return mTaskLowBatterySignal;
+  }
+
+  /**
+   * @copydoc Dali::Application::TaskLowMemorySignal()
+   */
+  Dali::Application::LowMemorySignalType& TaskLowMemorySignal()
+  {
+    return mTaskLowMemorySignal;
+  }
+
 protected:
   /**
    * Private Constructor
@@ -334,8 +428,9 @@ protected:
    * @param[in]  positionSize       A position and a size of the window
    * @param[in]  applicationType    A member of Dali::Framework::Type
    * @param[in]  type               The default window's type.
+   * @param[in]  useUiThread         True if the application would create UI thread
    */
-  Application(int* argc, char** argv[], const std::string& stylesheet, WINDOW_MODE windowMode, const PositionSize& positionSize, Framework::Type applicationType, WindowType type);
+  Application(int* argc, char** argv[], const std::string& stylesheet, WINDOW_MODE windowMode, const PositionSize& positionSize, Framework::Type applicationType, WindowType type, bool useUiThread);
 
   /**
    * Destructor
@@ -383,6 +478,14 @@ private:
   LowBatterySignalType mLowBatterySignal;
   LowMemorySignalType  mLowMemorySignal;
 
+  AppSignalType        mTaskInitSignal;
+  AppSignalType        mTaskTerminateSignal;
+  AppControlSignalType mTaskAppControlSignal;
+  AppSignalType        mTaskLanguageChangedSignal;
+  AppSignalType        mTaskRegionChangedSignal;
+  LowBatterySignalType mTaskLowBatterySignal;
+  LowMemorySignalType  mTaskLowMemorySignal;
+
   EventLoop* mEventLoop;
   Framework* mFramework;
 
@@ -403,6 +506,7 @@ private:
   Launchpad::State   mLaunchpadState;
   bool               mUseRemoteSurface;
   WindowType         mDefaultWindowType; ///< Default window's type. It is used when Application is created.
+  bool               mUseUiThread;
 
   SlotDelegate<Application> mSlotDelegate;
 
index 5ab74ac..bef6b77 100644 (file)
@@ -59,6 +59,8 @@ public:
 
   /**
    * Observer class for the framework.
+   * @brief When the UI thread is enabled, the events are emitted on the UI thread.
+   * When it is disabled, the events are emitted on the main thread.
    */
   class Observer
   {
@@ -99,9 +101,9 @@ public:
     }
 
     /**
-    * Invoked when the AppControl message is received.
-    * @param[in] The bundle data of AppControl message.
-    */
+     * Invoked when the AppControl message is received.
+     * @param[in] The bundle data of AppControl message.
+     */
     virtual void OnAppControl(void*)
     {
     }
@@ -182,15 +184,75 @@ public:
 #endif
   };
 
+  /**
+   * TaskObserver class for the framework.
+   * @brief This is used only when UiThread is enabled. the events are emitted on the main thread.
+   */
+  class TaskObserver
+  {
+  public:
+    /**
+     * Invoked when the application is to be initialised.
+     */
+    virtual void OnTaskInit()
+    {
+    }
+
+    /**
+     * Invoked when the application is to be terminated.
+     */
+    virtual void OnTaskTerminate()
+    {
+    }
+
+    /**
+     * Invoked when the AppControl message is received.
+     * @param[in] The bundle data of AppControl message.
+     */
+    virtual void OnTaskAppControl(void*)
+    {
+    }
+
+    /**
+     * Invoked when the language of the device is changed.
+     */
+    virtual void OnTaskLanguageChanged()
+    {
+    }
+
+    /**
+     * Invoked when the region is changed.
+     */
+    virtual void OnTaskRegionChanged()
+    {
+    }
+
+    /**
+     * Invoked when the battery level of the device is low.
+     */
+    virtual void OnTaskBatteryLow(Dali::DeviceStatus::Battery::Status status)
+    {
+    }
+
+    /**
+     * Invoked when the memory level of the device is low.
+     */
+    virtual void OnTaskMemoryLow(Dali::DeviceStatus::Memory::Status status)
+    {
+    }
+  };
+
 public:
   /**
    * Constructor
-   * @param[in]  observer  The observer of the Framework.
-   * @param[in]  argc      A pointer to the number of arguments.
-   * @param[in]  argv      A pointer the the argument list.
-   * @param[in]  type      The type of application
+   * @param[in]  observer      The observer of the Framework.
+   * @param[in]  taskObserver  The task observer of the Framework.
+   * @param[in]  argc          A pointer to the number of arguments.
+   * @param[in]  argv          A pointer the the argument list.
+   * @param[in]  type          The type of application
+   * @param[in]  useUiThread   True if the application would create a UI thread
    */
-  Framework(Observer& observer, int* argc, char*** argv, Type type = NORMAL);
+  Framework(Observer& observer, TaskObserver& taskObserver, int* argc, char*** argv, Type type, bool useUiThread);
 
   /**
    * Destructor
@@ -328,15 +390,16 @@ private:
   void InitThreads();
 
 private:
-  Observer&    mObserver;
-  bool         mInitialised;
-  bool         mPaused;
-  bool         mRunning;
-  int*         mArgc;
-  char***      mArgv;
-  std::string  mBundleName;
-  std::string  mBundleId;
-  AbortHandler mAbortHandler;
+  Observer&     mObserver;
+  TaskObserver& mTaskObserver;
+  bool          mInitialised;
+  bool          mPaused;
+  bool          mRunning;
+  int*          mArgc;
+  char***       mArgv;
+  std::string   mBundleName;
+  std::string   mBundleId;
+  AbortHandler  mAbortHandler;
 
 private: // impl members
   struct Impl;
index 4bd637c..b9c1439 100644 (file)
@@ -112,8 +112,9 @@ private:
   std::string mRegion;
 };
 
-Framework::Framework( Framework::Observer& observer, int *argc, char ***argv, Type type )
+Framework::Framework(Framework::Observer& observer, Framework::TaskObserver& taskObserver, int* argc, char*** argv, Type type, bool useUiThread)
 : mObserver(observer),
+  mTaskObserver(taskObserver),
   mInitialised(false),
   mPaused(false),
   mRunning(false),
index ceec60a..09f3aa4 100644 (file)
@@ -35,7 +35,7 @@ ComponentApplicationPtr ComponentApplication::New(
 }
 
 ComponentApplication::ComponentApplication(int* argc, char** argv[], const std::string& stylesheet, Dali::Application::WINDOW_MODE windowMode)
-: Application(argc, argv, stylesheet, windowMode, PositionSize(), Framework::COMPONENT, WindowType::NORMAL)
+: Application(argc, argv, stylesheet, windowMode, PositionSize(), Framework::COMPONENT, WindowType::NORMAL, false)
 {
 }
 
index 7db93c7..3f638d8 100644 (file)
 #include <app_control_internal.h>
 #include <bundle.h>
 #include <bundle_internal.h>
+#include <dlog.h>
+#include <glib.h>
 #include <system_info.h>
 #include <system_settings.h>
 #include <widget_base.h>
 #include <app_core_ui_base.hh>
 #include <app_event_internal.hh>
+
 // CONDITIONAL INCLUDES
 #ifdef APPCORE_WATCH_AVAILABLE
 #include <appcore-watch/watch_app.h>
@@ -219,33 +222,230 @@ struct Framework::Impl
   class UiAppContext : public AppCoreUiBase
   {
   public:
+    class Task : public AppCoreTaskBase
+    {
+    public:
+      explicit Task(Framework* framework)
+      : mFramework(framework),
+        mNewBatteryStatus(Dali::DeviceStatus::Battery::Status::NORMAL),
+        mNewMemoryStatus(Dali::DeviceStatus::Memory::NORMAL)
+      {
+      }
+
+      virtual ~Task()
+      {
+      }
+
+      int OnCreate() override
+      {
+        // On the main thread, the log functions are not set. So print_log() is used directly.
+        print_log(DLOG_INFO, "DALI", "%s: %s(%d) > OnCreate() emitted", __MODULE__, __func__, __LINE__);
+        mFramework->mTaskObserver.OnTaskInit();
+        return AppCoreTaskBase::OnCreate();
+      }
+
+      int OnTerminate() override
+      {
+        print_log(DLOG_INFO, "DALI", "%s: %s(%d) > OnTerminate() emitted", __MODULE__, __func__, __LINE__);
+        mFramework->mTaskObserver.OnTaskTerminate();
+        return AppCoreTaskBase::OnTerminate();
+      }
+
+      int OnControl(tizen_base::Bundle b) override
+      {
+        print_log(DLOG_INFO, "DALI", "%s: %s(%d) > OnControl() emitted", __MODULE__, __func__, __LINE__);
+        AppCoreTaskBase::OnControl(b);
+
+        app_control_h appControl = nullptr;
+
+        auto* bundleData = b.GetHandle();
+        if(bundleData)
+        {
+          if(app_control_create_event(bundleData, &appControl) != TIZEN_ERROR_NONE)
+          {
+            print_log(DLOG_ERROR, "DALI", "%s: %s(%d) > Failed to create an app_control handle with Bundle", __MODULE__, __func__, __LINE__);
+          }
+        }
+        else
+        {
+          if(app_control_create(&appControl) != TIZEN_ERROR_NONE)
+          {
+            print_log(DLOG_ERROR, "DALI", "%s: %s(%d) > Failed to create an app_control handle", __MODULE__, __func__, __LINE__);
+          }
+        }
+        mFramework->mTaskObserver.OnTaskAppControl(appControl);
+
+        app_control_destroy(appControl);
+        return 0;
+      }
+
+      void OnUiEvent(AppCoreTaskBase::UiState state) override
+      {
+        // This event is emitted when the UI thread is paused or resumed.
+        print_log(DLOG_INFO, "DALI", "%s: %s(%d) > OnUiEvent() emitted", __MODULE__, __func__, __LINE__);
+
+        // Note: This isn't implemented.
+        AppCoreTaskBase::OnUiEvent(state);
+      }
+
+      void OnLowMemory(AppCoreTaskBase::LowMemoryState state) override
+      {
+        print_log(DLOG_INFO, "DALI", "%s: %s(%d) > OnLowMemory() emitted", __MODULE__, __func__, __LINE__);
+
+        mNewMemoryStatus = AppCore::GetMemoryStatus(static_cast<app_event_low_memory_status_e>(state));
+
+        PostToUiThread(
+          [](gpointer userData) -> gboolean
+          {
+            auto* task      = static_cast<Task*>(userData);
+            auto* framework = static_cast<Framework*>(task->mFramework);
+            framework->mObserver.OnMemoryLow(task->mNewMemoryStatus);
+            return G_SOURCE_REMOVE;
+          });
+        mFramework->mTaskObserver.OnTaskMemoryLow(mNewMemoryStatus);
+        AppCoreTaskBase::OnLowMemory(state);
+      }
+
+      void OnLowBattery(AppCoreTaskBase::LowBatteryState state) override
+      {
+        print_log(DLOG_INFO, "DALI", "%s: %s(%d) > OnLowBattery() emitted", __MODULE__, __func__, __LINE__);
+        mNewBatteryStatus = AppCore::GetBatteryStatus(static_cast<app_event_low_battery_status_e>(state));
+
+        PostToUiThread(
+          [](gpointer userData) -> gboolean
+          {
+            auto* task      = static_cast<Task*>(userData);
+            auto* framework = static_cast<Framework*>(task->mFramework);
+            framework->mObserver.OnBatteryLow(task->mNewBatteryStatus);
+            return G_SOURCE_REMOVE;
+          });
+        mFramework->mTaskObserver.OnTaskBatteryLow(mNewBatteryStatus);
+        AppCoreTaskBase::OnLowBattery(state);
+      }
+
+      void OnLangChanged(const std::string& lang) override
+      {
+        print_log(DLOG_INFO, "DALI", "%s: %s(%d) > OnLangChanged() emitted", __MODULE__, __func__, __LINE__);
+        mNewLanguage = lang;
+        mFramework->SetLanguage(mNewLanguage);
+
+        PostToUiThread(
+          [](gpointer userData) -> gboolean
+          {
+            auto* task      = static_cast<Task*>(userData);
+            auto* framework = static_cast<Framework*>(task->mFramework);
+            framework->mObserver.OnLanguageChanged();
+            return G_SOURCE_REMOVE;
+          });
+
+        mFramework->mTaskObserver.OnTaskLanguageChanged();
+        AppCoreTaskBase::OnLangChanged(lang);
+      }
+
+      void OnRegionChanged(const std::string& region) override
+      {
+        print_log(DLOG_INFO, "DALI", "%s: %s(%d) > nRegionChanged() emitted", __MODULE__, __func__, __LINE__);
+        mNewRegion = region;
+        mFramework->SetRegion(mNewRegion);
+
+        PostToUiThread(
+          [](gpointer userData) -> gboolean
+          {
+            auto* task      = static_cast<Task*>(userData);
+            auto* framework = static_cast<Framework*>(task->mFramework);
+            framework->mObserver.OnRegionChanged();
+            return G_SOURCE_REMOVE;
+          });
+
+        mFramework->mTaskObserver.OnTaskRegionChanged();
+        AppCoreTaskBase::OnRegionChanged(mNewRegion);
+      }
+
+      void OnDeviceOrientationChanged(AppCoreTaskBase::DeviceOrientationState state) override
+      {
+        print_log(DLOG_INFO, "DALI", "%s: %s(%d) > OnDeviceOrientationChanged() emitted", __MODULE__, __func__, __LINE__);
+        // Note: This isn't emitted to the App.
+        AppCoreTaskBase::OnDeviceOrientationChanged(state);
+      }
+
+    private:
+      GMainContext* GetTizenGlibContext()
+      {
+        GMainContext* context;
+        const char*   env = getenv("TIZEN_GLIB_CONTEXT");
+        if(env)
+        {
+          context = (GMainContext*)strtoul(env, nullptr, 10);
+        }
+        else
+        {
+          context = nullptr;
+        }
+
+        return context;
+      }
+
+      void PostToUiThread(GSourceFunc func)
+      {
+        GSource* source = g_idle_source_new();
+        g_source_set_callback(source, func, this, nullptr);
+        g_source_attach(source, GetTizenGlibContext());
+        g_source_unref(source);
+      }
+
+    private:
+      Framework*                          mFramework;
+      std::string                         mNewLanguage;
+      std::string                         mNewRegion;
+      Dali::DeviceStatus::Battery::Status mNewBatteryStatus;
+      Dali::DeviceStatus::Memory::Status  mNewMemoryStatus;
+    };
+
     explicit UiAppContext(unsigned int hint, Framework* framework)
     : AppCoreUiBase(hint),
-      mFramework(framework)
+      mFramework(framework),
+      mUseUiThread(false)
     {
-      mLanguageChanged = std::make_shared<AppEvent>(IAppCore::IEvent::Type::LANG_CHANGE, OnLanguageChanged, this);
-      AddEvent(mLanguageChanged);
+      if(hint & AppCoreUiBase::HINT_DUAL_THREAD)
+      {
+        mUseUiThread = true;
+      }
+
+      if(!mUseUiThread)
+      {
+        mLanguageChanged = std::make_shared<AppEvent>(IAppCore::IEvent::Type::LANG_CHANGE, OnLanguageChanged, this);
+        AddEvent(mLanguageChanged);
 
-      mDeviceOrientationChanged = std::make_shared<AppEvent>(IAppCore::IEvent::Type::DEVICE_ORIENTATION_CHANGED, OnDeviceOrientationChanged, this);
-      AddEvent(mDeviceOrientationChanged);
+        mDeviceOrientationChanged = std::make_shared<AppEvent>(IAppCore::IEvent::Type::DEVICE_ORIENTATION_CHANGED, OnDeviceOrientationChanged, this);
+        AddEvent(mDeviceOrientationChanged);
 
-      mRegionFormatChanged = std::make_shared<AppEvent>(IAppCore::IEvent::Type::REGION_CHANGE, OnRegionFormatChanged, this);
-      AddEvent(mRegionFormatChanged);
+        mRegionFormatChanged = std::make_shared<AppEvent>(IAppCore::IEvent::Type::REGION_CHANGE, OnRegionFormatChanged, this);
+        AddEvent(mRegionFormatChanged);
 
-      mLowMemory = std::make_shared<AppEvent>(IAppCore::IEvent::Type::LOW_MEMORY, OnLowMemory, this);
-      AddEvent(mLowMemory);
+        mLowMemory = std::make_shared<AppEvent>(IAppCore::IEvent::Type::LOW_MEMORY, OnLowMemory, this);
+        AddEvent(mLowMemory);
 
-      mLowBattery = std::make_shared<AppEvent>(IAppCore::IEvent::Type::LOW_BATTERY, OnLowBattery, this);
-      AddEvent(mLowBattery);
+        mLowBattery = std::make_shared<AppEvent>(IAppCore::IEvent::Type::LOW_BATTERY, OnLowBattery, this);
+        AddEvent(mLowBattery);
+      }
     }
 
     virtual ~UiAppContext()
     {
-      RemoveEvent(mLowBattery);
-      RemoveEvent(mLowMemory);
-      RemoveEvent(mRegionFormatChanged);
-      RemoveEvent(mDeviceOrientationChanged);
-      RemoveEvent(mLanguageChanged);
+      if(!mUseUiThread)
+      {
+        RemoveEvent(mLowBattery);
+        RemoveEvent(mLowMemory);
+        RemoveEvent(mRegionFormatChanged);
+        RemoveEvent(mDeviceOrientationChanged);
+        RemoveEvent(mLanguageChanged);
+      }
+    }
+
+    std::unique_ptr<AppCoreTaskBase> CreateTask() override
+    {
+      return std::unique_ptr<AppCoreTaskBase>(
+        new Task(mFramework));
     }
 
     int OnCreate() override
@@ -451,12 +651,14 @@ struct Framework::Impl
     std::shared_ptr<AppEvent> mRegionFormatChanged;
     std::shared_ptr<AppEvent> mLowBattery;
     std::shared_ptr<AppEvent> mLowMemory;
+    bool                      mUseUiThread;
   };
 
   // Constructor
-  Impl(void* data, Type type)
+  Impl(void* data, Type type, bool useUiThread)
   : mAbortCallBack(NULL),
-    mCallbackManager(NULL)
+    mCallbackManager(NULL),
+    mUseUiThread(useUiThread)
 #ifdef APPCORE_WATCH_AVAILABLE
     ,
     mWatchCallback()
@@ -597,6 +799,7 @@ struct Framework::Impl
   Framework*                    mFramework;
   AppCore::AppEventHandlerPtr   handlers[5];
   std::unique_ptr<UiAppContext> mUiAppContext;
+  bool                          mUseUiThread;
 #ifdef APPCORE_WATCH_AVAILABLE
   watch_app_lifecycle_callback_s mWatchCallback;
   app_event_handler_h            watchHandlers[5];
@@ -767,6 +970,26 @@ struct Framework::Impl
                           AppCoreUiBase::HINT_HW_ACC_CONTROL |
                           AppCoreUiBase::HINT_WINDOW_AUTO_CONTROL;
 
+      // For testing UIThread model, This code turns on the UI Thread feature forcibly.
+      //  ex) app_launcher -e [APPID] __K_UI_THREAD enable
+      // This code doesn't change mUseUiThread in Internal::Application
+      bundle* b = bundle_import_from_argv(*mFramework->mArgc, *mFramework->mArgv);
+      if(b != nullptr)
+      {
+        const char* val = bundle_get_val(b, "__K_UI_THREAD");
+        if(val != nullptr && strcmp(val, "enable") == 0)
+        {
+          mUseUiThread = true;
+        }
+
+        bundle_free(b);
+      }
+
+      if(mUseUiThread)
+      {
+        hint |= AppCoreUiBase::HINT_DUAL_THREAD;
+      }
+
       mUiAppContext = std::make_unique<UiAppContext>(hint, mFramework);
     }
 
@@ -988,8 +1211,9 @@ private:
   Impl& operator=(const Impl& impl);
 };
 
-Framework::Framework(Framework::Observer& observer, int* argc, char*** argv, Type type)
+Framework::Framework(Framework::Observer& observer, Framework::TaskObserver& taskObserver, int* argc, char*** argv, Type type, bool useUiThread)
 : mObserver(observer),
+  mTaskObserver(taskObserver),
   mInitialised(false),
   mPaused(false),
   mRunning(false),
@@ -1010,7 +1234,7 @@ Framework::Framework(Framework::Observer& observer, int* argc, char*** argv, Typ
 
   InitThreads();
 
-  mImpl = new Impl(this, type);
+  mImpl = new Impl(this, type, useUiThread);
 }
 
 Framework::~Framework()
index 72cf282..7f7a7f1 100644 (file)
@@ -50,7 +50,7 @@ WatchApplicationPtr WatchApplication::New(
 }
 
 WatchApplication::WatchApplication(int* argc, char** argv[], const std::string& stylesheet, Dali::Application::WINDOW_MODE windowMode)
-: Application(argc, argv, stylesheet, windowMode, PositionSize(), Framework::WATCH, WindowType::NORMAL),
+: Application(argc, argv, stylesheet, windowMode, PositionSize(), Framework::WATCH, WindowType::NORMAL, false),
   mState(UNINITIALIZED)
 {
 }
index 38e3d76..60529c5 100644 (file)
@@ -134,8 +134,9 @@ struct Framework::Impl
   }
 };
 
-Framework::Framework(Framework::Observer& observer, int* argc, char*** argv, Type type)
+Framework::Framework(Framework::Observer& observer, Framework::TaskObserver& taskObserver, int* argc, char*** argv, Type type, bool useUiThread)
 : mObserver(observer),
+  mTaskObserver(taskObserver),
   mInitialised(false),
   mPaused(false),
   mRunning(false),
index 2a5ab92..0623baf 100644 (file)
@@ -184,8 +184,9 @@ private:
   std::string      mRegion;\r
 };\r
 \r
-Framework::Framework(Framework::Observer& observer, int* argc, char*** argv, Type type)\r
+Framework::Framework(Framework::Observer& observer, Framework::TaskObserver& taskObserver, int* argc, char*** argv, Type type, bool useUiThread)\r
 : mObserver(observer),\r
+  mTaskObserver(taskObserver),\r
   mInitialised(false),\r
   mPaused(false),\r
   mRunning(false),\r
index f4b661a..c262bd7 100644 (file)
@@ -144,6 +144,8 @@ namespace Adaptor
 
 #define DALI_ENV_SUPPRESS_SCREEN_READER "DALI_SUPPRESS_SCREEN_READER"
 
+#define DALI_ENV_ENABLE_UI_THREAD "DALI_ENABLE_UI_THREAD"
+
 } // namespace Adaptor
 
 } // namespace Internal
index 2b07db9..5c7aef6 100644 (file)
@@ -48,7 +48,7 @@ WidgetApplicationPtr WidgetApplication::New(
 }
 
 WidgetApplication::WidgetApplication(int* argc, char** argv[], const std::string& stylesheet)
-: Application(argc, argv, stylesheet, Dali::WidgetApplication::OPAQUE, PositionSize(), Framework::WIDGET, WindowType::NORMAL)
+: Application(argc, argv, stylesheet, Dali::WidgetApplication::OPAQUE, PositionSize(), Framework::WIDGET, WindowType::NORMAL, false)
 {
   DALI_LOG_ERROR("WidgetApplication is not implemented in UBUNTU profile.\n");
 }
index ccef811..f123f25 100644 (file)
@@ -655,8 +655,8 @@ void WindowBaseEcoreWl::Initialize(PositionSize positionSize, Any surface, bool
   mEcoreEventHandler.PushBack(ecore_event_handler_add(ECORE_WL_EVENT_SELECTION_DATA_READY, EcoreEventDataReceive, this));
 
   // Register Vconf notify - font name and size
-  vconf_notify_key_changed(DALI_VCONFKEY_SETAPPL_ACCESSIBILITY_FONT_NAME, VconfNotifyFontNameChanged, this);
-  vconf_notify_key_changed(VCONFKEY_SETAPPL_ACCESSIBILITY_FONT_SIZE, VconfNotifyFontSizeChanged, this);
+  vconf_notify_key_changed_for_ui_thread(DALI_VCONFKEY_SETAPPL_ACCESSIBILITY_FONT_NAME, VconfNotifyFontNameChanged, this);
+  vconf_notify_key_changed_for_ui_thread(VCONFKEY_SETAPPL_ACCESSIBILITY_FONT_SIZE, VconfNotifyFontSizeChanged, this);
 
   mDisplay = ecore_wl_display_get();
 
index 6c15aad..a77a163 100644 (file)
@@ -824,8 +824,8 @@ void WindowBaseEcoreWl2::Initialize(PositionSize positionSize, Any surface, bool
   mEcoreEventHandler.PushBack(ecore_event_handler_add(ECORE_WL2_EVENT_AUX_MESSAGE, EcoreEventWindowAuxiliaryMessage, this));
 
   // Register Vconf notify - font name and size
-  vconf_notify_key_changed(DALI_VCONFKEY_SETAPPL_ACCESSIBILITY_FONT_NAME, VconfNotifyFontNameChanged, this);
-  vconf_notify_key_changed(VCONFKEY_SETAPPL_ACCESSIBILITY_FONT_SIZE, VconfNotifyFontSizeChanged, this);
+  vconf_notify_key_changed_for_ui_thread(DALI_VCONFKEY_SETAPPL_ACCESSIBILITY_FONT_NAME, VconfNotifyFontNameChanged, this);
+  vconf_notify_key_changed_for_ui_thread(VCONFKEY_SETAPPL_ACCESSIBILITY_FONT_SIZE, VconfNotifyFontSizeChanged, this);
 
   Ecore_Wl2_Display* display = ecore_wl2_connected_display_get(NULL);
   mDisplay                   = ecore_wl2_display_get(display);
index 17403d2..20099eb 100644 (file)
@@ -46,7 +46,7 @@ Application Application::New(int* argc, char** argv[])
   }
   else
   {
-    internal = Internal::Adaptor::Application::New(argc, argv, "", OPAQUE, PositionSize(), Internal::Adaptor::Framework::NORMAL, WindowType::NORMAL);
+    internal = Internal::Adaptor::Application::New(argc, argv, "", OPAQUE, PositionSize(), Internal::Adaptor::Framework::NORMAL, WindowType::NORMAL, false);
   }
   return Application(internal.Get());
 }
@@ -66,7 +66,7 @@ Application Application::New(int* argc, char** argv[], const std::string& styles
   }
   else
   {
-    internal = Internal::Adaptor::Application::New(argc, argv, stylesheet, OPAQUE, PositionSize(), Internal::Adaptor::Framework::NORMAL, WindowType::NORMAL);
+    internal = Internal::Adaptor::Application::New(argc, argv, stylesheet, OPAQUE, PositionSize(), Internal::Adaptor::Framework::NORMAL, WindowType::NORMAL, false);
   }
   return Application(internal.Get());
 }
@@ -88,7 +88,7 @@ Application Application::New(int* argc, char** argv[], const std::string& styles
   }
   else
   {
-    internal = Internal::Adaptor::Application::New(argc, argv, stylesheet, windowMode, PositionSize(), Internal::Adaptor::Framework::NORMAL, WindowType::NORMAL);
+    internal = Internal::Adaptor::Application::New(argc, argv, stylesheet, windowMode, PositionSize(), Internal::Adaptor::Framework::NORMAL, WindowType::NORMAL, false);
   }
   return Application(internal.Get());
 }
@@ -113,7 +113,32 @@ Application Application::New(int* argc, char** argv[], const std::string& styles
   }
   else
   {
-    internal = Internal::Adaptor::Application::New(argc, argv, stylesheet, windowMode, positionSize, Internal::Adaptor::Framework::NORMAL, WindowType::NORMAL);
+    internal = Internal::Adaptor::Application::New(argc, argv, stylesheet, windowMode, positionSize, Internal::Adaptor::Framework::NORMAL, WindowType::NORMAL, false);
+  }
+  return Application(internal.Get());
+}
+
+Application Application::New(int* argc, char** argv[], const std::string& stylesheet, Application::WINDOW_MODE windowMode, PositionSize positionSize, bool useUiThread)
+{
+  Internal::Adaptor::ApplicationPtr internal = Internal::Adaptor::Application::GetPreInitializedApplication();
+  if(internal)
+  {
+    // pre-initialized application
+    internal->SetCommandLineOptions(argc, argv);
+    if(argc && (*argc > 0))
+    {
+      internal->GetWindow().SetClass((*argv)[0], "");
+    }
+    internal->SetStyleSheet(stylesheet);
+
+    internal->GetWindow().SetTransparency((windowMode == Application::OPAQUE ? false : true));
+
+    //Store only the value before adaptor is created
+    internal->StoreWindowPositionSize(positionSize);
+  }
+  else
+  {
+    internal = Internal::Adaptor::Application::New(argc, argv, stylesheet, windowMode, positionSize, Internal::Adaptor::Framework::NORMAL, WindowType::NORMAL, useUiThread);
   }
   return Application(internal.Get());
 }
@@ -229,6 +254,41 @@ Application::LowMemorySignalType& Application::LowMemorySignal()
   return Internal::Adaptor::GetImplementation(*this).LowMemorySignal();
 }
 
+Application::AppSignalType& Application::TaskInitSignal()
+{
+  return Internal::Adaptor::GetImplementation(*this).TaskInitSignal();
+}
+
+Application::AppSignalType& Application::TaskTerminateSignal()
+{
+  return Internal::Adaptor::GetImplementation(*this).TaskTerminateSignal();
+}
+
+Application::AppControlSignalType& Application::TaskAppControlSignal()
+{
+  return Internal::Adaptor::GetImplementation(*this).TaskAppControlSignal();
+}
+
+Application::AppSignalType& Application::TaskLanguageChangedSignal()
+{
+  return Internal::Adaptor::GetImplementation(*this).TaskLanguageChangedSignal();
+}
+
+Application::AppSignalType& Application::TaskRegionChangedSignal()
+{
+  return Internal::Adaptor::GetImplementation(*this).TaskRegionChangedSignal();
+}
+
+Application::LowBatterySignalType& Application::TaskLowBatterySignal()
+{
+  return Internal::Adaptor::GetImplementation(*this).TaskLowBatterySignal();
+}
+
+Application::LowMemorySignalType& Application::TaskLowMemorySignal()
+{
+  return Internal::Adaptor::GetImplementation(*this).TaskLowMemorySignal();
+}
+
 Application::Application(Internal::Adaptor::Application* application)
 : BaseHandle(application)
 {
index 90ed7b5..4861e71 100644 (file)
@@ -90,6 +90,22 @@ class Application;
  * app.ResumeSignal().Connect(&app, &MyApplication::Resume);
  * @endcode
  *
+ *
+ * #### UI thread
+ * There is the UI thread feature.
+ * UI thread is an additional thread that an Application object creates. The thread is for UI events.
+ *
+ * When the UI thread feature is enabled, you can use the task signals(TaskInit, TaskTerminate, TaskAppControl, TaskLanguageChanged, TaskLowBattery, and TaskLowMemory).
+ * The task signals are emitted on the main thread,
+ * and the normal signals(Init, Terminate, Pause, Resume, Reset, AppControl, LanguageChanged, Region, LowBattery, and LowMemory) are emitted on the UI thread.
+ *
+ * If you want to handle windows or actors in cases like when the memory level of the device is low, you have to use the normal signals, not the task signals.
+ * Callbacks of all signals in DALi except the task signals are emitted on the UI thread. (e.g., Timer callbacks are emitted on the UI thread.)
+ *
+ * To enable the UI Thread, you can use this method. you have to set True to the useUiThread.
+ * Dali::Application::New(int *argc, char **argv[], const std::string &stylesheet, Application::WINDOW_MODE windowMode, PositionSize positionSize, bool useUiThread)
+ *
+ *
  * This class accepts command line arguments as well. The following options are supported:
  *
  * @code
@@ -188,6 +204,25 @@ public:
   static Application New(int* argc, char** argv[], const std::string& stylesheet, Application::WINDOW_MODE windowMode, PositionSize positionSize);
 
   /**
+   * @brief This is the constructor for applications.
+   *
+   * @SINCE_2_1.20
+   * @PRIVLEVEL_PUBLIC
+   * @PRIVILEGE_DISPLAY
+   * @param[in,out]  argc         A pointer to the number of arguments
+   * @param[in,out]  argv         A pointer to the argument list
+   * @param[in]      stylesheet   The path to user defined theme file
+   * @param[in]      windowMode   A member of WINDOW_MODE
+   * @param[in]      positionSize A position and a size of the window
+   * @param[in]      useUiThread  True if the application would create a UI thread
+   * @return A handle to the Application
+   * @note If the stylesheet is not specified, then the library's default stylesheet will not be overridden.<BR>
+   * UI thread is an additional thread that DALi creates for UI events.
+   * The UI thread isn't blocked from the system events(AppControl, LanguageChanged, RegionChanged, LowMemory, LowBattery task signals).
+   */
+  static Application New(int* argc, char** argv[], const std::string& stylesheet, Application::WINDOW_MODE windowMode, PositionSize positionSize, bool useUiThread);
+
+  /**
    * @brief Constructs an empty handle.
    * @SINCE_1_0.0
    */
@@ -322,6 +357,8 @@ public: // Signals
   /**
    * @brief The user should connect to this signal to determine when they should initialize
    * their application.
+   * Only when the user uses the UiThread, this signal is emitted on the UI thread.
+   * Otherwise, it is emitted on the main thread.
    * @SINCE_1_0.0
    * @return The signal to connect to
    */
@@ -330,6 +367,8 @@ public: // Signals
   /**
    * @brief The user should connect to this signal to determine when they should terminate
    * their application.
+   * Only when the user uses the UiThread, this signal is emitted on the UI thread.
+   * Otherwise, it is emitted on the main thread.
    * @SINCE_1_0.0
    * @return The signal to connect to
    */
@@ -338,6 +377,8 @@ public: // Signals
   /**
    * @brief The user should connect to this signal if they need to perform any special
    * activities when the application is about to be paused.
+   * Only when the user uses the UiThread, this signal is emitted on the UI thread.
+   * Otherwise, it is emitted on the main thread.
    * @SINCE_1_0.0
    * @return The signal to connect to
    */
@@ -346,6 +387,8 @@ public: // Signals
   /**
    * @brief The user should connect to this signal if they need to perform any special
    * activities when the application has resumed.
+   * Only when the user uses the UiThread, this signal is emitted on the UI thread.
+   * Otherwise, it is emitted on the main thread.
    * @SINCE_1_0.0
    * @return The signal to connect to
    */
@@ -353,37 +396,47 @@ public: // Signals
 
   /**
    * @brief This signal is sent when the system requires the user to reinitialize itself.
+   * Only when the user uses the UiThread, this signal is emitted on the UI thread.
+   * Otherwise, it is emitted on the main thread.
    * @SINCE_1_0.0
    * @return The signal to connect to
    */
   AppSignalType& ResetSignal();
 
   /**
-  * @brief This signal is emitted when another application sends a launch request to the application.
-  *
-  * When the application is launched, this signal is emitted after the main loop of the application starts up.
-  * The passed parameter describes the launch request and contains the information about why the application is launched.
-  * @SINCE_1_0.0
-  * @return The signal to connect to
-  */
+   * @brief This signal is emitted when another application sends a launch request to the application.
+   *
+   * When the application is launched, this signal is emitted after the main loop of the application starts up.
+   * The passed parameter describes the launch request and contains the information about why the application is launched.
+   * Only when the user uses the UiThread, this signal is emitted on the UI thread.
+   * Otherwise, it is emitted on the main thread.
+   * @SINCE_1_0.0
+   * @return The signal to connect to
+   */
   AppControlSignalType& AppControlSignal();
 
   /**
    * @brief This signal is emitted when the language is changed on the device.
+   * Only when the user uses the UiThread, this signal is emitted on the UI thread.
+   * Otherwise, it is emitted on the main thread.
    * @SINCE_1_0.0
    * @return The signal to connect to
    */
   AppSignalType& LanguageChangedSignal();
 
   /**
-  * @brief This signal is emitted when the region of the device is changed.
-  * @SINCE_1_0.0
-  * @return The signal to connect to
-  */
+   * @brief This signal is emitted when the region of the device is changed.
+   * Only when the user uses the UiThread, this signal is emitted on the UI thread.
+   * Otherwise, it is emitted on the main thread.
+   * @SINCE_1_0.0
+   * @return The signal to connect to
+   */
   AppSignalType& RegionChangedSignal();
 
   /**
    * @brief This signal is emitted when the battery level of the device is low.
+   * Only when the user uses the UiThread, this signal is emitted on the UI thread.
+   * Otherwise, it is emitted on the main thread.
    * @SINCE_1_2.62
    * @return The signal to connect to
    */
@@ -391,11 +444,75 @@ public: // Signals
 
   /**
    * @brief This signal is emitted when the memory level of the device is low.
+   * Only when the user uses the UiThread, this signal is emitted on the UI thread.
+   * Otherwise, it is emitted on the main thread.
    * @SINCE_1_2.62
    * @return The signal to connect to
    */
   LowMemorySignalType& LowMemorySignal();
 
+  // TaskSignal
+  /**
+   * @brief The user should connect to this signal to determine when they should initialize
+   * their application.
+   * Only when the user uses the UiThread, this signal is emitted on the main thread.
+   * Otherwise, it is not emitted at all.
+   * @return The signal to connect to
+   */
+  AppSignalType& TaskInitSignal();
+
+  /**
+   * @brief The user should connect to this signal to determine when they should terminate
+   * their application.
+   * Only when the user uses the UiThread, this signal is emitted on the main thread.
+   * Otherwise, it is not emitted at all.
+   * @return The signal to connect to
+   */
+  AppSignalType& TaskTerminateSignal();
+
+  /**
+   * @brief This signal is emitted when another application sends a launch request to the application.
+   *
+   * When the application is launched, this signal is emitted after the main loop of the application starts up.
+   * The passed parameter describes the launch request and contains the information about why the application is launched.
+   * Only when the user uses the UiThread, this signal is emitted on the main thread.
+   * Otherwise, it is not emitted at all.
+   * @return The signal to connect to
+   */
+  AppControlSignalType& TaskAppControlSignal();
+
+  /**
+   * @brief This signal is emitted when the language is changed on the device.
+   * Only when the user uses the UiThread, this signal is emitted on the main thread.
+   * Otherwise, it is not emitted at all.
+   * @return The signal to connect to
+   */
+  AppSignalType& TaskLanguageChangedSignal();
+
+  /**
+   * @brief This signal is emitted when the region of the device is changed.
+   * Only when the user uses the UiThread, this signal is emitted on the main thread.
+   * Otherwise, it is not emitted at all.
+   * @return The signal to connect to
+   */
+  AppSignalType& TaskRegionChangedSignal();
+
+  /**
+   * @brief This signal is emitted when the battery level of the device is low.
+   * Only when the user uses the UiThread, this signal is emitted on the main thread.
+   * Otherwise, it is not emitted at all.
+   * @return The signal to connect to
+   */
+  LowBatterySignalType& TaskLowBatterySignal();
+
+  /**
+   * @brief This signal is emitted when the memory level of the device is low.
+   * Only when the user uses the UiThread, this signal is emitted on the main thread.
+   * Otherwise, it is not emitted at all.
+   * @return The signal to connect to
+   */
+  LowMemorySignalType&  TaskLowMemorySignal();
+
 public: // Not intended for application developers
   /// @cond internal
   /**