#include <gio/gio.h>
+#include <sqlite3.h>
#include <memory>
#include <string>
#include <list>
+#include <dlog.h>
+#include <app_common.h>
#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 {
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;
const std::string& default_provider_id,
ComplicationType default_type,
std::shared_ptr<IEditable::Geometry> geo);
+ int FindCandidateDataIdx(std::string provider_id, int type);
+ void RestoreStateOrSetDefault();
+ void StoreSetting(int comp_id, char* provider_id, int type);
+ std::unique_ptr<Bundle> 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_;
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
#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,
: 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<std::string> provider_list =
- parent_->GetProviderList(static_cast<ComplicationType>(type));
+ parent_->GetProviderList(static_cast<ComplicationType>(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);
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<Bundle> 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<ComplicationType>(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<Bundle> Complication::Impl::LoadSetting() {
+ char query[QUERY_MAXLEN];
+ std::unique_ptr<Bundle> 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<const char*>(sqlite3_column_text(stmt, 0));
+ setting_data = std::unique_ptr<Bundle>(new Bundle(std::string(raw_data)));
+ }
+ sqlite3_finalize(stmt);
+
+ return std::move(setting_data);
+}
+
int Complication::GetId() {
return impl_->complication_id_;
}
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<ComplicationType>(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_,
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_;
}
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