From 5009ca29eb84bd5f1b67d4c6461663bde2ebbac2 Mon Sep 17 00:00:00 2001 From: hyunho Date: Thu, 22 Feb 2018 14:35:23 +0900 Subject: [PATCH] Store previous complication state in DB Change-Id: I1d2f1cb176a3507a96ff0b833e3f0248e8ed8c07 Signed-off-by: hyunho --- packaging/libwatchface-complication.spec | 1 + watchface-complication/CMakeLists.txt | 1 + .../complication-implementation.h | 39 ++++- watchface-complication/complication.cc | 185 +++++++++++++++++++-- watchface-complication/complication.h | 4 + .../include/watchface-complication.h | 8 +- watchface-complication/watchface-complication.cc | 49 ++++++ 7 files changed, 273 insertions(+), 14 deletions(-) diff --git a/packaging/libwatchface-complication.spec b/packaging/libwatchface-complication.spec index 9d51b3c..a51497d 100644 --- a/packaging/libwatchface-complication.spec +++ b/packaging/libwatchface-complication.spec @@ -19,6 +19,7 @@ BuildRequires: pkgconfig(sqlite3) BuildRequires: pkgconfig(libxml-2.0) BuildRequires: pkgconfig(gmock) BuildRequires: pkgconfig(appsvc) +BuildRequires: pkgconfig(capi-appfw-app-common) %description API for creating a new watchface complication and managing it. diff --git a/watchface-complication/CMakeLists.txt b/watchface-complication/CMakeLists.txt index d7d4b5a..6c70cb3 100644 --- a/watchface-complication/CMakeLists.txt +++ b/watchface-complication/CMakeLists.txt @@ -17,6 +17,7 @@ pkg_check_modules(watchface-complication REQUIRED dlog aul appsvc + capi-appfw-app-common ) FOREACH(flag ${watchface-complication_CFLAGS}) diff --git a/watchface-complication/complication-implementation.h b/watchface-complication/complication-implementation.h index 68fb345..d4f25f3 100644 --- a/watchface-complication/complication-implementation.h +++ b/watchface-complication/complication-implementation.h @@ -19,13 +19,22 @@ #include +#include #include #include #include +#include +#include #include "watchface-complication/complication.h" #include "watchface-complication/complication-connector.h" +#ifdef LOG_TAG +#undef LOG_TAG +#endif + +#define LOG_TAG "WATCHFACE_COMPLICATION" + namespace watchface_complication { class Complication::Impl : ComplicationConnector::IEventListener { @@ -35,7 +44,10 @@ class Complication::Impl : ComplicationConnector::IEventListener { const std::string& interface_name, const std::string& signal_name, GVariant* parameters) override; - virtual ~Impl() = default; + virtual ~Impl() { + if (setting_db_ != NULL) + sqlite3_close(setting_db_); + } private: friend class Complication; @@ -44,6 +56,28 @@ class Complication::Impl : ComplicationConnector::IEventListener { const std::string& default_provider_id, ComplicationType default_type, std::shared_ptr geo); + int FindCandidateDataIdx(std::string provider_id, int type); + void RestoreStateOrSetDefault(); + void StoreSetting(int comp_id, char* provider_id, int type); + std::unique_ptr LoadSetting(); + void OpenSettingDataDB(); + + static std::string GetSettingDataPath() { + char* app_data_path = app_get_data_path(); + char setting_data_path[PATH_MAX] = {0, }; + + if (app_data_path == NULL) { + LOGE("fail to get app data path"); + return nullptr; + } + + snprintf(setting_data_path, PATH_MAX, "%s.watchface_setting.db", + app_data_path); + LOGI("get setting data path %s", setting_data_path); + free(app_data_path); + + return std::string(setting_data_path); + } private: Complication* parent_; @@ -60,6 +94,9 @@ class Complication::Impl : ComplicationConnector::IEventListener { EditableShapeType shape_type_; std::string name_; int subscribe_id_; + sqlite3* setting_db_ = NULL; + static const std::string provider_id_key_; + static const std::string provider_type_key_; }; } // namespace watchface_complication diff --git a/watchface-complication/complication.cc b/watchface-complication/complication.cc index 85f02d2..9360a1d 100644 --- a/watchface-complication/complication.cc +++ b/watchface-complication/complication.cc @@ -28,9 +28,12 @@ #define LOG_TAG "WATCHFACE_COMPLICATION" #define MAX_PACKAGE_STR_SIZE 512 +#define QUERY_MAXLEN 4096 namespace watchface_complication { +const std::string Complication::Impl::provider_id_key_ = "__PROVIDER_ID_KEY__"; +const std::string Complication::Impl::provider_type_key_ = "__PROVIDER_TYPE_KEY__"; Complication::Complication(int id, int support_types, const std::string& default_provider_id, ComplicationType default_type, @@ -51,25 +54,21 @@ Complication::Impl::Impl(Complication* parent, int id, : parent_(parent), complication_id_(id), support_types_(support_types), default_provider_id_(default_provider_id), default_type_(default_type), geo_(geo) { - // TODO(?): Make candidates using support_types + // TODO(?): Make candidates using DB (support_types) for (int type = ShortText; type <= Image; type *= 2 ) { if ((type & support_types_) == 0) continue; std::list provider_list = - parent_->GetProviderList(static_cast(type)); + parent_->GetProviderList(static_cast(type)); for (auto& provider_id : provider_list) { bundle* data = bundle_create(); - bundle_add_str(data, "PROVIDER_ID", provider_id.c_str()); - bundle_add_str(data, "PROVIDER_SUPPORT_TYPE", std::to_string(type).c_str()); + bundle_add_str(data, provider_id_key_.c_str(), provider_id.c_str()); + bundle_add_str(data, provider_type_key_.c_str(), std::to_string(type).c_str()); candidates_list_.emplace_back(new Bundle(data)); bundle_free(data); } } - - // TODO(?): Get previous provider id from storage - cur_provider_id_ = default_provider_id_; - cur_type_ = default_type_; - + RestoreStateOrSetDefault(); subscribe_id_ = ComplicationConnector::GetInst().SubscribeSignal( ComplicationConnector::Complication, cur_provider_id_, complication_id_, this); @@ -95,6 +94,139 @@ void Complication::Impl::OnSignal(const std::string& sender_name, parent_->OnDataUpdated(std::string(provider_id), cur_type_, data); } +int Complication::Impl::FindCandidateDataIdx(std::string provider_id, int type) { + int idx = 0; + int ret = -1; + for (auto& i : candidates_list_) { + char* temp_provider_id = NULL; + char* temp_type = NULL; + Bundle& data = *(i.get()); + bundle_get_str(data.GetRaw(), provider_id_key_.c_str(), &temp_provider_id); + bundle_get_str(data.GetRaw(), provider_type_key_.c_str(), &temp_type); + if (temp_provider_id != NULL && temp_type != NULL) { + if (strcmp(temp_provider_id, provider_id.c_str()) == 0 + && atoi(temp_type) == type) { + ret = idx; + LOGI("find cur idx %d", ret); + break; + } + } + idx++; + } + return ret; +} + +void Complication::Impl::OpenSettingDataDB() { + int ret = SQLITE_OK; + int open_flags = (SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE); + + if (setting_db_ != NULL) { + LOGI("setting db already exist"); + return; + } + std::string table_command = + "CREATE TABLE IF NOT EXISTS complication_setting" \ + "(complication_id INTEGER NOT NULL, setting_data TEXT NOT NULL, "\ + "PRIMARY KEY(complication_id))"; + std::string db_path = GetSettingDataPath(); + + ret = sqlite3_open_v2(db_path.c_str(), &setting_db_, open_flags, NULL); + if (ret != SQLITE_OK) { + LOGE("database creation failed with error: %d", ret); + return; + } + ret = sqlite3_exec(setting_db_, table_command.c_str(), NULL, NULL, NULL); + if (ret != SQLITE_OK) + LOGE("database table creation failed: %d", ret); +} + +void Complication::Impl::RestoreStateOrSetDefault() { + char* prev_provider_id = NULL; + char* prev_provider_type = NULL; + std::unique_ptr setting_data = LoadSetting(); + int ret; + + if (setting_data == nullptr) { + cur_provider_id_ = default_provider_id_; + cur_type_ = default_type_; + } else { + bundle_get_str(setting_data.get()->GetRaw(), provider_id_key_.c_str(), + &prev_provider_id); + if (prev_provider_id != NULL) + cur_provider_id_ = std::string(prev_provider_id); + else + cur_provider_id_ = default_provider_id_; + + bundle_get_str(setting_data.get()->GetRaw(), provider_type_key_.c_str(), + &prev_provider_type); + if (prev_provider_type != NULL) + cur_type_ = static_cast(atoi(prev_provider_type)); + else + cur_type_ = default_type_; + + LOGI("get setting from bundle %s, %s", prev_provider_id, prev_provider_type); + } + + cur_data_idx_ = 0; + ret = FindCandidateDataIdx(cur_provider_id_, cur_type_); + if (ret != -1) + cur_data_idx_ = ret; +} + +void Complication::Impl::StoreSetting(int comp_id, char* provider_id, int type) { + int r; + char* error = NULL; + char query[QUERY_MAXLEN]; + bundle* setting_data = bundle_create(); + bundle_raw* raw_data; + int raw_len; + char buf[32]; + + snprintf(buf, sizeof(buf), "%d", type); + bundle_add_str(setting_data, provider_id_key_.c_str(), provider_id); + bundle_add_str(setting_data, provider_type_key_.c_str(), buf); + bundle_encode(setting_data, &raw_data, &raw_len); + sqlite3_snprintf(QUERY_MAXLEN, query, + "INSERT OR REPLACE INTO complication_setting(complication_id, " \ + "setting_data)" \ + "VALUES (%d, %Q)", + comp_id, raw_data); + LOGI("complication setting insert sql : %s", query); + r = sqlite3_exec(setting_db_, query, NULL, NULL, &error); + if (r != SQLITE_OK) { + LOGE("sqlite3_exec error(query = %s, error = %s)", query, error); + sqlite3_free(error); + } +} + +std::unique_ptr Complication::Impl::LoadSetting() { + char query[QUERY_MAXLEN]; + std::unique_ptr setting_data = nullptr; + const char* raw_data; + sqlite3_stmt* stmt; + int ret; + + OpenSettingDataDB(); + sqlite3_snprintf(QUERY_MAXLEN, query, + "SELECT setting_data FROM complication_setting WHERE " \ + "complication_id = %d ", complication_id_); + LOGI("complication setting select sql : %s", query); + ret = sqlite3_prepare_v2(setting_db_, query, strlen(query), &stmt, NULL); + if (ret != SQLITE_OK) { + LOGE("execute query = %s fail %s\n", query, sqlite3_errmsg(setting_db_)); + sqlite3_close_v2(setting_db_); + return nullptr; + } + + if (sqlite3_step(stmt) == SQLITE_ROW) { + raw_data = reinterpret_cast(sqlite3_column_text(stmt, 0)); + setting_data = std::unique_ptr(new Bundle(std::string(raw_data))); + } + sqlite3_finalize(stmt); + + return std::move(setting_data); +} + int Complication::GetId() { return impl_->complication_id_; } @@ -147,13 +279,16 @@ int Complication::SetCurDataIdx(int cur_data_idx) { impl_->cur_data_idx_ = cur_data_idx; Bundle& data = GetCurData(); - bundle_get_str(data.GetRaw(), "PROVIDER_ID", &provider_id); - bundle_get_str(data.GetRaw(), "PROVIDER_SUPPORT_TYPE", &type); + bundle_get_str(data.GetRaw(), impl_->provider_id_key_.c_str(), &provider_id); + bundle_get_str(data.GetRaw(), impl_->provider_type_key_.c_str(), &type); impl_->cur_provider_id_ = std::string(provider_id); impl_->cur_type_ = static_cast(atoi(type)); LOGI("cur idx %d, cur provider %s, cur type %d", impl_->cur_data_idx_, impl_->cur_provider_id_.c_str(), impl_->cur_type_); + impl_->StoreSetting(impl_->complication_id_, provider_id, atoi(type)); + LOGI("set %s, %d", provider_id, atoi(type)); + ComplicationConnector::GetInst().UnSubscribeSignal(impl_->subscribe_id_); impl_->subscribe_id_ = ComplicationConnector::GetInst().SubscribeSignal( ComplicationConnector::Complication, impl_->cur_provider_id_, @@ -163,6 +298,26 @@ int Complication::SetCurDataIdx(int cur_data_idx) { return 0; } +const char* Complication::GetCurProviderId() { + char* provider_id = NULL; + Bundle& data = GetCurData(); + bundle_get_str(data.GetRaw(), impl_->provider_id_key_.c_str(), &provider_id); + + return provider_id; +} + +int Complication::GetCurType() { + char* type; + int ret = -1; + Bundle& data = GetCurData(); + bundle_get_str(data.GetRaw(), impl_->provider_type_key_.c_str(), &type); + + if (type) + ret = atoi(type); + + return ret; +} + const std::string& Complication::GetName() { return impl_->name_; } @@ -226,4 +381,12 @@ void Complication::SendDataUpdateRequest() { LOGI("emit signal done"); } +const char* Complication::GetProviderIdKey() { + return Complication::Impl::provider_id_key_.c_str(); +} + +const char* Complication::GetProviderTypeKey() { + return Complication::Impl::provider_type_key_.c_str(); +} + } // namespace watchface_complication diff --git a/watchface-complication/complication.h b/watchface-complication/complication.h index 61fa40e..08e53a5 100644 --- a/watchface-complication/complication.h +++ b/watchface-complication/complication.h @@ -44,6 +44,8 @@ class EXPORT_API Complication : public IEditable Bundle& GetCurData() override; Bundle& GetNthData(int nth) override; int GetCurDataIdx() override; + const char* GetCurProviderId(); + int GetCurType(); const std::string& GetName() override; const IEditable::EditableShapeType GetShapeType() override; int SetCurData(Bundle* data) override; @@ -60,6 +62,8 @@ class EXPORT_API Complication : public IEditable void SetShapeType(IEditable::EditableShapeType shape_type); std::list GetProviderList( ComplicationType type); + static const char* GetProviderIdKey(); + static const char* GetProviderTypeKey(); private: class Impl; diff --git a/watchface-complication/include/watchface-complication.h b/watchface-complication/include/watchface-complication.h index 72f8a1f..9775906 100644 --- a/watchface-complication/include/watchface-complication.h +++ b/watchface-complication/include/watchface-complication.h @@ -45,8 +45,8 @@ typedef int (*on_complication_update)(int complication_id, const bundle *data, void *user_data); -int complication_get_cur_provider(complication_h handle, - const char *cur_provider); +int complication_get_cur_provider_id(complication_h handle, + const char **cur_provider); int complication_get_cur_type(complication_h handle, complication_type *cur_type); int complication_get_support_types(complication_h handle, int *support_types); @@ -63,6 +63,10 @@ int complication_create(int complication_id, const char *default_provider_id, complication_shape_type type, complication_h *created_handle); int complication_destroy(complication_h handle); +int complication_get_provider_id(const bundle *candidate, + const char **provider_id); +int complication_get_type(const bundle *candidate, + complication_type *cur_type); #ifdef __cplusplus } diff --git a/watchface-complication/watchface-complication.cc b/watchface-complication/watchface-complication.cc index 7d1a8f1..9477562 100644 --- a/watchface-complication/watchface-complication.cc +++ b/watchface-complication/watchface-complication.cc @@ -146,6 +146,7 @@ extern "C" EXPORT_API int complication_create(int complication_id, const char *default_provider_id, complication_type default_type, int support_types, complication_shape_type shape_type, complication_h *created_handle) { + // TODO(?) check default value and type is valid auto ws = new WatchComplicationStub( complication_id, support_types, @@ -167,3 +168,51 @@ extern "C" EXPORT_API int complication_destroy(complication_h handle) { return 0; } + +extern "C" EXPORT_API int complication_get_cur_provider_id(complication_h handle, + const char** cur_provider_id) { + auto sh = static_cast*>(handle); + auto ptr = SharedHandle::Share(sh); + *cur_provider_id = ptr.get()->GetCurProviderId(); + + return 0; +} + +extern "C" EXPORT_API int complication_get_cur_type(complication_h handle, + complication_type* cur_type) { + auto sh = static_cast*>(handle); + auto ptr = SharedHandle::Share(sh); + int ret = ptr.get()->GetCurType(); + if (ret != -1) + *cur_type = static_cast(ret); + + return 0; +} + +extern "C" EXPORT_API int complication_get_provider_id(const bundle* candidate, + const char** provider_id) { + char* val = NULL; + + bundle_get_str(const_cast(candidate), + Complication::GetProviderIdKey(), &val); + if (val != NULL) + *provider_id = val; + else + return -1; + + return 0; +} + +extern "C" EXPORT_API int complication_get_type(const bundle* candidate, + complication_type* cur_type) { + char* val = NULL; + + bundle_get_str(const_cast(candidate), + Complication::GetProviderTypeKey(), &val); + if (val != NULL) + *cur_type = static_cast(atoi(val)); + else + return -1; + + return 0; +} \ No newline at end of file -- 2.7.4