From: JinWang An Date: Thu, 5 Sep 2019 01:11:16 +0000 (+0900) Subject: Add changed callback for vconf plugin X-Git-Tag: submit/tizen/20200406.072014~44 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=54c5865c67897e72e01f34fd1202792923ae720c;p=platform%2Fcore%2Fsystem%2Fmodes-plugins.git Add changed callback for vconf plugin --- diff --git a/unittests/mdsp_test_vconf.cpp b/unittests/mdsp_test_vconf.cpp index 398852d..a7af18a 100644 --- a/unittests/mdsp_test_vconf.cpp +++ b/unittests/mdsp_test_vconf.cpp @@ -13,9 +13,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +#include +#include #include #include #include +#include "plugin-log.h" #include "plugin-def.h" MODES_NAMESPACE_USE; @@ -23,56 +26,99 @@ MODES_NAMESPACE_USE; extern "C" Plugin *objectCreate(void); extern "C" void objectDelete(Plugin *plugin); -TEST(PluginTest, setPluginVconfInt) +class VconfPluginTest : public ::testing::Test { +protected: + void SetUp() override + { + plugin = objectCreate(); + loop = g_main_loop_new(NULL, FALSE); + } + + void TearDown() override + { + objectDelete(plugin); + g_main_loop_unref(loop); + loop = NULL; + result = -1; + } + + static void valChangedCb(const std::string &key, void *userData) + { + DBG("%s changed callback called!", key.c_str()); + g_main_loop_quit(loop); + } + + static void valChangedResetStoredCb(const std::string &key, void *userData) + { + DBG("%s changed callback called!", key.c_str()); + result = MODES_ERROR_NONE; + } + + static void valChangedResetCb(const std::string &key, void *userData) + { + DBG("%s changed callback called!", key.c_str()); + g_main_loop_quit(loop); + } + + static gboolean changedCallbackidler(gpointer data) + { + DBG("start change the value db/setting/mode"); + vconf_set_int("db/setting/psmode", 7); + return G_SOURCE_REMOVE; + } + + static int result; + static GMainLoop *loop; + static Plugin *plugin; + static int oldval; +}; + +int VconfPluginTest::oldval = 0; +int VconfPluginTest::result = -1; +Plugin *VconfPluginTest::plugin = nullptr; +GMainLoop *VconfPluginTest::loop = NULL; + + +TEST_F(VconfPluginTest, setPluginVconfInt) { int ret; int oldval; - Plugin *plugin = objectCreate(); ret = plugin->set("db.setting.psmode", 3, nullptr); EXPECT_EQ(ret, MODES_ERROR_NONE); ret = plugin->set("db.setting.psmode", 1, &oldval); EXPECT_EQ(ret, MODES_ERROR_NONE); EXPECT_EQ(oldval, 3); - - objectDelete(plugin); } -TEST(PluginTest, setPluginVconfDouble) +TEST_F(VconfPluginTest, setPluginVconfDouble) { int ret; double oldval; - Plugin *plugin = objectCreate(); ret = plugin->set("db.system.timechange_external", 1.0, nullptr); EXPECT_EQ(ret, MODES_ERROR_NONE); ret = plugin->set("db.system.timechange_external", 0.0, &oldval); EXPECT_EQ(ret, MODES_ERROR_NONE); EXPECT_EQ(oldval, 1.0); - - objectDelete(plugin); } -TEST(PluginTest, setPluginVconfBool) +TEST_F(VconfPluginTest, setPluginVconfBool) { int ret; bool oldval; - Plugin *plugin = objectCreate(); ret = plugin->set("db.setting.sound.button_sounds", false, nullptr); EXPECT_EQ(ret, MODES_ERROR_NONE); ret = plugin->set("db.setting.sound.button_sounds", true, &oldval); EXPECT_EQ(ret, MODES_ERROR_NONE); EXPECT_EQ(oldval, false); - - objectDelete(plugin); } -TEST(PluginTest, setPluginVconfStr) +TEST_F(VconfPluginTest, setPluginVconfStr) { int ret; std::string oldval; - Plugin *plugin = objectCreate(); std::string testVal = "org.tizen.menu-screen.test"; ret = plugin->set("db.setting.menuscreen.package_name", testVal, nullptr); @@ -80,8 +126,42 @@ TEST(PluginTest, setPluginVconfStr) ret = plugin->set("db.setting.menuscreen.package_name", "org.tizen.menu-screen", &oldval); EXPECT_EQ(ret, MODES_ERROR_NONE); EXPECT_EQ(oldval.compare(testVal), 0); +} + +TEST_F(VconfPluginTest, callbackPluginVconf) +{ + vconf_get_int("db/setting/psmode", &oldval); + int ret = plugin->setChangedCallback(valChangedCb, + "db.setting.psmode", nullptr); + EXPECT_EQ(ret, MODES_ERROR_NONE); + g_idle_add(changedCallbackidler, nullptr); + g_main_loop_run(loop); + + ret = plugin->unSetChangedCallback(valChangedCb, "db.setting.psmode", nullptr); + EXPECT_EQ(ret, MODES_ERROR_NO_DATA); + vconf_set_int("db/setting/psmode", oldval); +} + +TEST_F(VconfPluginTest, callbackPluginVconfReset) +{ + int ret; + ret = plugin->set("db.setting.psmode", 4, &oldval); + EXPECT_EQ(ret, MODES_ERROR_NONE); + ret = plugin->setChangedCallback(valChangedResetStoredCb, "db.setting.psmode", nullptr); + EXPECT_EQ(ret, MODES_ERROR_NONE); + ret = plugin->set("db.setting.psmode", 2, nullptr); + EXPECT_EQ(ret, MODES_ERROR_NONE); + EXPECT_EQ(MODES_ERROR_NONE, result); + ret = plugin->setChangedCallback(valChangedResetCb, "db.setting.psmode", nullptr); + EXPECT_EQ(ret, MODES_ERROR_NONE); + g_idle_add(changedCallbackidler, nullptr); + g_main_loop_run(loop); - objectDelete(plugin); + DBG("loop end and unregister callback start"); + ret = plugin->unSetChangedCallback(valChangedResetCb, "db.setting.psmode", nullptr); + EXPECT_EQ(ret, MODES_ERROR_NO_DATA); + vconf_set_int("db/setting/psmode", oldval); + EXPECT_EQ(MODES_ERROR_NONE, result); } int main(int argc, char **argv) { diff --git a/vconf/VconfPlugin.cpp b/vconf/VconfPlugin.cpp index d362ce5..76d67c7 100644 --- a/vconf/VconfPlugin.cpp +++ b/vconf/VconfPlugin.cpp @@ -13,10 +13,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#include -#include +#include #include #include +#include +#include #include #include "plugin-log.h" #include "plugin-def.h" @@ -25,8 +26,6 @@ MODES_NAMESPACE_USE; class VconfPlugin : public Plugin { -private: - public: VconfPlugin(); @@ -39,6 +38,19 @@ public: double getDouble(const std::string &key) override; bool getBool(const std::string &key) override; std::string getString(const std::string &key) override; + + int setChangedCallback(valueChangedCb callback, const std::string &key, void *userData); + int unSetChangedCallback(valueChangedCb callback, const std::string &key, void *userData); +private: + struct CallbackData { + void *userData; + valueChangedCb *callback; + }; + + int handleChange(const std::string &key); + static void vconfChangedCallback(keynode_t *node, void *userData); + + static std::map callbackMap; }; extern "C" API Plugin *objectCreate(void) @@ -51,6 +63,8 @@ extern "C" API void objectDelete(Plugin *plugin) delete plugin; } +std::map VconfPlugin::callbackMap; + VconfPlugin::VconfPlugin() { setName("vconf"); @@ -72,6 +86,12 @@ int VconfPlugin::set(const std::string &key, int val, int *oldVal) } } + ret = handleChange(newKey); + if (MODES_ERROR_NONE != ret) { + ERR("handleChange(%s) Fail(%d)", newKey.c_str(), ret); + return ret; + } + ret = vconf_set_int(newKey.c_str(), val); if (0 != ret) { ERR("vconf_set_int(%s, %d) Fail(%d)", newKey.c_str(), val, ret); @@ -96,6 +116,12 @@ int VconfPlugin::set(const std::string &key, double val, double *oldVal) } } + ret = handleChange(newKey); + if (MODES_ERROR_NONE != ret) { + ERR("handleChange(%s) Fail(%d)", newKey.c_str(), ret); + return ret; + } + ret = vconf_set_dbl(newKey.c_str(), val); if (0 != ret) { ERR("vconf_set_int(%s, %lf) Fail(%d)", newKey.c_str(), val, ret); @@ -122,6 +148,12 @@ int VconfPlugin::set(const std::string &key, bool val, bool *oldVal) *oldVal = prev; } + ret = handleChange(newKey); + if (MODES_ERROR_NONE != ret) { + ERR("handleChange(%s) Fail(%d)", newKey.c_str(), ret); + return ret; + } + ret = vconf_set_bool(newKey.c_str(), val); if (0 != ret) { ERR("vconf_set_bool(%s, %d) Fail(%d)", newKey.c_str(), val, ret); @@ -147,8 +179,13 @@ int VconfPlugin::set(const std::string &key, const std::string &val, std::string free(prevStr); } + int ret = handleChange(newKey); + if (MODES_ERROR_NONE != ret) { + ERR("handleChange(%s) Fail(%d)", newKey.c_str(), ret); + return ret; + } - int ret = vconf_set_str(newKey.c_str(), val.c_str()); + ret = vconf_set_str(newKey.c_str(), val.c_str()); if (0 != ret) { ERR("vconf_set_str(%s, %s) Fail(%d)", newKey.c_str(), val.c_str(), ret); return MODES_ERROR_SYSTEM; @@ -223,3 +260,81 @@ std::string VconfPlugin::getString(const std::string &key) return retStr; } + +int VconfPlugin::setChangedCallback(valueChangedCb callback, const std::string &key, void *userData) +{ + std::string newKey(key); + std::replace(newKey.begin(), newKey.end(), '.', '/'); + + callbackMap[newKey].userData = userData; + callbackMap[newKey].callback = callback; + + int ret = vconf_notify_key_changed(newKey.c_str(), VconfPlugin::vconfChangedCallback, &callbackMap[newKey]); + if (VCONF_OK != ret) { + ERR("vconf_notify_key_changed(%s) Fail(%s)", newKey.c_str(), get_error_message(ret)); + return MODES_ERROR_SYSTEM; + } + + DBG("setChangedCallback(%s) Success", newKey.c_str()); + return MODES_ERROR_NONE; +} + +int VconfPlugin::unSetChangedCallback(valueChangedCb callback, const std::string &key, void *userData) +{ + std::string newKey(key); + std::replace(newKey.begin(), newKey.end(), '.', '/'); + + auto found = callbackMap.find(newKey); + if (found == callbackMap.end()) { + ERR("No Changed Callback(%s)", newKey.c_str()); + return MODES_ERROR_NO_DATA; + } + + callbackMap.erase(found); + int ret = vconf_ignore_key_changed(newKey.c_str(), VconfPlugin::vconfChangedCallback); + if (VCONF_OK != ret) { + ERR("vconf_ignore_key_changed(%s) Fail(%s)", newKey.c_str(), get_error_message(ret)); + return MODES_ERROR_SYSTEM; + } + + DBG("unSetChangedCallback(%s) Success", newKey.c_str()); + return MODES_ERROR_NONE; +} + +int VconfPlugin::handleChange(const std::string &key) +{ + auto found = callbackMap.find(key); + if (callbackMap.end() != found) { + DBG("Acition(%s) already exist", key.c_str()); + found->second.callback(key, found->second.userData); + + callbackMap.erase(found); + int ret = vconf_ignore_key_changed(key.c_str(), VconfPlugin::vconfChangedCallback); + if (VCONF_OK != ret) { + ERR("vconf_ignore_key_changed(%s) Fail(%s)", key.c_str(), get_error_message(ret)); + return MODES_ERROR_SYSTEM; + } + } + return MODES_ERROR_NONE; +} + +void VconfPlugin::vconfChangedCallback(keynode_t *node, void *userData) +{ + CallbackData *cbData = (CallbackData*)userData; + + RET_IF(NULL == userData); + + auto found = callbackMap.find(node->keyname); + if (&(found->second) != cbData) { + ERR("Unknown callbackData(%s)", node->keyname); + return; + } + + cbData->callback(node->keyname, cbData->userData); + DBG("Action(%s) is Changed", node->keyname); + + callbackMap.erase(found); + int ret = vconf_ignore_key_changed(node->keyname, VconfPlugin::vconfChangedCallback); + if (VCONF_OK != ret) + ERR("vconf_ignore_key_changed(%s) Fail(%s)", node->keyname, get_error_message(ret)); +}