update appfw plugin to support undo
authorJinWang An <jinwang.an@samsung.com>
Thu, 22 Aug 2019 04:49:51 +0000 (13:49 +0900)
committerYoungjae Shin <yj99.shin@samsung.com>
Thu, 19 Mar 2020 04:30:19 +0000 (13:30 +0900)
12 files changed:
appfw/AppfwAction.cpp
appfw/AppfwAction.h
appfw/AppfwActionLaunch.cpp
appfw/AppfwActionLaunch.h
appfw/AppfwFactory.cpp
appfw/AppfwFactory.h
appfw/AppfwPlugin.cpp
appfw/CMakeLists.txt
bluetooth/BtPlugin.cpp
packaging/modes-plugins.spec
unittests/CMakeLists.txt
unittests/mdsp_test_appfw.cpp

index 97a9c17..32736be 100644 (file)
@@ -31,6 +31,16 @@ int AppfwAction::set(const std::string &val)
        return MODES_ERROR_NOT_SUPPORTED;
 }
 
+int AppfwAction::undo(const std::string &val)
+{
+       return MODES_ERROR_NOT_SUPPORTED;
+}
+
+int AppfwAction::get(std::string *val)
+{
+       return MODES_ERROR_NOT_SUPPORTED;
+}
+
 void AppfwAction::setName(std::string name)
 {
        this->name = name;
index 2719ca3..c5f40ae 100644 (file)
@@ -27,6 +27,8 @@ public:
 
        std::string getName();
        virtual int set(const std::string &val);
+       virtual int get(std::string *val);
+       virtual int undo(const std::string &val);
 
 protected:
        void setName(std::string name);
index e6834bc..515a93f 100644 (file)
  */
 #include "AppfwActionLaunch.h"
 
+#include <algorithm>
 #include <app_control.h>
+#include <app_manager.h>
+#include <app_manager_extension.h>
 #include <modes_errors.h>
 #include "plugin-log.h"
 
 MODES_NAMESPACE_USE;
 
 const std::string AppfwActionLaunch::NAME = "launch";
+std::list<std::string> AppfwActionLaunch::appidList;
+void AppfwActionLaunch::appContextStatusCallback(app_context_h app_context, app_context_status_e status, void *user_data)
+{
+       char *appid = NULL;
+       DBG("appContextStatusCallback(status:%d)", status);
+       if (app_context_get_app_id(app_context, &appid) != APP_MANAGER_ERROR_NONE) {
+               ERR("Failed to get appid\n");
+               return;
+       }
+
+       DBG("app_context_cb(appid:%s)", appid);
+       if (APP_CONTEXT_STATUS_TERMINATED == status) {
+               DBG("APP_CONTEXT_STATUS_TERMINATED appid : %s\n", appid);
+               appidList.remove(appid);
+       }
+
+       free(appid);
+       return;
+}
 
 AppfwActionLaunch::AppfwActionLaunch()
 {
@@ -32,18 +54,82 @@ int AppfwActionLaunch::set(const std::string &val)
 {
        DBG("id(%s)", val.c_str());
 
-       app_control_h service;
-       app_control_create(&service);
-       app_control_set_app_id(service, val.c_str());
-       app_control_set_operation(service, APP_CONTROL_OPERATION_DEFAULT);
-       app_control_set_launch_mode(service, APP_CONTROL_LAUNCH_MODE_SINGLE);
+       auto found = std::find(appidList.begin(), appidList.end(), val);
+
+       if (found == appidList.end())
+       {
+               bool running;
+               app_manager_is_running(val.c_str(), &running);
+
+               if (running) {
+                       ERR("It's already running before started mode-supervisor daemon");
+                       return MODES_ERROR_CONFLICT;
+               }
 
-       int ret = app_control_send_launch_request(service, NULL, NULL);
-       if (APP_CONTROL_ERROR_NONE != ret) {
-               ERR("app_control_send_launch_request() Fail(%s)", get_error_message(ret));
-               return MODES_ERROR_IO_ERROR;
+               app_control_h service;
+               app_control_create(&service);
+               app_control_set_app_id(service, val.c_str());
+               app_control_set_operation(service, APP_CONTROL_OPERATION_DEFAULT);
+               app_control_set_launch_mode(service, APP_CONTROL_LAUNCH_MODE_SINGLE);
+
+               int ret = app_control_send_launch_request(service, NULL, NULL);
+               if (APP_CONTROL_ERROR_NONE != ret) {
+                       ERR("app_control_send_launch_request() Fail(%s)", get_error_message(ret));
+                       return MODES_ERROR_IO_ERROR;
+               }
+               app_control_destroy(service);
+
+               appidList.push_back(val);
+
+               DBG("APP_CONTEXT_EVENT_LAUNCHED(appid : %s) added list\n", val.c_str());
+
+               ret = app_manager_set_app_context_status_cb(AppfwActionLaunch::appContextStatusCallback, val.c_str(), NULL);
+               if (APP_MANAGER_ERROR_NONE != ret) {
+                       ERR("app_manager_set_app_context_status_cb() Fail(%s)", get_error_message(ret));
+                       return MODES_ERROR_IO_ERROR;
+               }
+
+               appID = val;
        }
 
-       app_control_destroy(service);
+       return MODES_ERROR_NONE;
+}
+
+int AppfwActionLaunch::get(std::string *val)
+{
+       if(val)
+               *val = appID;
+       return MODES_ERROR_NONE;
+}
+
+int AppfwActionLaunch::undo(const std::string &val)
+{
+       bool running;
+       app_context_h runAppContext;
+
+       app_manager_is_running(val.c_str(), &running);
+       if (!running) {
+               DBG("It's NOT running");
+               return MODES_ERROR_NONE;
+       }
+
+       int ret = app_manager_unset_app_context_status_cb(AppfwActionLaunch::appContextStatusCallback, val.c_str());
+       if (APP_MANAGER_ERROR_NONE != ret) {
+               ERR("app_manager_unset_app_context_status_cb() Fail(%s)", get_error_message(ret));
+               return MODES_ERROR_IO_ERROR;
+       }
+
+       appidList.remove(val);
+
+       ret = app_manager_get_app_context(val.c_str(), &runAppContext);
+       if (APP_MANAGER_ERROR_NONE != ret) {
+               ERR("app_manager_get_app_context(%s) Fail(%s)", val.c_str(), get_error_message(ret));
+               return MODES_ERROR_IO_ERROR;
+       }
+       ret = app_manager_terminate_app(runAppContext);
+       if (APP_MANAGER_ERROR_NONE != ret) {
+               ERR("app_manager_terminate_app() Fail(%s)", get_error_message(ret));
+               return MODES_ERROR_IO_ERROR;
+       }
        return MODES_ERROR_NONE;
 }
index 04eaf15..d9f6f8f 100644 (file)
  */
 #pragma once
 
+#include <list>
 #include <string>
+#include <app_manager.h>
+#include <app_manager_extension.h>
 #include "AppfwAction.h"
 
 MODES_NAMESPACE_BEGIN
@@ -25,8 +28,15 @@ public:
        AppfwActionLaunch();
 
        virtual int set(const std::string &val) override;
+       virtual int get(std::string *val) override;
+       virtual int undo(const std::string &val) override;
 
        static const std::string NAME;
+       static void appContextStatusCallback(app_context_h app_context, app_context_status_e status, void *user_data);
+
+private:
+       std::string appID;
+       static std::list<std::string> appidList;
 };
 
 MODES_NAMESPACE_END
index c6d1ac8..200d423 100644 (file)
@@ -14,7 +14,6 @@
  * limitations under the License.
  */
 #include "AppfwFactory.h"
-#include <modes_errors.h>
 #include "plugin-log.h"
 #include "AppfwActionLaunch.h"
 
index b65d7e5..74db4b0 100644 (file)
@@ -15,8 +15,8 @@
  */
 #pragma once
 
-#include <string>
 #include <map>
+#include <string>
 #include "AppfwAction.h"
 
 MODES_NAMESPACE_BEGIN
index a70de70..6327f68 100644 (file)
@@ -14,7 +14,6 @@
  * limitations under the License.
  */
 #include <string>
-#include <map>
 #include <modes_errors.h>
 #include <Plugin.h>
 #include "plugin-log.h"
@@ -28,6 +27,8 @@ public:
        ~AppfwPlugin();
 
        int set(const std::string &key, const std::string &val, std::string *oldVal) override;
+       int undo(const std::string &key, const std::string &val) override;
+
 private:
        AppfwFactory appfwFactory;
 };
@@ -59,7 +60,22 @@ int AppfwPlugin::set(const std::string &key, const std::string &val, std::string
        DBG("set [%s, %s]", key.c_str(), val.c_str());
 
        int appfwRet = action->set(val);
+
+       if (oldVal)
+               action->get(oldVal);
+
        appfwFactory.destroyAction(action);
        return appfwRet;
 }
 
+int AppfwPlugin::undo(const std::string &key, const std::string &val)
+{
+       AppfwAction *action = appfwFactory.createAction(key);
+       RETVM_IF(nullptr == action, MODES_ERROR_INVALID_PARAMETER, "action(%s) is null", key.c_str());
+
+       DBG("set [%s, %s]", key.c_str(), val.c_str());
+
+       int appfwRet = action->undo(val);
+       appfwFactory.destroyAction(action);
+       return appfwRet;
+}
index 98cb642..355a895 100644 (file)
@@ -2,7 +2,7 @@ SET(APPFW_PLUGIN "modes-plugin-appfw")
 
 FILE(GLOB APPFW_SRCS *.cpp)
 
-pkg_check_modules(appfw_pkgs REQUIRED modes dlog capi-base-common capi-appfw-application)
+pkg_check_modules(appfw_pkgs REQUIRED modes dlog capi-base-common capi-appfw-application capi-appfw-app-manager aul)
 INCLUDE_DIRECTORIES(${appfw_pkgs_INCLUDE_DIRS})
 LINK_DIRECTORIES(${appfw_pkgs_LIBRARY_DIRS})
 
index 03a6e6b..79c9a54 100644 (file)
@@ -101,4 +101,3 @@ int BtPlugin::set(const std::string &key, const std::string &val, std::string *o
        btFactory.destroyAction(action);
        return btRet;
 }
-
index 04fcf36..404fc5c 100644 (file)
@@ -14,12 +14,14 @@ BuildRequires: pkgconfig(modes)
 BuildRequires: modes-plugin-devel
 BuildRequires: pkgconfig(dlog)
 BuildRequires: pkgconfig(capi-appfw-application)
+BuildRequires: pkgconfig(capi-appfw-app-manager)
 BuildRequires: pkgconfig(capi-base-common)
 BuildRequires: pkgconfig(libxml-2.0)
 BuildRequires: pkgconfig(capi-network-wifi-manager)
 BuildRequires: pkgconfig(capi-network-bluetooth)
 BuildRequires: pkgconfig(vconf)
 BuildRequires: pkgconfig(gmock)
+BuildRequires: pkgconfig(aul)
 
 %description
 Plugin Libraries for Mode Supervisor
index dd008b7..9e7a56b 100644 (file)
@@ -2,7 +2,7 @@ SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIE")
 SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIE")
 ADD_DEFINITIONS("-DMDS_TEST")
 
-pkg_check_modules(test_pkgs REQUIRED modes dlog capi-network-wifi-manager capi-network-bluetooth gmock capi-appfw-application vconf)
+pkg_check_modules(test_pkgs REQUIRED modes dlog capi-network-wifi-manager capi-network-bluetooth gmock capi-appfw-application vconf capi-appfw-app-manager aul)
 INCLUDE_DIRECTORIES(${test_pkgs_INCLUDE_DIRS})
 LINK_DIRECTORIES(${test_pkgs_LIBRARY_DIRS})
 
index a1f97b0..ea1bbf5 100644 (file)
@@ -17,9 +17,9 @@
 #include <string>
 #include <gtest/gtest.h>
 #include <Plugin.h>
-#include <modes.h>
 #include <modes_errors.h>
-#include "plugin-log.h"
+#include <app_manager.h>
+#include <app_manager_extension.h>
 #include "plugin-def.h"
 
 MODES_NAMESPACE_USE;
@@ -27,17 +27,77 @@ MODES_NAMESPACE_USE;
 extern "C" API Plugin *objectCreate(void);
 extern "C" API void objectDelete(Plugin *plugin);
 
-TEST(PluginTest, setPluginAppfw)
-{
-       int ret;
-       Plugin *plugin = objectCreate();
+class PluginTest : public ::testing::Test {
+protected:
+       void SetUp() override
+       {
+               loop = g_main_loop_new(NULL, FALSE);
+       }
+
+       void TearDown() override
+       {
+               g_main_loop_unref(loop);
+               loop = NULL;
+       }
+
+       static gboolean appfwPluginUndoConflictIdler(gpointer data)
+       {
+               app_context_h runAppContext;
+               Plugin *plugin = objectCreate();
+               result = plugin->set("launch", std::string("org.tizen.w-stopwatch"), nullptr);
+               EXPECT_EQ(MODES_ERROR_NONE, result);
+               app_manager_get_app_context("org.tizen.w-stopwatch", &runAppContext);
+               app_manager_terminate_app(runAppContext);
+               result = plugin->undo("launch", std::string("org.tizen.w-stopwatch"));
+               EXPECT_EQ(MODES_ERROR_NONE, result);
+               objectDelete(plugin);
+               g_main_loop_quit(loop);
+
+               return G_SOURCE_REMOVE;
+       }
+
+       static gboolean appfwPluginSetUndoTimeout(gpointer data)
+       {
+               Plugin *plugin = (Plugin *)data;
+               result = plugin->undo("launch", std::string("org.tizen.w-stopwatch"));
+               EXPECT_EQ(MODES_ERROR_NONE, result);
+               g_main_loop_quit(loop);
+               return false;
+       }
+
+       static gboolean appfwPluginSetUndoIdler(gpointer data)
+       {
+               Plugin *plugin = (Plugin *)data;
+               result = plugin->set("launch", std::string("org.tizen.w-stopwatch"), nullptr);
+               EXPECT_EQ(MODES_ERROR_NONE, result);
+
+               g_timeout_add(1000, appfwPluginSetUndoTimeout, plugin);
+               return G_SOURCE_REMOVE;
+       }
 
-       ret = plugin->set("launch", std::string("org.tizen.w-stopwatch"), nullptr);
-       EXPECT_EQ(ret, MODES_ERROR_NONE);
+       static int result;
+       static GMainLoop *loop;
+       static GThread *my_thread;
+};
 
-       objectDelete(plugin);
+int PluginTest::result = 0;
+GMainLoop *PluginTest::loop = NULL;
+
+TEST_F(PluginTest, setUndoPluginAppfw)
+{
+       Plugin *plugin = objectCreate();
+       g_idle_add(appfwPluginSetUndoIdler, plugin);
+       g_main_loop_run(loop);
+       objectDelete(plugin);
+}
+
+TEST_F(PluginTest, undoConflictPluginAppfw)
+{
+       g_idle_add(appfwPluginUndoConflictIdler, nullptr);
+       g_main_loop_run(loop);
 }
 
+
 int main(int argc, char **argv) {
        testing::InitGoogleTest(&argc, argv);
        return RUN_ALL_TESTS();