From: JinWang An Date: Thu, 22 Aug 2019 04:49:51 +0000 (+0900) Subject: update appfw plugin to support undo X-Git-Tag: submit/tizen/20200406.072014~47 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=7f2089999996efd4c2c5d6485d0161e63235755b;p=platform%2Fcore%2Fsystem%2Fmodes-plugins.git update appfw plugin to support undo --- diff --git a/appfw/AppfwAction.cpp b/appfw/AppfwAction.cpp index 97a9c17..32736be 100644 --- a/appfw/AppfwAction.cpp +++ b/appfw/AppfwAction.cpp @@ -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; diff --git a/appfw/AppfwAction.h b/appfw/AppfwAction.h index 2719ca3..c5f40ae 100644 --- a/appfw/AppfwAction.h +++ b/appfw/AppfwAction.h @@ -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); diff --git a/appfw/AppfwActionLaunch.cpp b/appfw/AppfwActionLaunch.cpp index e6834bc..515a93f 100644 --- a/appfw/AppfwActionLaunch.cpp +++ b/appfw/AppfwActionLaunch.cpp @@ -15,13 +15,35 @@ */ #include "AppfwActionLaunch.h" +#include #include +#include +#include #include #include "plugin-log.h" MODES_NAMESPACE_USE; const std::string AppfwActionLaunch::NAME = "launch"; +std::list 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; } diff --git a/appfw/AppfwActionLaunch.h b/appfw/AppfwActionLaunch.h index 04eaf15..d9f6f8f 100644 --- a/appfw/AppfwActionLaunch.h +++ b/appfw/AppfwActionLaunch.h @@ -15,7 +15,10 @@ */ #pragma once +#include #include +#include +#include #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 appidList; }; MODES_NAMESPACE_END diff --git a/appfw/AppfwFactory.cpp b/appfw/AppfwFactory.cpp index c6d1ac8..200d423 100644 --- a/appfw/AppfwFactory.cpp +++ b/appfw/AppfwFactory.cpp @@ -14,7 +14,6 @@ * limitations under the License. */ #include "AppfwFactory.h" -#include #include "plugin-log.h" #include "AppfwActionLaunch.h" diff --git a/appfw/AppfwFactory.h b/appfw/AppfwFactory.h index b65d7e5..74db4b0 100644 --- a/appfw/AppfwFactory.h +++ b/appfw/AppfwFactory.h @@ -15,8 +15,8 @@ */ #pragma once -#include #include +#include #include "AppfwAction.h" MODES_NAMESPACE_BEGIN diff --git a/appfw/AppfwPlugin.cpp b/appfw/AppfwPlugin.cpp index a70de70..6327f68 100644 --- a/appfw/AppfwPlugin.cpp +++ b/appfw/AppfwPlugin.cpp @@ -14,7 +14,6 @@ * limitations under the License. */ #include -#include #include #include #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; +} diff --git a/appfw/CMakeLists.txt b/appfw/CMakeLists.txt index 98cb642..355a895 100644 --- a/appfw/CMakeLists.txt +++ b/appfw/CMakeLists.txt @@ -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}) diff --git a/bluetooth/BtPlugin.cpp b/bluetooth/BtPlugin.cpp index 03a6e6b..79c9a54 100644 --- a/bluetooth/BtPlugin.cpp +++ b/bluetooth/BtPlugin.cpp @@ -101,4 +101,3 @@ int BtPlugin::set(const std::string &key, const std::string &val, std::string *o btFactory.destroyAction(action); return btRet; } - diff --git a/packaging/modes-plugins.spec b/packaging/modes-plugins.spec index 04fcf36..404fc5c 100644 --- a/packaging/modes-plugins.spec +++ b/packaging/modes-plugins.spec @@ -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 diff --git a/unittests/CMakeLists.txt b/unittests/CMakeLists.txt index dd008b7..9e7a56b 100644 --- a/unittests/CMakeLists.txt +++ b/unittests/CMakeLists.txt @@ -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}) diff --git a/unittests/mdsp_test_appfw.cpp b/unittests/mdsp_test_appfw.cpp index a1f97b0..ea1bbf5 100644 --- a/unittests/mdsp_test_appfw.cpp +++ b/unittests/mdsp_test_appfw.cpp @@ -17,9 +17,9 @@ #include #include #include -#include #include -#include "plugin-log.h" +#include +#include #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();