AddOn manager 18/226818/27
authoradam.b <adam.b@samsung.com>
Thu, 16 Jul 2020 11:57:24 +0000 (12:57 +0100)
committeradam.b <adam.b@samsung.com>
Fri, 24 Jul 2020 09:40:07 +0000 (10:40 +0100)
Change-Id: I50dc482ca0afd4b4a3a5eb2f2da2f218350727d2

26 files changed:
automated-tests/src/dali-adaptor-internal/CMakeLists.txt
automated-tests/src/dali-adaptor-internal/addons/test-sample-addon.cpp [new file with mode: 0644]
automated-tests/src/dali-adaptor-internal/utc-Dali-AddOns.cpp [new file with mode: 0644]
build/tizen/module-list.cmake
build/tizen/profiles/android-profile.cmake
build/tizen/profiles/common-profile.cmake
build/tizen/profiles/ivi-profile.cmake
build/tizen/profiles/mobile-profile.cmake
build/tizen/profiles/tv-profile.cmake
build/tizen/profiles/ubuntu-profile.cmake
build/tizen/profiles/wearable-profile.cmake
build/tizen/profiles/windows-profile.cmake
dali/internal/adaptor/common/adaptor-impl.cpp
dali/internal/adaptor/common/adaptor-impl.h
dali/internal/adaptor/file.list
dali/internal/addons/common/addon-manager-factory.h [new file with mode: 0644]
dali/internal/addons/common/addon-manager-impl.h [new file with mode: 0644]
dali/internal/addons/common/addon-manager.cpp [new file with mode: 0644]
dali/internal/addons/common/addon-manager.h [new file with mode: 0644]
dali/internal/addons/dummy/addon-manager-factory-dummy.cpp [new file with mode: 0644]
dali/internal/addons/file.list [new file with mode: 0644]
dali/internal/addons/linux/addon-manager-impl-linux.cpp [new file with mode: 0644]
dali/internal/addons/linux/addon-manager-impl-linux.h [new file with mode: 0644]
dali/internal/addons/tizen/addon-manager-factory-tizen.cpp [new file with mode: 0644]
dali/internal/addons/ubuntu/addon-manager-factory-ubuntu.cpp [new file with mode: 0644]
dali/internal/system/common/environment-variables.h

index 691d90c..cf0069c 100644 (file)
@@ -6,6 +6,7 @@ SET(RPM_NAME "core-${PKG_NAME}-tests")
 SET(CAPI_LIB "dali-adaptor-internal")
 
 SET(TC_SOURCES
+    utc-Dali-AddOns.cpp
     utc-Dali-CommandLineOptions.cpp
     utc-Dali-CompressedTextures.cpp
     utc-Dali-FontClient.cpp
@@ -18,6 +19,7 @@ SET(TC_SOURCES
     utc-Dali-TiltSensor.cpp
 )
 
+
 LIST(APPEND TC_SOURCES
     image-loaders.cpp
     ../dali-adaptor/dali-test-suite-utils/mesh-builder.cpp
@@ -47,6 +49,7 @@ ADD_COMPILE_OPTIONS( ${${CAPI_LIB}_CFLAGS_OTHER} )
 # But CMake's new auto-escape quote policy doesn't work right.
 CMAKE_POLICY(SET CMP0005 OLD)
 ADD_DEFINITIONS(-DTEST_IMAGE_DIR=\"\\\"${CMAKE_CURRENT_SOURCE_DIR}/../../images\\\"\" )
+ADD_DEFINITIONS(-DADDON_LIBS_PATH=\"\\\"${CMAKE_CURRENT_BINARY_DIR}\\\"\" )
 
 
 FOREACH(directory ${${CAPI_LIB}_LIBRARY_DIRS})
@@ -70,3 +73,18 @@ TARGET_LINK_LIBRARIES(${EXEC_NAME}
 INSTALL(PROGRAMS ${EXEC_NAME}
     DESTINATION ${BIN_DIR}/${EXEC_NAME}
 )
+
+# build addons
+MESSAGE( STATUS "BINDIR: ${CMAKE_CURRENT_BINARY_DIR}")
+SET(ADDON_NAME SampleAddOn )
+SET(ADDON_SOURCES addons/test-sample-addon.cpp )
+ADD_LIBRARY( ${ADDON_NAME} SHARED ${ADDON_SOURCES} )
+TARGET_LINK_LIBRARIES(${ADDON_NAME}
+        -lpthread -ldl --coverage
+        )
+
+INSTALL( TARGETS ${ADDON_NAME} DESTINATION ${BIN_DIR} )
+
+# store AddOn list
+FILE( WRITE ${CMAKE_CURRENT_BINARY_DIR}/addons.txt lib${ADDON_NAME}.so )
+
diff --git a/automated-tests/src/dali-adaptor-internal/addons/test-sample-addon.cpp b/automated-tests/src/dali-adaptor-internal/addons/test-sample-addon.cpp
new file mode 100644 (file)
index 0000000..ee736b9
--- /dev/null
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <cstring>
+#include <dali/devel-api/addons/addon-base.h>
+#include <dali-test-suite-utils.h>
+
+namespace
+{
+bool gIsPaused = false;
+}
+
+int StringLen( const char* str )
+{
+  return strlen( str );
+}
+
+int DoSum( int a, int b )
+{
+  return a+b;
+}
+
+bool GetLifecycleStatus()
+{
+  return gIsPaused;
+}
+
+struct AddOnDataInstance
+{
+  int GetValue()
+  {
+    return 42;
+  }
+
+  static int GetValueWithInstance( AddOnDataInstance* instance )
+  {
+    return instance->GetValue();
+  }
+};
+
+AddOnDataInstance* CreateInstance()
+{
+  return new AddOnDataInstance();
+}
+
+class TestDummyAddOn : public Dali::AddOns::AddOnBase
+{
+public:
+
+  void GetAddOnInfo( Dali::AddOnInfo& info ) override
+  {
+    info.type = Dali::AddOnType::GENERIC;
+    info.name = "SampleAddOn";
+    info.version = Dali::DALI_ADDON_VERSION( 1, 0, 0 );
+    info.next = nullptr;
+    tet_printf( "SampleAddOn: GetAddOnInfo() : name = %s\n", info.name.c_str());
+  }
+
+  /**
+   * Dispatch table for global functions
+   * @return
+   */
+  Dali::AddOns::DispatchTable* GetGlobalDispatchTable() override
+  {
+    static Dali::AddOns::DispatchTable dispatchTable{};
+    if( dispatchTable.Empty() )
+    {
+      dispatchTable["DoSum"]                     = DoSum;
+      dispatchTable["StringLen"]                 = StringLen;
+      dispatchTable["GetLifecycleStatus"]        = GetLifecycleStatus;
+      dispatchTable["CreateInstance"]            = CreateInstance;
+
+    }
+    return &dispatchTable;
+  }
+
+  /**
+   * Lifecycle
+   */
+  void OnStart() override
+  {
+    gIsPaused = false;
+  }
+
+  void OnStop() override
+  {
+    gIsPaused = true;
+  }
+
+  void OnPause() override
+  {
+    gIsPaused = true;
+  }
+
+  void OnResume() override
+  {
+    gIsPaused = false;
+  }
+
+  /**
+   * Dispatch table for instance functions
+   * @return
+   */
+  Dali::AddOns::DispatchTable* GetInstanceDispatchTable() override
+  {
+    static Dali::AddOns::DispatchTable dispatchTable{};
+    if( dispatchTable.Empty() )
+    {
+      dispatchTable["InstanceCall"] = AddOnDataInstance::GetValueWithInstance;
+    }
+    return &dispatchTable;
+  }
+};
+
+REGISTER_ADDON_CLASS( TestDummyAddOn );
diff --git a/automated-tests/src/dali-adaptor-internal/utc-Dali-AddOns.cpp b/automated-tests/src/dali-adaptor-internal/utc-Dali-AddOns.cpp
new file mode 100644 (file)
index 0000000..fc4ddd0
--- /dev/null
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#include <dali/dali.h>
+#include <dali-test-suite-utils.h>
+#include <dali/integration-api/addon-manager.h>
+#include <dali/internal/addons/common/addon-manager-factory.h>
+#include <dali/devel-api/common/addon-binder.h>
+
+std::unique_ptr<Dali::Integration::AddOnManager> CreateAddOnManager()
+{
+  // Set env variables
+  setenv( "DALI_ADDONS_PATH", ADDON_LIBS_PATH, 1 );
+  setenv( "DALI_ADDONS_LIBS", "libSampleAddOn.so", 1);
+
+  return std::unique_ptr<Dali::Integration::AddOnManager>( Dali::Internal::AddOnManagerFactory::CreateAddOnManager() );
+}
+
+struct TestAddOn : public Dali::AddOn::AddOnBinder
+{
+  TestAddOn() : AddOnBinder( "SampleAddOn", 0u )
+  {}
+
+  ADDON_BIND_FUNCTION( GetLifecycleStatus, bool() );
+};
+
+int UtcDaliTestAddOnInterface(void)
+{
+  TestApplication application;
+  // Create AddOnManager using internal factory
+  auto addOnManager = CreateAddOnManager();
+
+  TestAddOn addon;
+
+  DALI_TEST_EQUALS( addon.IsValid(), true, TEST_LOCATION );
+
+  const auto& info = addon.GetAddOnInfo();
+
+  // Test returned addon version and type
+  DALI_TEST_EQUALS( info.version, Dali::DALI_ADDON_VERSION( 1, 0 , 0), TEST_LOCATION );
+  DALI_TEST_EQUALS( info.type, Dali::AddOnType::GENERIC, TEST_LOCATION );
+
+  // Test lifecycle
+  addOnManager->Pause();
+
+  auto result1 = addon.GetLifecycleStatus();
+  DALI_TEST_EQUALS( result1, true, TEST_LOCATION );
+
+  addOnManager->Resume();
+  auto result2 = addon.GetLifecycleStatus();
+  DALI_TEST_EQUALS( result2, false, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliTestAddOnManager(void)
+{
+  TestApplication application;
+
+  // Create AddOnManager using internal factory
+  auto addOnManagerUPTR = CreateAddOnManager();
+
+  // Get addon-manager
+  auto* addonManager = Dali::Integration::AddOnManager::Get();
+
+  bool result = addonManager != nullptr;
+
+  DALI_TEST_EQUALS( result, true, TEST_LOCATION );
+
+  auto availableAddons = addonManager->EnumerateAddOns();
+
+  // must be 1 addon available
+  DALI_TEST_EQUALS( availableAddons.size(), 1u, TEST_LOCATION );
+
+  Dali::AddOnInfo info{};
+  addonManager->GetAddOnInfo( availableAddons[0], info );
+
+  // Test returned addon version and type
+  DALI_TEST_EQUALS( info.version, Dali::DALI_ADDON_VERSION( 1, 0 , 0), TEST_LOCATION );
+  DALI_TEST_EQUALS( info.type, Dali::AddOnType::GENERIC, TEST_LOCATION );
+
+  // Get addon handle
+  auto testAddon = addonManager->GetAddOn( availableAddons[0] );
+  result = testAddon != 0;
+  DALI_TEST_EQUALS( result, true, TEST_LOCATION );
+
+  // Get addon global function
+  auto createInstance = addonManager->GetGlobalProc<void*()>( testAddon, "CreateInstance");
+  result = createInstance != nullptr;
+  DALI_TEST_EQUALS( result, true, TEST_LOCATION );
+
+  // Test for false positive (queried function must not be found)
+  auto dummyfunction = addonManager->GetGlobalProc<void*()>( testAddon, "ThisFunctionDoesntExist");
+  result = dummyfunction == nullptr;
+  DALI_TEST_EQUALS( result, true, TEST_LOCATION );
+
+  // Get Instance function and call it, expect answer 42
+  auto instanceFunction = addonManager->GetInstanceProc<uint32_t(void*)>( testAddon, "InstanceCall" );
+  auto* instance = createInstance();
+  auto answer = instanceFunction( instance );
+  DALI_TEST_EQUALS( answer, 42, TEST_LOCATION );
+
+  // Test lifecycle
+  auto GetLifecycleStatus = addonManager->GetGlobalProc<bool()>( testAddon, "GetLifecycleStatus");
+  addonManager->Pause();
+
+  DALI_TEST_EQUALS( GetLifecycleStatus(), true, TEST_LOCATION );
+
+  addonManager->Resume();
+  DALI_TEST_EQUALS( GetLifecycleStatus(), false, TEST_LOCATION );
+
+  END_TEST;
+}
\ No newline at end of file
index 9e45dea..161d1de 100644 (file)
@@ -129,6 +129,9 @@ include( ${ADAPTOR_ROOT}/dali/internal/trace/file.list )
 SET( adaptor_thread_dir ${ADAPTOR_ROOT}/dali/internal/thread )
 include( ${ADAPTOR_ROOT}/dali/internal/thread/file.list )
 
+SET( adaptor_addons_dir ${ADAPTOR_ROOT}/dali/internal/addons )
+include( ${ADAPTOR_ROOT}/dali/internal/addons/file.list )
+
 SET( adaptor_vector_animation_dir ${ADAPTOR_ROOT}/dali/internal/vector-animation )
 include( ${ADAPTOR_ROOT}/dali/internal/vector-animation/file.list )
 
index f0d1cf0..5862cec 100644 (file)
@@ -42,6 +42,8 @@ SET( SOURCES
         ${devel_api_text_abstraction_src_files}
         ${static_libraries_libunibreak_src_files}
         ${static_libraries_glyphy_src_files}
+        ${adaptor_addons_common_src_files}
+        ${adaptor_addons_dummy_src_files}
 )
 
 IF( ENABLE_ANDROIDJNI_FRAMEWORK )
index bdc26ff..2d24972 100644 (file)
@@ -40,6 +40,8 @@ SET( SOURCES
     ${adaptor_window_system_tizen_wayland_src_files}
     ${adaptor_trace_common_src_files}
     ${adaptor_thread_common_src_files}
+    ${adaptor_addons_common_src_files}
+    ${adaptor_addons_dummy_src_files}
     ${devel_api_text_abstraction_src_files}
     ${static_libraries_glyphy_src_files}
     ${static_libraries_libunibreak_src_files}
index 77d540c..aebd8b6 100644 (file)
@@ -41,6 +41,8 @@ SET( SOURCES
      ${adaptor_window_system_tizen_wayland_src_files}
      ${adaptor_trace_common_src_files}
      ${adaptor_thread_common_src_files}
+     ${adaptor_addons_common_src_files}
+     ${adaptor_addons_tizen_src_files}
      ${devel_api_text_abstraction_src_files}
      ${static_libraries_glyphy_src_files}
      ${static_libraries_libunibreak_src_files}
index 0ba3e35..a53da27 100644 (file)
@@ -40,6 +40,8 @@ SET( SOURCES
         ${adaptor_window_system_tizen_wayland_src_files}
         ${adaptor_trace_common_src_files}
         ${adaptor_thread_common_src_files}
+        ${adaptor_addons_common_src_files}
+        ${adaptor_addons_tizen_src_files}
         ${devel_api_text_abstraction_src_files}
         ${static_libraries_glyphy_src_files}
         ${static_libraries_libunibreak_src_files}
index ff4b008..2469de7 100644 (file)
@@ -41,6 +41,8 @@ SET( SOURCES
     ${adaptor_trace_common_src_files}
     ${adaptor_thread_common_src_files}
     ${devel_api_text_abstraction_src_files}
+    ${adaptor_addons_common_src_files}
+    ${adaptor_addons_tizen_src_files}
     ${static_libraries_glyphy_src_files}
     ${static_libraries_libunibreak_src_files}
      )
index 27cc6ad..82643fa 100644 (file)
@@ -40,6 +40,8 @@ SET( SOURCES
         ${adaptor_thread_common_src_files}
         ${adaptor_window_system_ubuntu_x11_src_files}
         ${devel_api_text_abstraction_src_files}
+        ${adaptor_addons_common_src_files}
+        ${adaptor_addons_ubuntu_src_files}
         ${static_libraries_glyphy_src_files}
         ${static_libraries_libunibreak_src_files}
 )
index 7d5b1b4..2a908d0 100644 (file)
@@ -42,6 +42,8 @@ SET( SOURCES
     ${adaptor_window_system_tizen_wayland_src_files}
     ${adaptor_trace_common_src_files}
     ${adaptor_thread_common_src_files}
+    ${adaptor_addons_common_src_files}
+    ${adaptor_addons_tizen_src_files}
     ${devel_api_text_abstraction_src_files}
     ${static_libraries_glyphy_src_files}
     ${static_libraries_libunibreak_src_files}
index 28b0d31..c39c3bd 100644 (file)
@@ -40,6 +40,8 @@ SET( SOURCES
         ${adaptor_input_windows_src_files}
         ${adaptor_clipboard_windows_src_files}
         ${adaptor_imaging_windows_src_files}
+        ${adaptor_addons_common_src_files}
+        ${adaptor_addons_dummy_src_files}
 )
 
 # Builds the c files as c++
index b43c376..e111bdb 100644 (file)
@@ -17,6 +17,8 @@
 
 // CLASS HEADER
 #include <dali/internal/adaptor/common/adaptor-impl.h>
+#include <dali/internal/addons/common/addon-manager-impl.h>
+#include <dali/internal/addons/common/addon-manager-factory.h>
 #include <dali/internal/adaptor/common/adaptor-builder-impl.h>
 
 // EXTERNAL INCLUDES
@@ -35,6 +37,7 @@
 #include <dali/integration-api/events/touch-event-integ.h>
 #include <dali/integration-api/events/wheel-event-integ.h>
 #include <dali/integration-api/processor-interface.h>
+#include <dali/integration-api/addon-manager.h>
 
 // INTERNAL INCLUDES
 #include <dali/public-api/dali-adaptor-common.h>
@@ -174,6 +177,9 @@ void Adaptor::Initialize( GraphicsFactory& graphicsFactory, Dali::Configuration:
   EglSyncImplementation& eglSyncImpl = eglGraphics->GetSyncImplementation();
   EglContextHelperImplementation& eglContextHelperImpl = eglGraphics->GetContextHelperImplementation();
 
+  // Create the AddOnManager
+  mAddOnManager.reset( Dali::Internal::AddOnManagerFactory::CreateAddOnManager() );
+
   mCore = Integration::Core::New( *this,
                                   *mPlatformAbstraction,
                                   mGLES,
@@ -184,6 +190,7 @@ void Adaptor::Initialize( GraphicsFactory& graphicsFactory, Dali::Configuration:
                                   mGraphics->GetStencilBufferRequired(),
                                   mGraphics->GetPartialUpdateRequired() );
 
+
   defaultWindow->SetAdaptor( Get() );
 
   Dali::Integration::SceneHolder defaultSceneHolder( defaultWindow );
@@ -401,6 +408,8 @@ void Adaptor::Start()
   {
     (*iter)->OnStart();
   }
+
+  mAddOnManager->Start();
 }
 
 // Dali::Internal::Adaptor::Adaptor::Pause
@@ -415,6 +424,9 @@ void Adaptor::Pause()
       (*iter)->OnPause();
     }
 
+    // Extensions
+    mAddOnManager->Pause();
+
     // Pause all windows event handlers when adaptor paused
     for( auto window : mWindows )
     {
@@ -449,6 +461,9 @@ void Adaptor::Resume()
       window->Resume();
     }
 
+    // Resume AddOnManager
+    mAddOnManager->Resume();
+
     // Inform observers that we have resumed.
     for( ObserverContainer::iterator iter = mObservers.begin(), endIter = mObservers.end(); iter != endIter; ++iter )
     {
@@ -480,6 +495,8 @@ void Adaptor::Stop()
       (*iter)->OnStop();
     }
 
+    mAddOnManager->Stop();
+
     mThreadController->Stop();
 
     // Delete the TTS player
index 115f78a..7cb94dd 100644 (file)
@@ -53,6 +53,7 @@ namespace Integration
 class Core;
 class GlAbstraction;
 class Processor;
+class AddOnManager;
 }
 
 namespace Internal
@@ -694,6 +695,8 @@ private: // Data
   const bool                            mEnvironmentOptionsOwned:1;   ///< Whether we own the EnvironmentOptions (and thus, need to delete it)
   bool                                  mUseRemoteSurface:1;          ///< whether the remoteSurface is used or not
 
+  std::unique_ptr<Integration::AddOnManager> mAddOnManager;           ///< Pointer to the addon manager
+
 public:
   inline static Adaptor& GetImplementation(Dali::Adaptor& adaptor) { return *adaptor.mImpl; }
 };
index cf5b02c..34b2f41 100644 (file)
@@ -1,30 +1,30 @@
 
 # module: adaptor, backend: common
-SET( adaptor_adaptor_common_src_files 
-    ${adaptor_adaptor_dir}/common/lifecycle-controller-impl.cpp 
-    ${adaptor_adaptor_dir}/common/adaptor-impl.cpp 
-    ${adaptor_adaptor_dir}/common/adaptor.cpp 
-    ${adaptor_adaptor_dir}/common/adaptor-builder-impl.cpp 
-    ${adaptor_adaptor_dir}/common/application-impl.cpp 
-    ${adaptor_adaptor_dir}/common/combined-update-render-controller.cpp 
+SET( adaptor_adaptor_common_src_files
+    ${adaptor_adaptor_dir}/common/lifecycle-controller-impl.cpp
+    ${adaptor_adaptor_dir}/common/adaptor-impl.cpp
+    ${adaptor_adaptor_dir}/common/adaptor.cpp
+    ${adaptor_adaptor_dir}/common/adaptor-builder-impl.cpp
+    ${adaptor_adaptor_dir}/common/application-impl.cpp
+    ${adaptor_adaptor_dir}/common/combined-update-render-controller.cpp
     ${adaptor_adaptor_dir}/common/system-cache-path.cpp
 )
 
 # module: adaptor, backend: tizen-wayland
-SET( adaptor_adaptor_tizen_wayland_src_files 
-    ${adaptor_adaptor_dir}/tizen-wayland/adaptor-impl-tizen.cpp 
+SET( adaptor_adaptor_tizen_wayland_src_files
+    ${adaptor_adaptor_dir}/tizen-wayland/adaptor-impl-tizen.cpp
     ${adaptor_adaptor_dir}/tizen-wayland/framework-tizen.cpp
 )
 
 # module: adaptor, backend: tizen-wearable
-SET( adaptor_adaptor_tizen_wearable_src_files 
-    ${adaptor_adaptor_dir}/tizen-wayland/tizen-wearable/watch-application.cpp 
+SET( adaptor_adaptor_tizen_wearable_src_files
+    ${adaptor_adaptor_dir}/tizen-wayland/tizen-wearable/watch-application.cpp
     ${adaptor_adaptor_dir}/tizen-wayland/tizen-wearable/watch-application-impl.cpp
 )
 
 # module: adaptor, backend: ubuntu
-SET( adaptor_adaptor_ubuntu_src_files 
-    ${adaptor_adaptor_dir}/generic/adaptor-impl-generic.cpp 
+SET( adaptor_adaptor_ubuntu_src_files
+    ${adaptor_adaptor_dir}/generic/adaptor-impl-generic.cpp
     ${adaptor_adaptor_dir}/ubuntu/framework-ubuntu.cpp
 )
 
diff --git a/dali/internal/addons/common/addon-manager-factory.h b/dali/internal/addons/common/addon-manager-factory.h
new file mode 100644 (file)
index 0000000..a0d8f18
--- /dev/null
@@ -0,0 +1,42 @@
+#ifndef DALI_ADDON_MANAGER_FACTORY
+#define DALI_ADDON_MANAGER_FACTORY
+
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <dali/integration-api/addon-manager.h>
+
+namespace Dali
+{
+namespace Internal
+{
+/**
+ * @brief The base AddOnManager factory class
+ */
+class AddOnManagerFactory
+{
+public:
+  /**
+   * @brief Creates AddOnManager
+   * @return returns AddOnManager object or nullptr if no support
+   */
+  static Integration::AddOnManager* CreateAddOnManager();
+};
+} // namespace Internal
+} // namespace Dali
+
+#endif // DALI_ADDON_MANAGER_FACTORY
\ No newline at end of file
diff --git a/dali/internal/addons/common/addon-manager-impl.h b/dali/internal/addons/common/addon-manager-impl.h
new file mode 100644 (file)
index 0000000..f431c49
--- /dev/null
@@ -0,0 +1,121 @@
+#ifndef DALI_INTERNAL_ADDON_MANAGER_IMPL
+#define DALI_INTERNAL_ADDON_MANAGER_IMPL
+
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <dali/integration-api/addon-manager.h>
+
+#include <string>
+#include <vector>
+#include <memory>
+
+namespace Dali
+{
+namespace Internal
+{
+/**
+ * Base class for platform-specific implementation of AddOnManager
+ */
+class AddOnManager
+{
+protected:
+
+  /**
+   * @brief Constructor
+   */
+  AddOnManager() = default;
+
+public:
+  /**
+   * @brief Destructor
+   */
+  virtual ~AddOnManager() = default;
+
+  /**
+   * @brief Registers the dispatch table with AddOnManager.
+   * @param[in] dispatchTable Pointer to the valid dispatch table
+   */
+  virtual void RegisterAddOnDispatchTable( const AddOnDispatchTable* dispatchTable ) = 0;
+
+  /**
+   * @brief Retrieves list of the available AddOns
+   * @return List of AddOn names
+   */
+  virtual std::vector<std::string> EnumerateAddOns() = 0;
+
+  /**
+   * @brief Returns AddOnInfo structure for specified AddOn name
+   * @param[in] name Name of AddOn
+   * @param[out]] info Output reference
+   * @return True on success, False if extension info cannot be retrieved
+   */
+  virtual bool GetAddOnInfo(const std::string& name, AddOnInfo& info ) = 0;
+
+  /**
+   * @brief Loads and initialises specified AddOns
+   * @param[in] extensionNames Array of extension names
+   * @return vector of initialised AddOnLibrary handles
+   */
+  virtual std::vector<Dali::AddOnLibrary> LoadAddOns( const std::vector<std::string>& addonNames ) = 0;
+
+  /**
+   * @brief Returns AddOn global function pointer
+   * @param[in] addOnLibrary valid AddOn library object
+   * @param[in] procName Name of the function to retrieve
+   * @return Pointer to the function or null if function doesn't exist
+   */
+  virtual void* GetGlobalProc( const Dali::AddOnLibrary& addonHandle, const char* procName ) = 0;
+
+  /**
+   * @brief Returns addon instance function pointer
+   * @param[in] addOnLibrary valid AddOn library object
+   * @param[in] procName Name of the function to retrieve
+   * @return Pointer to the function or null if function doesn't exist
+   */
+  virtual void* GetInstanceProc( const Dali::AddOnLibrary& addonHandle, const char* procName ) = 0;
+
+  /**
+   * @brief Pause lifecycle event
+   * Implementation is optional and depends whether AddOn needs to handle lifecycle event.
+   */
+  virtual void Pause() {}
+
+  /**
+   * @brief Resume lifecycle event
+   * Implementation is optional and depends whether AddOn needs to handle lifecycle event.
+   */
+  virtual void Resume() {}
+
+  /**
+   * @brief Start lifecycle event
+   * Implementation is optional and depends whether AddOn needs to handle lifecycle event.
+   */
+  virtual void Start() {}
+
+  /**
+   * @brief Stop lifecycle event
+   * Implementation is optional and depends whether AddOn needs to handle lifecycle event.
+   */
+  virtual void Stop() {}
+};
+
+} // Internal
+
+} // Dali
+
+#endif // DALI_CMAKE_EXTENSION_MANAGER_IMPL
diff --git a/dali/internal/addons/common/addon-manager.cpp b/dali/internal/addons/common/addon-manager.cpp
new file mode 100644 (file)
index 0000000..ffd193d
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include "addon-manager.h"
+#include <dali/internal/addons/common/addon-manager-impl.h>
+
+namespace Dali
+{
+namespace Internal
+{
+namespace AddOnManagerFactory
+{
+__attribute__((weak)) Dali::Integration::AddOnManager* CreateAddOnManager()
+{
+  return nullptr;
+}
+
+} // AddOnManagerFactory
+}
+
+namespace Adaptor
+{
+
+AddOnManager::AddOnManager(Internal::AddOnManager* impl ) : Integration::AddOnManager()
+{
+  mImpl.reset(impl);
+}
+
+AddOnManager::~AddOnManager() = default;
+
+void AddOnManager::RegisterAddOnDispatchTable( const AddOnDispatchTable* dispatchTable )
+{
+  mImpl->RegisterAddOnDispatchTable( dispatchTable );
+}
+
+std::vector<std::string> AddOnManager::EnumerateAddOns()
+{
+  return mImpl->EnumerateAddOns();
+}
+
+bool AddOnManager::GetAddOnInfo(const std::string& name, AddOnInfo& info )
+{
+  return mImpl->GetAddOnInfo( name, info );
+}
+
+std::vector<Dali::AddOnLibrary> AddOnManager::LoadAddOns(const std::vector<std::string>& addonNames )
+{
+  return std::move(mImpl->LoadAddOns( addonNames ));
+}
+
+void* AddOnManager::GetGlobalProc(const Dali::AddOnLibrary& addonHandle, const char *procName)
+{
+  return mImpl->GetGlobalProc( addonHandle, procName );
+}
+
+void* AddOnManager::GetInstanceProc(const Dali::AddOnLibrary& addonHandle, const char* procName )
+{
+  return mImpl->GetInstanceProc( addonHandle, procName );
+}
+
+void AddOnManager::Pause()
+{
+  mImpl->Pause();
+}
+
+void AddOnManager::Resume()
+{
+  mImpl->Resume();
+}
+
+void AddOnManager::Start()
+{
+  mImpl->Start();
+}
+
+void AddOnManager::Stop()
+{
+  mImpl->Stop();
+}
+
+}
+}
\ No newline at end of file
diff --git a/dali/internal/addons/common/addon-manager.h b/dali/internal/addons/common/addon-manager.h
new file mode 100644 (file)
index 0000000..ab57360
--- /dev/null
@@ -0,0 +1,123 @@
+#ifndef DALI_ADAPTOR_COMMON_ADDON_MANAGER
+#define DALI_ADAPTOR_COMMON_ADDON_MANAGER
+
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <dali/integration-api/addon-manager.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+class AddOnManager;
+};
+
+namespace Adaptor
+{
+
+class AddOnManager : public Dali::Integration::AddOnManager
+{
+public:
+
+  /**
+   * @brief Constructor
+   * @param impl Pointer to the platform specific implementation
+   */
+  explicit AddOnManager(Internal::AddOnManager* impl);
+
+  /**
+   * @brief Destructor
+   */
+  ~AddOnManager() override;
+
+  /**
+   * @brief Registers a dispatch table for new AddOn. Dispatch table contains essential
+   * functions that will be called by the AddOnManager. It also includes lifecycle
+   * event callbacks.
+   * @param[in] dispatchTable Valid pointer to the DispatchTable object
+   */
+  void RegisterAddOnDispatchTable( const AddOnDispatchTable* dispatchTable ) override;
+
+  /**
+   * @brief Retrieves list of all the extensions available
+   * @return List of AddOn names
+   */
+  std::vector<std::string> EnumerateAddOns() override;
+
+  /**
+   * @brief Returns AddOnInfo structure for specified extension name
+   * @param[in] name Name of extension
+   * @param[out]] info Output reference
+   * @return True on success, False if extension info cannot be retrieved
+   */
+  bool GetAddOnInfo(const std::string& name, AddOnInfo& info ) override;
+
+  /**
+   * @brief Loads and initialises specified extensions
+   *
+   * @param[in] extensionNames Array of extension names
+   * @return vector of initialised extension handles
+   */
+  std::vector<AddOnLibrary> LoadAddOns( const std::vector<std::string>& addonNames ) override;
+
+  /**
+   * @brief Returns addon global function pointer
+   * @param[in] addonHandle Addon handle
+   * @param[in] procName Name of the function to retrieve
+   * @return Pointer to the function or null if function doesn't exist
+   */
+  void* GetGlobalProc( const Dali::AddOnLibrary& addonHandle, const char* procName ) override;
+
+  /**
+   * @brief Returns addon instance function pointer
+   * @param[in] addonHandle Addon handle
+   * @param[in] procName Name of the function to retrieve
+   * @return Pointer to the function or null if function doesn't exist
+   */
+  void* GetInstanceProc( const Dali::AddOnLibrary& addonHandle, const char* procName ) override;
+
+  /**
+   * @brief Lifecycle pause function
+   */
+  void Pause() override;
+
+  /**
+   * @brief Lifecycle resume function
+   */
+  void Resume() override;
+
+  /**
+   * @brief Lifecycle start function
+   */
+  void Start() override;
+
+  /**
+   * @brief Lifecycle stop function
+   */
+  void Stop() override;
+
+private:
+
+  std::unique_ptr<Internal::AddOnManager> mImpl; /// Implementation of the AddOnManager
+
+};
+} // namespace Internal
+} // namespace Dali
+
+#endif // DALI_ADAPTOR_COMMON_ADDON_MANAGER
diff --git a/dali/internal/addons/dummy/addon-manager-factory-dummy.cpp b/dali/internal/addons/dummy/addon-manager-factory-dummy.cpp
new file mode 100644 (file)
index 0000000..758f811
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <dali/internal/addons/common/addon-manager-factory.h>
+
+namespace Dali
+{
+namespace Internal
+{
+Integration::AddOnManager* AddOnManagerFactory::CreateAddOnManager()
+{
+  // AddOnManager may be not implemented.
+  return nullptr;
+}
+
+} // namespace Internal
+} // namespace Dali
diff --git a/dali/internal/addons/file.list b/dali/internal/addons/file.list
new file mode 100644 (file)
index 0000000..c885207
--- /dev/null
@@ -0,0 +1,22 @@
+
+# module: addons, backend: common
+SET( adaptor_addons_common_src_files
+    ${adaptor_addons_dir}/common/addon-manager.cpp
+)
+
+# module: addons, backend: tizen
+SET( adaptor_addons_tizen_src_files
+    ${adaptor_addons_dir}/linux/addon-manager-impl-linux.cpp
+    ${adaptor_addons_dir}/tizen/addon-manager-factory-tizen.cpp
+)
+
+# module: addons, backend: ubuntu
+SET( adaptor_addons_ubuntu_src_files
+    ${adaptor_addons_dir}/linux/addon-manager-impl-linux.cpp
+    ${adaptor_addons_dir}/ubuntu/addon-manager-factory-ubuntu.cpp
+)
+
+# module: addons, backend: dummy
+SET( adaptor_addons_dummy_src_files
+    ${adaptor_addons_dir}/dummy/addon-manager-factory-dummy.cpp
+)
diff --git a/dali/internal/addons/linux/addon-manager-impl-linux.cpp b/dali/internal/addons/linux/addon-manager-impl-linux.cpp
new file mode 100644 (file)
index 0000000..036f7e5
--- /dev/null
@@ -0,0 +1,289 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali/internal/addons/linux/addon-manager-impl-linux.h>
+#include <dali/devel-api/adaptor-framework/environment-variable.h>
+#include <dali/internal/system/common/environment-variables.h>
+
+// EXTERNAL INCLUDES
+#include <dali/integration-api/debug.h>
+
+#include <dlfcn.h>
+#include <functional>
+#include <algorithm>
+#include <iterator>
+#include <sstream>
+
+namespace Dali
+{
+namespace Internal
+{
+
+AddOnManagerLinux::AddOnManagerLinux() = default;
+
+AddOnManagerLinux::~AddOnManagerLinux() = default;
+
+void AddOnManagerLinux::RegisterAddOnDispatchTable( const AddOnDispatchTable* dispatchTable )
+{
+  mAddOnNames.emplace_back(dispatchTable->name);
+  mAddOnCache.emplace_back();
+  mAddOnCache.back().GetGlobalProc = dispatchTable->GetGlobalProc;
+  mAddOnCache.back().GetInstanceProc = dispatchTable->GetInstanceProc;
+  mAddOnCache.back().GetAddOnInfo = dispatchTable->GetAddOnInfo;
+
+  auto& callbacks = mAddOnCache.back().lifecycleCallbacks;
+  auto initEvent = [&callbacks](uint32_t event, void(*fn)() ) {
+    callbacks[event].function = fn;
+    callbacks[event].initialized = true;
+  };
+
+  initEvent( LifecycleCallback::EVENT_START, dispatchTable->OnStart );
+  initEvent( LifecycleCallback::EVENT_STOP, dispatchTable->OnStop );
+  initEvent( LifecycleCallback::EVENT_PAUSE, dispatchTable->OnPause );
+  initEvent( LifecycleCallback::EVENT_RESUME, dispatchTable->OnResume );
+}
+
+std::vector<std::string> AddOnManagerLinux::EnumerateAddOns()
+{
+  if( mAddOnNames.empty() )
+  {
+    // AddOn libs must be separated with ':' character
+    const char *addonsLibs = Dali::EnvironmentVariable::GetEnvironmentVariable( DALI_ENV_ADDONS_LIBS );
+    if (!addonsLibs)
+    {
+      return {};
+    }
+
+    // Get the path where addon libs are stored
+    const char *addonsPath = Dali::EnvironmentVariable::GetEnvironmentVariable( DALI_ENV_ADDONS_PATH );
+    std::string addonsPathStr(addonsPath ? addonsPath : "/usr/lib");
+
+    // Split libs
+    std::string addonLibsStr(addonsLibs);
+    std::vector<std::string> results;
+    results.emplace_back();
+
+    std::find_if(addonLibsStr.begin(), addonLibsStr.end(), [&results](char &c)
+    {
+      if (c == ':')
+      {
+        results.emplace_back();
+      }
+      else
+      {
+        results.back() += c;
+      }
+      return false;
+    });
+
+    const char *EXTENSION_PATH = (addonsPath) ? addonsPath : "/usr/lib";
+
+    for (auto &name : results)
+    {
+      std::string fullPath(EXTENSION_PATH);
+      fullPath += "/";
+      fullPath += name;
+
+      // open lib, look for essential symbols. The libary is opened with RTLD_DEEPBIND flag
+      // to make sure the local symbol table is going to be used during lookup first.
+      auto* handle = dlopen(fullPath.c_str(), RTLD_DEEPBIND|RTLD_LAZY);
+      if (handle)
+      {
+        auto& cacheEntry = mAddOnCache.back();
+        AddOnInfo info{};
+        cacheEntry.GetAddOnInfo(info);
+        cacheEntry.info             = info;
+        cacheEntry.addOnLib         = fullPath;
+        cacheEntry.libHandle        = handle;
+        cacheEntry.opened           = false;
+      }
+      else
+      {
+        DALI_LOG_ERROR("Can't open library: %s, error: %s\n", fullPath.c_str(), dlerror());
+      }
+    }
+  }
+  return mAddOnNames;
+}
+
+bool AddOnManagerLinux::GetAddOnInfo(const std::string& name, AddOnInfo& info )
+{
+  if( mAddOnNames.empty() )
+  {
+    EnumerateAddOns();
+  }
+
+  if( mAddOnNames.empty() )
+  {
+    return false;
+  }
+
+  auto iter = std::find_if( mAddOnCache.begin(), mAddOnCache.end(), [name]( AddOnCacheEntry& item )
+  {
+    return (item.info.name == name);
+  });
+
+  if (iter == mAddOnCache.end())
+  {
+    return false;
+  }
+
+  info = iter->info;
+  return true;
+}
+
+std::vector<Dali::AddOnLibrary> AddOnManagerLinux::LoadAddOns( const std::vector<std::string>& addonNames )
+{
+  std::vector<AddOnLibrary> retval{};
+  retval.resize( addonNames.size() );
+  std::fill( retval.begin(), retval.end(), nullptr );
+
+  if( mAddOnCache.empty() )
+  {
+    EnumerateAddOns();
+    if(mAddOnCache.empty())
+    {
+      // no any extensions
+      return retval;
+    }
+  }
+
+  auto nameIndex = 0u;
+  for( const auto& name : addonNames )
+  {
+    auto index = 0u;
+    nameIndex++;
+    auto iter = std::find_if( mAddOnCache.begin(), mAddOnCache.end(), [&index, name]( AddOnCacheEntry& item )
+    {
+      ++index;
+      return (item.info.name == name);
+    });
+
+    if(iter == mAddOnCache.end())
+    {
+      continue;
+    }
+
+    if(!iter->opened && iter->libHandle)
+    {
+      // Open library, pull symbols and keep the handle
+      auto& entry = *iter;
+      entry.opened = true;
+    }
+
+    // Store cache index of extension for indirect calling
+    // Stored number in this implementation is always +1 (0 is nullptr, unsuccessful)
+    retval[nameIndex-1] = reinterpret_cast<void*>( index );
+  }
+
+  return retval;
+}
+
+void* AddOnManagerLinux::GetGlobalProc( const Dali::AddOnLibrary& addonHandle, const char* procName )
+{
+  if( !addonHandle )
+  {
+    return nullptr;
+  }
+
+  auto index = (intptr_t(addonHandle));
+  const auto& entry = mAddOnCache[ index-1 ];
+
+  if(entry.opened && entry.libHandle )
+  {
+    // First call into dispatch table
+    auto retval = entry.GetGlobalProc( procName );
+    if( !retval )
+    {
+      // fallback
+      retval = dlsym( entry.libHandle, procName );
+    }
+    return retval;
+  }
+  else
+  {
+    DALI_LOG_ERROR("AddOn: GetGlobalProc() library failed!\n");
+  }
+  return nullptr;
+}
+
+void* AddOnManagerLinux::GetInstanceProc( const Dali::AddOnLibrary& addonHandle, const char* procName )
+{
+  if( !addonHandle )
+  {
+    return nullptr;
+  }
+
+  auto index = (intptr_t(addonHandle));
+  const auto& entry = mAddOnCache[ index-1 ];
+  if(entry.opened && entry.libHandle )
+  {
+    // First call into dispatch table
+    auto retval = entry.GetInstanceProc( procName );
+    if( !retval )
+    {
+      // fallback
+      retval = dlsym( entry.libHandle, procName );
+    }
+    return retval;
+  }
+  return nullptr;
+}
+
+void AddOnManagerLinux::Pause()
+{
+  InvokeLifecycleFunction( LifecycleCallback::EVENT_PAUSE );
+}
+
+void AddOnManagerLinux::Resume()
+{
+  InvokeLifecycleFunction( LifecycleCallback::EVENT_RESUME );
+}
+
+void AddOnManagerLinux::Start()
+{
+  InvokeLifecycleFunction( LifecycleCallback::EVENT_START );
+}
+
+void AddOnManagerLinux::Stop()
+{
+  InvokeLifecycleFunction( LifecycleCallback::EVENT_STOP );
+}
+
+void AddOnManagerLinux::InvokeLifecycleFunction( uint32_t lifecycleEvent )
+{
+  for( auto& entry : mAddOnCache )
+  {
+    auto& callback = entry.lifecycleCallbacks[lifecycleEvent];
+
+    // If AddOn didn't auto-register try to pull symbols
+    // directly out of the addon
+    if(!callback.initialized)
+    {
+      callback.function    = reinterpret_cast<decltype(callback.function)>(entry.GetGlobalProc(callback.functionName.c_str()));
+      callback.initialized = true;
+    }
+    if(callback.function)
+    {
+      callback.function();
+    }
+  }
+}
+
+} // namespace Internal
+} // namespace Dali
\ No newline at end of file
diff --git a/dali/internal/addons/linux/addon-manager-impl-linux.h b/dali/internal/addons/linux/addon-manager-impl-linux.h
new file mode 100644 (file)
index 0000000..9139321
--- /dev/null
@@ -0,0 +1,174 @@
+#ifndef DALI_ADDON_MANAGER_IMPL_LINUX
+#define DALI_ADDON_MANAGER_IMPL_LINUX
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali/internal/addons/common/addon-manager-impl.h>
+#include <dali/internal/addons/common/addon-manager.h>
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/common/vector-wrapper.h>
+
+#include <string>
+#include <memory>
+
+namespace Dali
+{
+namespace Internal
+{
+
+/**
+ * Implementation of AddOnManager for Linux based platforms (ie. Tizen, Ubuntu)
+ */
+class AddOnManagerLinux : public Internal::AddOnManager
+{
+public:
+
+  /**
+   * @copydoc Dali::Internal::AddOnManager()
+   */
+  AddOnManagerLinux();
+
+  /**
+   * @copydoc Dali::Internal::~AddOnManager()
+   */
+  ~AddOnManagerLinux() override;
+
+  /**
+   * @copydoc Dali::Internal::AddOnManager::RegisterAddOnDispatchTable()
+   */
+  void RegisterAddOnDispatchTable( const AddOnDispatchTable* dispatchTable ) override;
+
+  /**
+   * @copydoc Dali::Internal::AddOnManager::EnumerateAddOns()
+   */
+  std::vector<std::string> EnumerateAddOns() override;
+
+  /**
+   * @copydoc Dali::Internal::AddOnManager::GetAddOnInfo()
+   */
+  bool GetAddOnInfo(const std::string& name, AddOnInfo& info ) override;
+
+  /**
+   * @copydoc Dali::Internal::AddOnManager::LoadAddOns()
+   */
+  std::vector<Dali::AddOnLibrary> LoadAddOns( const std::vector<std::string>& extensionNames ) override;
+
+  /**
+   * @copydoc Dali::Internal::AddOnManager::GetGlobalProc()
+   */
+  void* GetGlobalProc( const Dali::AddOnLibrary& addonHandle, const char* procName ) override;
+
+  /**
+   * @copydoc Dali::Internal::AddOnManager::GetInstanceProc()
+   */
+  void* GetInstanceProc( const Dali::AddOnLibrary& addonHandle, const char* procName ) override;
+
+  /**
+   * @copydoc Dali::Internal::AddOnManager::Pause()
+   */
+  void Pause() override;
+
+  /**
+   * @copydoc Dali::Internal::AddOnManager::Resume()
+   */
+  void Resume() override;
+
+  /**
+   * @copydoc Dali::Internal::AddOnManager::Start()
+   */
+  void Start() override;
+
+  /**
+   * @copydoc Dali::Internal::AddOnManager::Stop()
+   */
+  void Stop() override;
+
+private:
+
+  /**
+   * @brief Invokes lifecycle event handling function based on incoming event
+   * @param[in] lifecycleEvent The lifecycle event
+   */
+  void InvokeLifecycleFunction( uint32_t lifecycleEvent );
+
+  /**
+   * @struct Lifecycle callback structure
+   * The instance of the LifecycleCallback handles a single lifecycle
+   * event and is bound to an AddOn lifecycle function. The lifecycle
+   * function is optional and in case it doesn't exist, the event
+   * will be ignored.
+   */
+  struct LifecycleCallback
+  {
+    const static uint32_t EVENT_PAUSE = 0u; ///< pause event
+    const static uint32_t EVENT_RESUME = 1u; ///< resume event
+    const static uint32_t EVENT_START = 2u; ///< start event
+    const static uint32_t EVENT_STOP = 3u; ///< stop event
+
+    /**
+     * @brief Constructor
+     * @param[in] funcName name of the lifecycle function
+     */
+    explicit LifecycleCallback(const char* funcName)
+    {
+      functionName = funcName;
+    }
+
+    std::string functionName; ///< Name of lifecycle function
+    void(*function)() = nullptr; ///< Lifecycle function pointer
+    bool initialized { false }; ///< Flag indicates whether LifecycleCallback is initialized
+  };
+
+  /**
+   * @struct AddOnCacheEntry
+   * @brief Instance of AddOnCacheEntry stores AddOn essential
+   * function pointers and library handle.
+   */
+  struct AddOnCacheEntry
+  {
+    std::string addOnLib{};
+    AddOnInfo info{};
+
+    // library handle
+    void* libHandle {nullptr};
+
+    // main function pointers
+    void(*GetAddOnInfo)(AddOnInfo& ) = nullptr; ///< Returns AddOnInfo structure
+    void*(*GetInstanceProc)( const char* ) = nullptr; ///< Returns pointer of instance function (member funtion)
+    void*(*GetGlobalProc)( const char* ) = nullptr; ///< Returns pointer of global function (non-member function)
+
+    // lifecycle functions
+    std::vector<LifecycleCallback> lifecycleCallbacks =
+                                     {
+                                       LifecycleCallback{ "OnPause" },
+                                       LifecycleCallback{ "OnResume" },
+                                       LifecycleCallback{ "OnStart" },
+                                       LifecycleCallback{ "OnStop" },
+                                     };
+    bool opened{false};
+  };
+
+  std::vector<AddOnCacheEntry> mAddOnCache;
+  std::vector<std::string> mAddOnNames;
+};
+
+
+}
+}
+#endif //DALI_CMAKE_EXTENSION_MANAGER_IMPL_UBUNTU
diff --git a/dali/internal/addons/tizen/addon-manager-factory-tizen.cpp b/dali/internal/addons/tizen/addon-manager-factory-tizen.cpp
new file mode 100644 (file)
index 0000000..53e06aa
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <dali/internal/addons/common/addon-manager-factory.h>
+#include <dali/internal/addons/linux/addon-manager-impl-linux.h>
+
+namespace Dali
+{
+namespace Internal
+{
+Integration::AddOnManager* AddOnManagerFactory::CreateAddOnManager()
+{
+  return new Dali::Adaptor::AddOnManager( new AddOnManagerLinux() );
+}
+
+} // namespace Internal
+} // namespace Dali
diff --git a/dali/internal/addons/ubuntu/addon-manager-factory-ubuntu.cpp b/dali/internal/addons/ubuntu/addon-manager-factory-ubuntu.cpp
new file mode 100644 (file)
index 0000000..53e06aa
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <dali/internal/addons/common/addon-manager-factory.h>
+#include <dali/internal/addons/linux/addon-manager-impl-linux.h>
+
+namespace Dali
+{
+namespace Internal
+{
+Integration::AddOnManager* AddOnManagerFactory::CreateAddOnManager()
+{
+  return new Dali::Adaptor::AddOnManager( new AddOnManagerLinux() );
+}
+
+} // namespace Internal
+} // namespace Dali
index 6dca45a..542afba 100755 (executable)
@@ -136,6 +136,10 @@ namespace Adaptor
 
 #define DALI_ENV_DPI_VERTICAL "DALI_DPI_VERTICAL"
 
+#define DALI_ENV_ADDONS_PATH "DALI_ADDONS_PATH"
+
+#define DALI_ENV_ADDONS_LIBS "DALI_ADDONS_LIBS"
+
 } // namespace Adaptor
 
 } // namespace Internal