--- /dev/null
+/*
+ * Copyright 2017 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 "VConf.hpp"
+
+#include <vconf.h>
+#include <unordered_map>
+#include <tuple>
+#include <map>
+#include <limits>
+
+namespace
+{
+ template <class ValueType>
+ using CallbackMap = std::map<int, std::function<void(ValueType)>>;
+ template <class ValueType>
+ using KeyMap = std::unordered_map<std::string, CallbackMap<ValueType>>;
+ static std::string inCallbackKeyGuard;
+
+ static int idxCurrent = std::numeric_limits<int>::max();
+ static KeyMap<int> intCallbackMap;
+ static KeyMap<bool> boolCallbackMap;
+ static KeyMap<double> doubleCallbackMap;
+ static KeyMap<std::string> stringCallbackMap;
+
+ template<class KeyMapType, class VconfCbType, class CallbackType>
+ inline int vconfRegisterKeyChangedCb(KeyMapType &keyMap, VconfCbType &vconfCb, const std::string &key, CallbackType &&callback)
+ {
+ auto idx = --idxCurrent;
+ auto iterator = keyMap.find(key);
+ if (iterator == keyMap.end()) {
+ iterator = keyMap.emplace(key, typename KeyMapType::mapped_type()).first;
+ if (vconf_notify_key_changed(key.c_str(), vconfCb, &iterator->second) != VCONF_OK) {
+ ERROR("Vconf: cant register callback for key: %s", key.c_str());
+ return idx;
+ }
+ }
+ iterator->second.emplace(idx, callback);
+ return idx;
+ }
+
+ template<class KeyMapType, class VconfCbType>
+ inline void vconfUnregisterCb(KeyMapType &keyMap, VconfCbType &vconfCb, const std::string &key, int idx)
+ {
+ auto iterator = keyMap.find(key);
+ if (iterator == keyMap.end()) {
+ ERROR("Vconf: unregister, key: %s not found", key.c_str());
+ return;
+ }
+ if (iterator->second.erase(idx) != 1)
+ ERROR("Vconf: could not remove callback for key: %s with idx: %d", key.c_str(), idx);
+ if (iterator->second.empty() && inCallbackKeyGuard != key) {
+ keyMap.erase(iterator);
+ if (vconf_ignore_key_changed(key.c_str(), vconfCb) != VCONF_OK) {
+ ERROR("Vconf: cant unregister callback for key: %s", key.c_str());
+ }
+ }
+ }
+
+
+
+ template<class KeyMapType, class VconfCbType, class vconfGetType>
+ inline void vconfCbRun(KeyMapType &keyMap, VconfCbType &vconfCb, const vconfGetType &vconfGetFunction, const char *expectedType, int vconfType, keynode_t *keynode, void *data)
+ {
+ std::string key = vconf_keynode_get_name(keynode);
+ if (vconf_keynode_get_type(keynode) != vconfType) {
+ ERROR("vconf error: got '%s' changed with type: %d, expected type: %s", key.c_str(), vconf_keynode_get_type(keynode), expectedType);
+ return;
+ }
+ auto value = vconfGetFunction(keynode);
+ auto callbackMapPtr = (typename KeyMapType::mapped_type *)data;
+ ASSERT(!callbackMapPtr->empty(), "vconf error: no callbacks registered");
+
+ //we allow register and unregister callbacks during a callback call
+ {
+ //make sure we don't delete callbackMap during callbacks execution
+ inCallbackKeyGuard = key;
+ int idx = 0;
+ typename KeyMapType::mapped_type::iterator callbackIterator;
+ while ((callbackIterator = callbackMapPtr->upper_bound(idx)) != callbackMapPtr->end()) {
+ idx = callbackIterator->first;
+ auto callback = callbackIterator->second;
+ callback(value);
+ }
+ inCallbackKeyGuard.clear();
+ if (callbackMapPtr->empty()) {
+ //all callbacks removed
+ keyMap.erase(key);
+ if (vconf_ignore_key_changed(key.c_str(), vconfCb) != VCONF_OK) {
+ ERROR("Vconf: cant unregister callback for key: %s", key.c_str());
+ }
+ }
+ }
+ }
+
+ void vconfIntCb(keynode_t *key, void *data)
+ {
+ vconfCbRun(intCallbackMap, vconfIntCb, vconf_keynode_get_int, "int", VCONF_TYPE_INT, key, data);
+ }
+ void vconfBoolCb(keynode_t *key, void *data)
+ {
+ vconfCbRun(boolCallbackMap, vconfBoolCb, vconf_keynode_get_bool, "bool", VCONF_TYPE_BOOL, key, data);
+ }
+ void vconfDoubleCb(keynode_t *key, void *data)
+ {
+ vconfCbRun(doubleCallbackMap, vconfDoubleCb, vconf_keynode_get_dbl, "double", VCONF_TYPE_DOUBLE, key, data);
+ }
+ void vconfStringCb(keynode_t *key, void *data)
+ {
+ vconfCbRun(stringCallbackMap, vconfStringCb, vconf_keynode_get_str, "char*", VCONF_TYPE_STRING, key, data);
+ }
+}
+
+
+class VConfImpl : public VConfInterface
+{
+public:
+ enum class VConfRecordType {INT, BOOL, DOUBLE, STRING};
+
+ struct Handle : public HandleBase {
+ std::string key;
+ int callbackIdx;
+ VConfRecordType vconfRecordType;
+
+ Handle(std::string key, int callbackIdx, VConfRecordType vconfRecordType)
+ : key{std::move(key)}, callbackIdx{callbackIdx}, vconfRecordType{vconfRecordType}
+ {}
+
+ ~Handle() override
+ {
+ switch (vconfRecordType) {
+ case VConfRecordType::INT:
+ vconfUnregisterCb(intCallbackMap, vconfIntCb, key, callbackIdx);
+ break;
+ case VConfRecordType::BOOL:
+ vconfUnregisterCb(boolCallbackMap, vconfBoolCb, key, callbackIdx);
+ break;
+ case VConfRecordType::DOUBLE:
+ vconfUnregisterCb(doubleCallbackMap, vconfDoubleCb, key, callbackIdx);
+ break;
+ case VConfRecordType::STRING:
+ vconfUnregisterCb(stringCallbackMap, vconfStringCb, key, callbackIdx);
+ break;
+ }
+ }
+ };
+
+ int get(const std::string &key, int value) const override
+ {
+ auto k = keyPrefix + key;
+ if (vconf_get_int(k.c_str(), &value) != VCONF_OK)
+ WARNING("Vconf: cant get value for key: %s, returning default value = %d", k.c_str(), value);
+ return value;
+ }
+
+ bool get(const std::string &key, bool defaultValue) const override
+ {
+ auto k = keyPrefix + key;
+ int value = defaultValue;
+ if (vconf_get_bool(k.c_str(), &value) != VCONF_OK)
+ WARNING("Vconf: cant get value for key: %s, returning default value = %s", k.c_str(), value ? "true" : "false");
+ return value;
+ }
+
+ double get(const std::string &key, double value) const override
+ {
+ auto k = keyPrefix + key;
+ if (vconf_get_dbl(k.c_str(), &value) != VCONF_OK)
+ WARNING("Vconf: cant get value for key: %s, returning default value = %lf", k.c_str(), value);
+ return value;
+ }
+
+ std::string get(const std::string &key, const std::string &value) const override
+ {
+ auto k = keyPrefix + key;
+ char *str = vconf_get_str(k.c_str());
+ if (str)
+ return str;
+
+ WARNING("Vconf: cant get value for key: %s, returning default value = %s", k.c_str(), value.c_str());
+ return value;
+ }
+
+
+ void set(const std::string &key, int value) override
+ {
+ auto k = keyPrefix + key;
+ auto status = vconf_set_int(k.c_str(), value);
+ if (status != VCONF_OK)
+ ERROR("Vconf error %d: cant set value for key: %s, value = %d", status, k.c_str(), value);
+ }
+
+ void set(const std::string &key, bool value) override
+ {
+ auto k = keyPrefix + key;
+ auto status = vconf_set_bool(k.c_str(), (int)value);
+ if (status != VCONF_OK)
+ ERROR("Vconf error %d: cant set value for key: %s, value = %s", status, k.c_str(), value ? "true" : "false");
+ }
+
+ void set(const std::string &key, double value) override
+ {
+ auto k = keyPrefix + key;
+ auto status = vconf_set_dbl(k.c_str(), value);
+ if (status != VCONF_OK)
+ ERROR("Vconf error %d: cant set value for key: %s, value = %lf", status, k.c_str(), value);
+ }
+
+ void set(const std::string &key, const std::string &value) override
+ {
+ auto k = keyPrefix + key;
+ auto status = vconf_set_str(k.c_str(), value.c_str());
+ if (status != VCONF_OK)
+ ERROR("Vconf error %d: cant set value for key: %s, value = %s", status, k.c_str(), value.c_str());
+ }
+
+
+ CallbackHandle registerKeyChangedCb(const std::string &key, std::function<void(int)> callback) override
+ {
+ auto k = keyPrefix + key;
+ auto idx = vconfRegisterKeyChangedCb(intCallbackMap, vconfIntCb, k, std::move(callback));
+ return CallbackHandle{ new Handle{k, idx, VConfRecordType::INT} };
+ }
+
+ CallbackHandle registerKeyChangedCb(const std::string &key, std::function<void(bool)> callback) override
+ {
+ auto k = keyPrefix + key;
+ auto idx = vconfRegisterKeyChangedCb(boolCallbackMap, vconfBoolCb, k, std::move(callback));
+ return CallbackHandle{ new Handle{k, idx, VConfRecordType::BOOL} };
+ }
+
+ CallbackHandle registerKeyChangedCb(const std::string &key, std::function<void(double)> callback) override
+ {
+ auto k = keyPrefix + key;
+ auto idx = vconfRegisterKeyChangedCb(doubleCallbackMap, vconfDoubleCb, k, std::move(callback));
+ return CallbackHandle{ new Handle{k, idx, VConfRecordType::DOUBLE} };
+ }
+
+ CallbackHandle registerKeyChangedCb(const std::string &key, std::function<void(std::string)> callback) override
+ {
+ auto k = keyPrefix + key;
+ auto idx = vconfRegisterKeyChangedCb(stringCallbackMap, vconfStringCb, k, std::move(callback));
+ return CallbackHandle{ new Handle{k, idx, VConfRecordType::STRING} };
+ }
+
+ void setKeyPrefix(const std::string &prefix) override
+ {
+ keyPrefix = prefix;
+ }
+
+private:
+ std::string keyPrefix;
+};
+
+template<>
+template<>
+std::unique_ptr<VConfInterface> Singleton<VConfInterface>::createImplementation<VConfInterface>()
+{
+ return std::unique_ptr<VConfInterface> { new VConfImpl };
+}
--- /dev/null
+/*
+ * Copyright 2017 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.
+ */
+
+#ifndef VCONF_HPP
+#define VCONF_HPP
+
+#include "AccessibilitySettingLog.hpp"
+#include "Singleton.hpp"
+
+#include <string>
+#include <functional>
+#include <memory>
+
+/**
+ * Singleton<VConfInterface>::instance() is a c++ singleton wrapper around vconf.
+ *
+ * usage examples:
+ * 1. get key value:
+ * bool enabled = Singleton<VConfInterface>::instance().get("db/setting/accessibility/universal-switch", false);
+ * 2. set key value:
+ * Singleton<VConfInterface>::instance().set("db/setting/accessibility/universal-switch/FEEDBACK_VOICE_SPEECH_VOLUME", 0.50);
+ * 3. register callback on value change:
+ * auto print = [](bool enabled) { std::cout << enabled << std::endl; }
+ * CallbackHandle handle = Singleton<VConfInterface>::instance().registerKeyChangedCb("db/setting/accessibility/universal-switch", print);
+ * callback will be registered until \p handle exists.
+ * 4. register callback on value change and get current value:
+ * auto print = [](bool enabled) { std::cout << enabled << std::endl; }
+ * CallbackHandle handle = Singleton<VConfInterface>::instance().registerAndGet("db/setting/accessibility/universal-switch", print);
+ * callback will be registered until \p handle exists.
+ *
+ */
+
+class VConfInterface
+{
+public:
+ struct HandleBase {
+ virtual ~HandleBase() = default;
+ };
+
+ using CallbackHandle = std::unique_ptr<HandleBase>;
+
+ virtual int get(const std::string &key, int defaultValue) const = 0;
+
+ virtual bool get(const std::string &key, bool defaultValue) const = 0;
+
+ virtual double get(const std::string &key, double defaultValue) const = 0;
+
+ virtual std::string get(const std::string &key, const std::string &defaultValue) const = 0;
+
+ virtual void set(const std::string &key, int value) = 0;
+
+ virtual void set(const std::string &key, bool value) = 0;
+
+ virtual void set(const std::string &key, double value) = 0;
+
+ virtual void set(const std::string &key, const std::string &value) = 0;
+
+ virtual CallbackHandle registerKeyChangedCb(const std::string &key, std::function<void(int)> callback) = 0;
+
+ virtual CallbackHandle registerKeyChangedCb(const std::string &key, std::function<void(bool)> callback) = 0;
+
+ virtual CallbackHandle registerKeyChangedCb(const std::string &key, std::function<void(double)> callback) = 0;
+
+ virtual CallbackHandle registerKeyChangedCb(const std::string &key, std::function<void(std::string)> callback) = 0;
+
+ template<class T>
+ inline CallbackHandle registerKeyChangedCb(const std::string &key, std::function<void(T)> callback)
+ {
+ return registerKeyChangedCb(key, callback);
+ }
+
+ template<class T>
+ CallbackHandle registerAndGet(const std::string &key, T defaultValue, std::function<void(T)> callback)
+ {
+ auto handle = registerKeyChangedCb(key, callback);
+ callback(get(key, defaultValue));
+ return handle;
+ }
+
+ virtual void setKeyPrefix(const std::string &prefix) = 0;
+};
+
+#endif