ADD_DEPENDENCIES(watchface-editor watchface-complication)
ADD_DEPENDENCIES(watchface-complication-provider watchface-complication)
ADD_DEPENDENCIES(complication-parser watchface-complication)
+ADD_DEPENDENCIES(gtest-watchface-complication watchface-complication-provider)
BuildRequires: pkgconfig(libtzplatform-config)
BuildRequires: pkgconfig(pkgmgr-info)
BuildRequires: pkgconfig(pkgmgr-installer)
+BuildRequires: pkgconfig(capi-appfw-app-control)
%if 0%{?gcov:1}
BuildRequires: lcov
%endif
glib-2.0
dlog
gmock
+ capi-appfw-app-control
)
FOREACH(flag ${gtest-watchface-complication_CFLAGS})
string providerId = "sample_provider";
virtual void SetUp() {
- complication = new WatchComplication(0, 1, providerId.c_str(), ShortText,
+ complication = new WatchComplication(0, ShortText, providerId.c_str(), ShortText,
std::shared_ptr<IEditable::Geometry>(new IEditable::Geometry(0, 0, 100, 100)));
}
virtual void TearDown() {
EXPECT_NE(curData.GetRaw(), nullptr);
EXPECT_NE(nthData.GetRaw(), nullptr);
- EXPECT_EQ(WC::complication->GetType(curData), 1);
+ EXPECT_EQ(WC::complication->GetType(curData), ShortText);
}
TEST_F(WC, DataIdx)
gio-2.0
dlog
aul
+ capi-appfw-app-control
)
FOREACH(flag ${watchface-complication-provider_CFLAGS})
int support_types)
: parent_(parent), provider_id_(provider_id), support_types_(support_types) {
subscribe_id_ = ComplicationConnector::GetInst().SubscribeSignal(
- ComplicationConnector::Complication, provider_id_, 0, this);
+ ComplicationConnector::Complication, provider_id_, -1, this);
LOGI("subscribe signal %d", subscribe_id_);
}
#define WATCHFACE_COMPLICATION_PROVIDER_INCLUDE_WATCHFACE_COMPLICATION_PROVIDER_H_
#include <tizen.h>
+#include <app_control.h>
#include "watchface-complication/include/watchface-complication.h"
#ifdef __cplusplus
int *types);
int complication_provider_notify_update(const char *provider_id);
+/**
+ * @brief Sends reply to the editor.
+ * @details Using this API, setup app can sends new context data to the editor
+ * @since_tizen 5.0
+ * @param[in] handle The editable handle
+ * @param[in] context The new context data of complication provider.
+ * @see #complication_provider_setup_get_context
+ * @return #COMPLICATION_ERROR_NONE on success,
+ * otherwise an error code (see COMPLICATION_ERROR_XXX) on failure
+ * @retval #COMPLICATION_ERROR_NONE Successful
+ * @retval #COMPLICATION_ERROR_OUT_OF_MEMORY Out of memory
+ * @retval #COMPLICATION_ERROR_INVALID_PARAMETER Invalid parameter
+ * @par Sample code:
+ * @code
+#include <watchface-complication-provider.h>
+
+{
+ bundle *b = bundle_create();
+ bundle_add_str(b, "REGION_DATA", "KR");
+ complication_provider_setup_reply_to_editor(handle, b);
+ bundle_free(b);
+}
+ * @endcode
+ */
+int complication_provider_setup_reply_to_editor(app_control_h h, bundle *context);
+
+/**
+ * @brief Check whether watch app request editing or not.
+ * @details Using this API, setup app can tell what kind of UI should be displayed
+ *
+ * @since_tizen 5.0
+ * @param[in] handle The editable handle
+ * @param[out] is_editing The value that tell it's editing mode.
+ * @see #complication_provider_setup_reply_to_editor
+ * @return #COMPLICATION_ERROR_NONE on success,
+ * otherwise an error code (see COMPLICATION_ERROR_XXX) on failure
+ * @retval #COMPLICATION_ERROR_NONE Successful
+ * @retval #COMPLICATION_ERROR_OUT_OF_MEMORY Out of memory
+ * @retval #COMPLICATION_ERROR_INVALID_PARAMETER Invalid parameter
+ * @par Sample code:
+ * @code
+#include <watchface-complication-provider.h>
+void app_control(app_control_h app_control, void *data)
+{
+ bool is_editing;
+
+ complication_provider_setup_is_editing(handle, &is_editing);
+ if (is_editing) {
+ complication_provider_setup_get_context(handle, &b);
+ // Draw complication provider app's current setting state.
+ }
+}
+ * @endcode
+ */
+int complication_provider_setup_is_editing(
+ app_control_h handle, bool *id_editing);
+
+/**
+ * @brief Get provider app's setup context data.
+ * @details Context data will be passed to the complication provider application
+ * through the app_control event callaback's app_control_h handle parameter
+ * @since_tizen 5.0
+ * @param[in] handle The editable handle
+ * @param[out] context
+ * @see #complication_provider_setup_reply_to_editor
+ * @return #COMPLICATION_ERROR_NONE on success,
+ * otherwise an error code (see COMPLICATION_ERROR_XXX) on failure
+ * @retval #COMPLICATION_ERROR_NONE Successful
+ * @retval #COMPLICATION_ERROR_OUT_OF_MEMORY Out of memory
+ * @retval #COMPLICATION_ERROR_INVALID_PARAMETER Invalid parameter
+ * @par Sample code:
+ * @code
+#include <watchface-complication-provider.h>
+void app_control(app_control_h app_control, void *data)
+{
+ bundle *b;
+
+ complication_provider_setup_get_context(handle, &b);
+ // Draw complication provider app's current setting state.
+}
+ * @endcode
+ */
+int complication_provider_setup_get_context(app_control_h handle, bundle **context);
+
#ifdef __cplusplus
}
+
#endif
#endif // WATCHFACE_COMPLICATION_PROVIDER_INCLUDE_WATCHFACE_COMPLICATION_PROVIDER_H_
#include "watchface-complication-provider/complication-provider.h"
#include "watchface-complication-provider/include/watchface-complication-provider.h"
+#include "watchface-complication/include/watchface-complication-internal.h"
#ifdef LOG_TAG
#undef LOG_TAG
return 0;
}
+
+extern "C" EXPORT_API int complication_provider_setup_reply_to_editor(
+ app_control_h handle, bundle* context)
+{
+ char* editor_appid = NULL;
+ char* editable_id = NULL;
+ int ret;
+ int str_len = 0;
+ bundle_raw* raw_data = NULL;
+
+ ret = app_control_get_extra_data(handle, SETUP_EDITOR_APPID_KEY, &editor_appid);
+ if (ret != 0) {
+ LOGE("Fail to get editor appid");
+ return COMPLICATION_ERROR_INVALID_PARAMETER;
+ }
+
+ ret = app_control_get_extra_data(handle, SETUP_EDITABLE_ID_KEY, &editable_id);
+ if (ret != APP_CONTROL_ERROR_NONE) {
+ if (ret == APP_CONTROL_ERROR_OUT_OF_MEMORY) {
+ LOGE("Fail to get context data");
+ return COMPLICATION_ERROR_OUT_OF_MEMORY;
+ }
+ LOGE("Fail to get context data");
+ return COMPLICATION_ERROR_INVALID_PARAMETER;
+ }
+
+ if (context != NULL) {
+ ret = bundle_encode(context, &raw_data, &str_len);
+ if (ret != 0) {
+ LOGE("Fail to encode data");
+ free(editable_id);
+ free(editor_appid);
+ return COMPLICATION_ERROR_INVALID_PARAMETER;
+ }
+ }
+
+ ComplicationConnector::GetInst().EmitSignal(
+ ComplicationConnector::Editable,
+ std::string(editor_appid),
+ std::string(editor_appid), -1,
+ ComplicationConnector::GetInst().GetCmdStr(
+ ComplicationConnector::SetupReply),
+ g_variant_new("(is)", atoi(editable_id),
+ raw_data == NULL ? "" : reinterpret_cast<char*>(raw_data)));
+
+ free(editor_appid);
+ free(editable_id);
+ free(raw_data);
+
+ return COMPLICATION_ERROR_NONE;
+}
+
+extern "C" EXPORT_API int complication_provider_setup_is_editing(
+ app_control_h handle, bool* is_editing)
+{
+ char* value = NULL;
+ int ret;
+
+ if (handle == NULL) {
+ LOGE("handle is null");
+ return COMPLICATION_ERROR_INVALID_PARAMETER;
+ }
+
+ ret = app_control_get_extra_data(handle, SETUP_EDITOR_APPID_KEY, &value);
+ if (ret != APP_CONTROL_ERROR_NONE) {
+ if (ret == APP_CONTROL_ERROR_OUT_OF_MEMORY) {
+ LOGE("Fail to get context data");
+ return COMPLICATION_ERROR_OUT_OF_MEMORY;
+ }
+ LOGE("Fail to get context data");
+ return COMPLICATION_ERROR_INVALID_PARAMETER;
+ }
+
+ *is_editing = true;
+ free(value);
+
+ return COMPLICATION_ERROR_NONE;
+}
+
+extern "C" EXPORT_API int complication_provider_setup_get_context(
+ app_control_h handle, bundle** context)
+{
+ char* value = NULL;
+ bundle* data = NULL;
+ int ret;
+
+ ret = app_control_get_extra_data(handle, SETUP_CONTEXT_DATA_KEY, &value);
+ if (ret != APP_CONTROL_ERROR_NONE) {
+ if (ret == APP_CONTROL_ERROR_OUT_OF_MEMORY) {
+ LOGE("Fail to get context data");
+ return COMPLICATION_ERROR_OUT_OF_MEMORY;
+ }
+ LOGE("Fail to get context data");
+ return COMPLICATION_ERROR_INVALID_PARAMETER;
+ }
+
+ data = bundle_decode(reinterpret_cast<const bundle_raw*>(value),
+ strlen(value));
+ *context = data;
+ free(value);
+
+ return COMPLICATION_ERROR_NONE;
+}
case EditableEditReady :
ret = "__EDITABLE_EDIT_READY__";
break;
+ case SetupReply :
+ ret = "__SETUP_REPLY__";
+ break;
default :
break;
}
EditableEditComplete,
EditableEditPreview,
EditableEditCancel,
- EditableEditReady
+ EditableEditReady,
+ SetupReply
};
class IEventListener {
std::list<std::unique_ptr<Bundle>> candidates_list_;
int cur_data_idx_;
std::unique_ptr<Bundle> context_data_ = nullptr;
+ std::unique_ptr<Bundle> last_context_data_ = nullptr;
std::unique_ptr<Bundle> last_data_ = nullptr;
int last_data_idx_;
EditableShapeType shape_type_;
/* Initialize last_data_idx_ */
last_data_idx_ = cur_data_idx_;
+ if (candidates_list_.size() > 0) {
+ std::list<std::unique_ptr<Bundle>>::iterator it
+ = candidates_list_.begin();
+ auto nx = std::next(it, last_data_idx_);
+ last_data_.reset(new Bundle((*nx).get()->GetRaw()));
+ }
+
+ context_data_ = EditablesManager::GetInst().LoadContext(complication_id_,
+ cur_provider_id_.c_str());
+ if (context_data_ != nullptr)
+ last_context_data_.reset(new Bundle(context_data_.get()->GetRaw()));
}
int Complication::Impl::StoreSetting(int comp_id, std::string& provider_id,
ComplicationConnector::Complication,
provider_appid,
impl_->cur_provider_id_,
- 0,
+ -1,
ComplicationConnector::GetInst().GetCmdStr(
ComplicationConnector::CompUpdateRequest),
g_variant_new("(siis)",
return impl_->ed_state_;
}
+const std::string Complication::GetSetupAppId() {
+ // TODO(?): from db
+ return "org.tizen.comp_setting";
+}
+
+int Complication::SetContext(std::unique_ptr<Bundle> context) {
+ impl_->context_data_.reset();
+ impl_->context_data_ = std::move(context);
+ return COMPLICATION_ERROR_NONE;
+}
+
+std::unique_ptr<Bundle>& Complication::GetContext() const {
+ return impl_->context_data_;
+}
+
+int Complication::UpdateLastContext() {
+ if (impl_->context_data_.get() == NULL) {
+ LOGI("Empty context");
+ return COMPLICATION_ERROR_NONE;
+ }
+
+ int ret = EditablesManager::GetInst().StoreContext(impl_->complication_id_,
+ impl_->cur_provider_id_.c_str(), *impl_->context_data_.get());
+ if (ret != COMPLICATION_ERROR_NONE)
+ return ret;
+
+ impl_->last_context_data_.reset(new Bundle((impl_->context_data_.get())->GetRaw()));
+ return COMPLICATION_ERROR_NONE;
+}
+
+std::unique_ptr<Bundle>& Complication::GetLastContext() const {
+ return impl_->last_context_data_;
+}
+
+
} // namespace watchface_complication
void SetName(const std::string& name) override;
void SetState(IEditable::EditableState state) override;
IEditable::EditableState GetState() override;
+ int SetContext(std::unique_ptr<Bundle> context) override;
+ std::unique_ptr<Bundle>& GetContext() const override;
+ int UpdateLastContext() override;
+ std::unique_ptr<Bundle>& GetLastContext() const override;
+ const std::string GetSetupAppId() override;
int SendDataUpdateRequest();
void SetShapeType(IEditable::EditableShapeType shape_type);
std::list<std::string> GetProviderList(
EditableShapeType shape_type_;
std::string name_;
IEditable::EditableState ed_state_;
+ std::unique_ptr<Bundle> context_data_;
+ std::unique_ptr<Bundle> last_context_data_ = nullptr;
};
} // namespace watchface_complication
return impl_->ed_state_;
}
+const std::string DesignElement::GetSetupAppId() {
+ std::string setup_appid = "org.tizen.comp_setting";
+ // TODO(?) : from DB
+ return setup_appid;
+}
+
+int DesignElement::SetContext(std::unique_ptr<Bundle> context) {
+ impl_->context_data_.reset();
+ impl_->context_data_ = std::move(context);
+ return COMPLICATION_ERROR_NONE;
+}
+
+std::unique_ptr<Bundle>& DesignElement::GetContext() const {
+ return impl_->context_data_;
+}
+
+int DesignElement::UpdateLastContext() {
+ if (impl_->context_data_.get() == NULL) {
+ LOGI("Empty context");
+ return COMPLICATION_ERROR_NONE;
+ }
+ impl_->last_context_data_.reset(new Bundle((impl_->context_data_.get())->GetRaw()));
+ return COMPLICATION_ERROR_NONE;
+}
+
+std::unique_ptr<Bundle>& DesignElement::GetLastContext() const {
+ return impl_->last_context_data_;
+}
+
} // namespace watchface_complication
void SetName(const std::string& name) override;
void SetState(IEditable::EditableState state) override;
IEditable::EditableState GetState() override;
+ int SetContext(std::unique_ptr<Bundle> context) override;
+ std::unique_ptr<Bundle>& GetContext() const override;
+ int UpdateLastContext() override;
+ std::unique_ptr<Bundle>& GetLastContext() const override;
+ const std::string GetSetupAppId() override;
void SetShapeType(IEditable::EditableShapeType shape_type);
private:
virtual void OnEditableUpdated(int selected_idx, EditableState state) = 0;
virtual void SetState(EditableState state) = 0;
virtual EditableState GetState() = 0;
+ virtual const std::string GetSetupAppId() = 0;
+ virtual int SetContext(std::unique_ptr<Bundle> context) = 0;
+ virtual std::unique_ptr<Bundle>& GetContext() const = 0;
+ virtual int UpdateLastContext() = 0;
+ virtual std::unique_ptr<Bundle>& GetLastContext() const = 0;
};
} // namespace watchface_complication
public:
virtual void OnRequestEdit(const std::string& appid,
std::list<std::unique_ptr<IEditable>> e_list) = 0;
+ virtual void OnSetupReply(int editable_id, std::unique_ptr<Bundle> context) = 0;
};
} // namespace watchface_complication
GVariant* parameters) override;
void OnVanish(const std::string& name) override;
void OnAppear(const std::string& name, const std::string& name_owner) override;
+ void CancelEditing();
explicit Impl(EditablesContainer* parent);
Impl(Impl const& other) = default;
Impl(Impl && other) = default;
: parent_(parent) {
subscribe_id_ = ComplicationConnector::GetInst().SubscribeSignal(
ComplicationConnector::Editable,
- ComplicationConnector::GetInst().GetAppId(), 0, this);
+ ComplicationConnector::GetInst().GetAppId(), -1, this);
LOGI("subscribe signal %d", subscribe_id_);
}
ComplicationConnector::EditableEditPreview)) == 0) {
int editable_id;
int selected_idx;
- g_variant_get(parameters, "(ii)", &selected_idx, &editable_id);
+ char *context = NULL;
+ std::string ctx_str;
+
+ g_variant_get(parameters, "(iis)", &selected_idx, &editable_id, &context);
LOGI("preview selected_idx, editable_id, state: %d, %d", selected_idx,
editable_id);
+
+ if (context != NULL)
+ ctx_str = std::string(context);
for (auto& i : ed_list_) {
if (i.get()->GetId() == editable_id) {
i.get()->SetState(IEditable::OnGoing);
i.get()->SetCurDataIdx(selected_idx);
+ if (!ctx_str.empty())
+ i.get()->SetContext(std::unique_ptr<Bundle>(new Bundle(ctx_str)));
i.get()->OnEditableUpdated(i.get()->GetCurDataIdx(), IEditable::OnGoing);
parent_->OnUpdate(*i.get(), i.get()->GetCurDataIdx(), IEditable::OnGoing);
}
i.get()->SetState(IEditable::Complete);
i.get()->SetCurDataIdx(i.get()->GetCurDataIdx());
i.get()->UpdateLastDataIdx();
+ i.get()->UpdateLastContext();
i.get()->OnEditableUpdated(i.get()->GetCurDataIdx(), IEditable::Complete);
parent_->OnUpdate(*i.get(), i.get()->GetCurDataIdx(), IEditable::Complete);
}
- } else if (signal_name.compare(
- ComplicationConnector::GetInst().GetCmdStr(
+ } else if (signal_name.compare(ComplicationConnector::GetInst().GetCmdStr(
ComplicationConnector::EditableEditCancel)) == 0) {
- for (auto& i : ed_list_) {
- i.get()->SetState(IEditable::Cancel);
- i.get()->SetCurDataIdx(i.get()->GetLastDataIdx());
- i.get()->OnEditableUpdated(i.get()->GetCurDataIdx(), IEditable::Cancel);
- parent_->OnUpdate(*i.get(), i.get()->GetCurDataIdx(), IEditable::Cancel);
- }
+ CancelEditing();
}
}
-void EditablesContainer::Impl::OnVanish(const std::string& name) {
+void EditablesContainer::Impl::CancelEditing() {
for (auto& i : ed_list_) {
if (i.get()->GetState() != IEditable::Complete) {
i.get()->SetState(IEditable::Cancel);
i.get()->SetCurDataIdx(i.get()->GetLastDataIdx());
+ if (i.get()->GetLastContext().get() != NULL) {
+ i.get()->SetContext(std::unique_ptr<Bundle>(
+ new Bundle(i.get()->GetLastContext().get()->GetRaw())));
+ } else {
+ i.get()->SetContext(std::unique_ptr<Bundle>{});
+ }
i.get()->OnEditableUpdated(i.get()->GetCurDataIdx(), IEditable::Cancel);
parent_->OnUpdate(*i.get(), i.get()->GetCurDataIdx(), IEditable::Cancel);
}
}
}
+void EditablesContainer::Impl::OnVanish(const std::string& name) {
+ CancelEditing();
+}
+
void EditablesContainer::Impl::OnAppear(const std::string& name,
const std::string& name_owner) {
}
ComplicationConnector::Editable,
editor_id,
editor_id,
- 0,
+ -1,
ComplicationConnector::GetInst().GetCmdStr(
ComplicationConnector::EditableEditRequest),
g_variant_new("(ss)",
virtual void OnUpdate(const IEditable& ed, int selected_idx,
IEditable::EditableState state);
void OnEditReady(const std::string& editor_id) override;
+
private:
class Impl;
std::unique_ptr<Impl> impl_;
virtual ~Impl() {
if (setting_db_ != NULL)
sqlite3_close(setting_db_);
+ if (context_db_ != NULL)
+ sqlite3_close(context_db_);
};
private:
friend class EditablesManager;
Impl();
- static std::string GetSettingDataPath() {
+ static std::string GetEditablesDataPath() {
char* app_data_path = app_get_data_path();
char setting_data_path[PATH_MAX] = {0, };
if (app_data_path != NULL) {
- snprintf(setting_data_path, PATH_MAX, "%s.watchface_editables_setting.db",
+ snprintf(setting_data_path, PATH_MAX, "%s.watchface_editables.db",
app_data_path);
LOGI("get setting data path %s", setting_data_path);
free(app_data_path);
private:
sqlite3* setting_db_ = NULL;
+ sqlite3* context_db_ = NULL;
};
} // namespace watchface_complication
LOGI("setting db already exist");
return;
}
- std::string table_command =
+ std::string context_table_command =
+ "CREATE TABLE IF NOT EXISTS editable_context" \
+ "(editable_id INTEGER NOT NULL, provider_id TEXT NOT NULL, "\
+ "context_data TEXT NULL, "\
+ "PRIMARY KEY(editable_id, provider_id))";
+
+ std::string setting_table_command =
"CREATE TABLE IF NOT EXISTS editable_setting" \
"(editable_id INTEGER NOT NULL, setting_data TEXT NOT NULL, "\
- "context_data TEXT NULL, "\
"PRIMARY KEY(editable_id))";
- std::string db_path = impl_->GetSettingDataPath();
+ std::string db_path = impl_->GetEditablesDataPath();
if (db_path.empty()) {
LOGE("GetSettingDataPath failed");
return;
LOGE("database creation failed with error: %d", ret);
return;
}
- ret = sqlite3_exec(impl_->setting_db_, table_command.c_str(), NULL, NULL, NULL);
+ ret = sqlite3_exec(impl_->setting_db_, setting_table_command.c_str(),
+ NULL, NULL, NULL);
+ if (ret != SQLITE_OK)
+ LOGE("database setting table creation failed: %d", ret);
+
+ ret = sqlite3_open_v2(db_path.c_str(), &impl_->context_db_, open_flags, NULL);
+ if (ret != SQLITE_OK) {
+ LOGE("database creation failed with error: %d", ret);
+ return;
+ }
+ ret = sqlite3_exec(impl_->context_db_, context_table_command.c_str(),
+ NULL, NULL, NULL);
if (ret != SQLITE_OK)
- LOGE("database table creation failed: %d", ret);
+ LOGE("database context table creation failed: %d", ret);
}
int EditablesManager::StoreSetting(int editable_id, bundle_raw* raw_data) {
return std::move(setting_data);
}
+int EditablesManager::StoreContext(int editable_id, const char* provider_id,
+ Bundle& context) {
+ int r;
+ char* error = NULL;
+ char query[QUERY_MAXLEN] = {0, };
+
+ if (impl_->setting_db_ == NULL) {
+ LOGE("DB is not initialized.");
+ return COMPLICATION_ERROR_IO_ERROR;
+ }
+
+ sqlite3_snprintf(QUERY_MAXLEN, query,
+ "INSERT OR REPLACE INTO editable_context(editable_id, provider_id, " \
+ "context_data) " \
+ "VALUES (%d, %Q, %Q)",
+ editable_id, provider_id, context.ToString());
+ LOGI("editables context insert sql : %s", query);
+ r = sqlite3_exec(impl_->context_db_, query, NULL, NULL, &error);
+ if (r != SQLITE_OK) {
+ LOGE("sqlite3_exec error(query = %s, error = %s)", query, error);
+ sqlite3_free(error);
+ return COMPLICATION_ERROR_IO_ERROR;
+ }
+ return COMPLICATION_ERROR_NONE;
+}
+
+std::unique_ptr<Bundle> EditablesManager::LoadContext(int editable_id,
+ const char* provider_id) {
+ char query[QUERY_MAXLEN];
+ std::unique_ptr<Bundle> context_data = nullptr;
+ const char* raw_data;
+ sqlite3_stmt* stmt;
+ int ret;
+
+ if (impl_->context_db_ == NULL) {
+ return nullptr;
+ }
+
+ sqlite3_snprintf(QUERY_MAXLEN, query,
+ "SELECT context_data FROM editable_context WHERE " \
+ "editable_id = %d AND provider_id = %Q ", editable_id, provider_id);
+ LOGI("editable context select sql : %s", query);
+ ret = sqlite3_prepare_v2(impl_->context_db_,
+ query, strlen(query), &stmt, NULL);
+ if (ret != SQLITE_OK) {
+ LOGE("execute query = %s fail %s\n",
+ query, sqlite3_errmsg(impl_->context_db_));
+ sqlite3_close_v2(impl_->context_db_);
+ return nullptr;
+ }
+
+ if (sqlite3_step(stmt) == SQLITE_ROW) {
+ raw_data = reinterpret_cast<const char*>(sqlite3_column_text(stmt, 0));
+ context_data = std::unique_ptr<Bundle>(new Bundle(std::string(raw_data)));
+ }
+ sqlite3_finalize(stmt);
+
+ return std::move(context_data);
+}
+
+
} // namespace watchface_complication
static EditablesManager& GetInst();
int StoreSetting(int editable_id, bundle_raw* raw_data);
std::unique_ptr<Bundle> LoadSetting(int editable_id);
+ int StoreContext(int editable_id, const char* provider_id, Bundle& context);
+ std::unique_ptr<Bundle> LoadContext(int editable_id, const char* provider_id);
private:
EditablesManager();
#include "watchface-complication/include/watchface-common.h"
+#define SETUP_EDITOR_APPID_KEY "__SETUP_EDITOR_APPID_KEY__"
+#define SETUP_EDITABLE_ID_KEY "__SETUP_EDITABLE_ID_KEY__"
+#define SETUP_CONTEXT_DATA_KEY "__SETUP_CONTEXT_DATA_KEY__"
+
namespace watchface_complication {
typedef enum {
int cur_data_idx_;
int last_data_idx_;
IEditable::EditableState ed_state_;
+ std::unique_ptr<Bundle> context_data_;
+ std::unique_ptr<Bundle> last_context_data_ = nullptr;
};
} // namespace watchface_complication
return impl_->ed_state_;
}
+const std::string ReceivedEditable::GetSetupAppId() {
+ // TODO(?): from db
+ return "org.tizen.comp_setting";
+}
+
+int ReceivedEditable::SetContext(std::unique_ptr<Bundle> context) {
+ impl_->context_data_.reset();
+ impl_->context_data_ = std::move(context);
+ return COMPLICATION_ERROR_NONE;
+}
+
+std::unique_ptr<Bundle>& ReceivedEditable::GetContext() const {
+ return impl_->context_data_;
+}
+
+int ReceivedEditable::UpdateLastContext() {
+ if (impl_->context_data_.get() == NULL) {
+ LOGI("Empty context");
+ return COMPLICATION_ERROR_NONE;
+ }
+ impl_->last_context_data_.reset(new Bundle((impl_->context_data_.get())->GetRaw()));
+ return COMPLICATION_ERROR_NONE;
+}
+
+std::unique_ptr<Bundle>& ReceivedEditable::GetLastContext() const {
+ return impl_->last_context_data_;
+}
+
} // namespace watchface_complication
void SetName(const std::string& name) override;
void SetState(IEditable::EditableState state) override;
IEditable::EditableState GetState() override;
+ int SetContext(std::unique_ptr<Bundle> context) override;
+ std::unique_ptr<Bundle>& GetContext() const override;
+ int UpdateLastContext() override;
+ std::unique_ptr<Bundle>& GetLastContext() const override;
+ const std::string GetSetupAppId() override;
private:
class Impl;
auto ptr = SharedHandle<WatchComplicationStub>::Share(sh);
ptr.get()->AddCallbackInfo(new CallbackInfo(cb, user_data));
- return 0;
+ return COMPLICATION_ERROR_NONE;
}
extern "C" EXPORT_API int complication_update_cb_del(complication_h handle,
if (handle == NULL || cb == NULL)
return COMPLICATION_ERROR_INVALID_PARAMETER;
- return 0;
+ return COMPLICATION_ERROR_NONE;
}
extern "C" EXPORT_API int complication_send_update_request(
support_types > COMPLICATION_TYPE_MAX)
return COMPLICATION_ERROR_INVALID_PARAMETER;
- // TODO(?) check default value and type is valid
- auto ws = new WatchComplicationStub(
+ try {
+ auto ws = new WatchComplicationStub(
complication_id,
support_types,
default_provider_id,
static_cast<ComplicationType>(default_type),
std::shared_ptr<IEditable::Geometry>(
new IEditable::Geometry(0, 0, 100, 100)));
- LOGI("comp created");
- auto sh = SharedHandle<WatchComplicationStub>::Make(ws);
- *created_handle = static_cast<void*>(sh);
+ LOGI("comp created");
+ auto sh = SharedHandle<WatchComplicationStub>::Make(ws);
+ *created_handle = static_cast<void*>(sh);
+ } catch(...) {
+ LOGE("Create complication fail");
+ return COMPLICATION_ERROR_IO_ERROR;
+ }
- return 0;
+ return COMPLICATION_ERROR_NONE;
}
extern "C" EXPORT_API int complication_destroy(complication_h handle) {
auto ptr = SharedHandle<WatchComplicationStub>::Share(sh);
*cur_provider_id = ptr.get()->GetCurProviderId();
- return 0;
+ return COMPLICATION_ERROR_NONE;
}
extern "C" EXPORT_API int complication_get_cur_type(complication_h handle,
if (ret != -1)
*cur_type = static_cast<complication_type>(ret);
- return 0;
+ return COMPLICATION_ERROR_NONE;
}
extern "C" EXPORT_API int complication_get_provider_id(const bundle* candidate,
if (val != NULL)
*provider_id = val;
else
- return -1;
+ return COMPLICATION_ERROR_INVALID_PARAMETER;
- return 0;
+ return COMPLICATION_ERROR_NONE;
}
extern "C" EXPORT_API int complication_get_type(const bundle* candidate,
if (val != NULL)
*cur_type = static_cast<complication_type>(atoi(val));
else
- return -1;
+ return COMPLICATION_ERROR_INVALID_PARAMETER;
- return 0;
+ return COMPLICATION_ERROR_NONE;
}
glib-2.0
bundle
dlog
+ capi-appfw-app-control
)
FOREACH(flag ${watchface-editor_CFLAGS})
: parent_(parent) {
subscribe_id_ = ComplicationConnector::GetInst().SubscribeSignal(
ComplicationConnector::Editable,
- ComplicationConnector::GetInst().GetAppId(), 0, this);
+ ComplicationConnector::GetInst().GetAppId(), -1, this);
LOGI("subscribe signal %d", subscribe_id_);
}
new ReceivedEditable(std::string(str_arr[i]))));
}
parent_->OnRequestEdit(std::string(appid), std::move(e_list));
+ } else if (signal_name.compare(
+ ComplicationConnector::GetInst().GetCmdStr(
+ ComplicationConnector::SetupReply)) == 0) {
+ int edit_id;
+ char* raw_str;
+ g_variant_get(parameters, "(i&s)", &edit_id, &raw_str);
+ parent_->OnSetupReply(edit_id, std::unique_ptr<Bundle>(new Bundle(std::string(raw_str))));
}
}
+void EditablesEditor::OnSetupReply(int editable_id, std::unique_ptr<Bundle> context) {
+
+}
+
void EditablesEditor::OnRequestEdit(const std::string& appid,
std::list<std::unique_ptr<IEditable>> e_list) {
}
ReceivedEditable& re = static_cast<ReceivedEditable&>(ed);
re.SetCurDataIdx(cur_data_idx);
+ Bundle *context = re.GetContext().get();
ComplicationConnector::GetInst().EmitSignal(
ComplicationConnector::Editable,
impl_->edit_appid_.c_str(),
impl_->edit_appid_.c_str(),
- 0,
+ -1,
ComplicationConnector::GetInst().GetCmdStr(
ComplicationConnector::EditableEditPreview),
- g_variant_new("(ii)", cur_data_idx, ed.GetId()));
+ g_variant_new("(iis)", cur_data_idx, ed.GetId(),
+ (context == nullptr) ? "" : context->ToString()));
return 0;
}
ComplicationConnector::Editable,
impl_->edit_appid_.c_str(),
impl_->edit_appid_.c_str(),
- 0,
+ -1,
ComplicationConnector::GetInst().GetCmdStr(
ComplicationConnector::EditableEditComplete), NULL);
ComplicationConnector::Editable,
impl_->edit_appid_.c_str(),
impl_->edit_appid_.c_str(),
- 0,
+ -1,
ComplicationConnector::GetInst().GetCmdStr(
ComplicationConnector::EditableEditCancel), NULL);
ComplicationConnector::Editable,
appid,
appid,
- 0,
+ -1,
ComplicationConnector::GetInst().GetCmdStr(
ComplicationConnector::EditableEditReady),
g_variant_new("(s)", ComplicationConnector::GetInst().GetAppId().c_str()));
virtual ~EditablesEditor();
void OnRequestEdit(const std::string& appid,
std::list<std::unique_ptr<IEditable>> e_list) override;
+ void OnSetupReply(int editable_id, std::unique_ptr<Bundle> context) override;
int EditPreview(IEditable& ed, int cur_data_idx);
int EditComplete();
int EditCancel();
extern "C" {
#endif
-
typedef GList *editable_list_h;
+typedef void (*on_setup_result)(editable_h ed, bundle *new_context,
+ void *user_data);
typedef int (*on_request_edit)(const char *appid, editable_list_h list_h,
void *user_data);
typedef int (*editable_list_foreach_cb)(const editable_h handle,
const bundle* editor_editable_candidate_list_get_nth(const editable_h handle,
int nth);
+/**
+ * @brief Set editable's contest
+ * @since_tizen 5.0
+ * @param[in] handle The editable handle
+ * @param[in] context The new context data
+ * @see #editor_launch_setup_app
+ * @return #COMPLICATION_ERROR_NONE on success,
+ * otherwise an error code (see COMPLICATION_ERROR_XXX) on failure
+ * @retval #COMPLICATION_ERROR_NONE Successful
+ * @retval #COMPLICATION_ERROR_OUT_OF_MEMORY Out of memory
+ * @retval #COMPLICATION_ERROR_INVALID_PARAMETER Invalid parameter
+ * @par Sample code:
+ * @code
+#include <watchface-editor.h>
+void on_setup_result(editable_h ed, bundle *new_context,
+ void *user_data)
+{
+ editor_set_context(ed, new_context);
+ // send update info to the watchface
+ editor_edit_preview(ed, __candidate_selected);
+}
+ * @endcode
+ */
+int editor_set_context(const editable_h handle, bundle *context);
+
+/**
+ * @brief Launch editable's setup app
+ * @since_tizen 5.0
+ * @param[in] handle The editable handle
+ * @param[in] cb The setup result callback
+ * @param[in] user_data The setup result callback's user data
+ * @see #editor_is_setup_app_exist
+ * @return #COMPLICATION_ERROR_NONE on success,
+ * otherwise an error code (see COMPLICATION_ERROR_XXX) on failure
+ * @retval #COMPLICATION_ERROR_NONE Successful
+ * @retval #COMPLICATION_ERROR_OUT_OF_MEMORY Out of memory
+ * @retval #COMPLICATION_ERROR_INVALID_PARAMETER Invalid parameter
+ * @par Sample code:
+ * @code
+#include <watchface-editor.h>
+
+{
+ bool exist;
+ editor_is_setup_app_exist(handle, &exist);
+ if (exist) {
+ editor_launch_setup_app(handle, on_setup_result, NULL);
+ }
+}
+ * @endcode
+ */
+int editor_launch_setup_app(const editable_h handle, on_setup_result cb, void *user_data);
+
+/**
+ * @brief Check setup app is exist
+ * @since_tizen 5.0
+ * @param[in] handle The editable handle
+ * @param[out] exist The flag whether setup app is exist or not
+ * @see #editor_launch_setup_app
+ * @return #COMPLICATION_ERROR_NONE on success,
+ * otherwise an error code (see COMPLICATION_ERROR_XXX) on failure
+ * @retval #COMPLICATION_ERROR_NONE Successful
+ * @retval #COMPLICATION_ERROR_OUT_OF_MEMORY Out of memory
+ * @retval #COMPLICATION_ERROR_INVALID_PARAMETER Invalid parameter
+ * @par Sample code:
+ * @code
+#include <watchface-editor.h>
+
+{
+ bool exist;
+ editor_is_setup_app_exist(handle, &exist);
+ if (exist) {
+ editor_launch_setup_app(handle, on_setup_result, NULL);
+ }
+}
+ * @endcode
+ */
+int editor_is_setup_app_exist(const editable_h handle, bool *exist);
+
#ifdef __cplusplus
}
#endif
#include <stdio.h>
#include <errno.h>
#include <glib.h>
-#include <dlog.h>
-
#include <string>
+#include <dlog.h>
+#include <app_control.h>
+
#include "watchface-editor/include/watchface-editor.h"
#include "watchface-complication/complication.h"
#include "watchface-editor/editables-editor.h"
#define LOG_TAG "WATCHFACE_COMPLICATION"
-using watchface_complication::EditablesEditor;
-using watchface_complication::Complication;
-using watchface_complication::Bundle;
-using watchface_complication::IEditable;
+using namespace watchface_complication;
class CallbackInfo {
public:
void* user_data_;
};
+class SetupCallbackInfo {
+ public:
+ SetupCallbackInfo(on_setup_result cb, void* user_data)
+ : cb_(cb), user_data_(user_data) {
+ }
+
+ void Invoke(void* handle, bundle* new_context) {
+ cb_(handle, new_context, user_data_);
+ }
+
+ private:
+ on_setup_result cb_;
+ void* user_data_;
+};
+
class EditablesEditorStub : public EditablesEditor {
public:
EditablesEditorStub()
LOGI("request edit!! %s", appid.c_str());
}
+ void OnSetupReply(int editable_id, std::unique_ptr<Bundle> context) override {
+
+ for (auto& i : e_list_) {
+ LOGI("Setup reply!! %d, %d", i.get()->GetId(), editable_id);
+ if (i.get()->GetId() == editable_id) {
+ for (auto& j : setup_cb_list_) {
+ j->Invoke(i.get(), context.get()->GetRaw());
+ }
+ }
+ }
+ }
+
+ void AddSetupCallbackInfo(SetupCallbackInfo* ci) {
+ setup_cb_list_.emplace_back(ci);
+ }
+
+ void RemoveCallbackInfo(SetupCallbackInfo* ci) {
+ for (auto& i : setup_cb_list_) {
+ if (i.get() == ci) {
+ setup_cb_list_.remove(i);
+ break;
+ }
+ }
+ }
+
void AddCallbackInfo(CallbackInfo* ci) {
cb_list_.emplace_back(ci);
}
private:
std::list<std::unique_ptr<IEditable>> e_list_;
std::list<std::unique_ptr<CallbackInfo>> cb_list_;
+ std::list<std::unique_ptr<SetupCallbackInfo>> setup_cb_list_;
};
static std::unique_ptr<EditablesEditorStub> __stub = nullptr;
extern "C" EXPORT_API int editor_edit_preview(const editable_h handle,
int cur_data_idx) {
- if (handle == NULL)
+ if (handle == NULL)
return COMPLICATION_ERROR_INVALID_PARAMETER;
IEditable* ed = static_cast<IEditable*>(handle);
return 0;
}
-
extern "C" EXPORT_API int editor_foreach_editable_list(editable_list_h list_h,
editable_list_foreach_cb cb, void *user_data) {
if (list_h == NULL || cb == NULL)
auto nx = std::next(it, nth);
return ((*nx).get())->GetRaw();
}
+
+extern "C" EXPORT_API int editor_get_setup_appid(const editable_h handle,
+ char **setup_appid) {
+ if (handle == NULL || setup_appid == NULL)
+ return COMPLICATION_ERROR_INVALID_PARAMETER;
+
+ IEditable* ed = static_cast<IEditable*>(handle);
+ std::string appid = ed->GetSetupAppId();
+ if (appid.empty())
+ return COMPLICATION_ERROR_NO_DATA;
+ *setup_appid = strdup(appid.c_str());
+
+ return COMPLICATION_ERROR_NONE;
+}
+
+extern "C" EXPORT_API int editor_set_context(const editable_h handle,
+ bundle *new_context) {
+ if (handle == NULL) {
+ LOGE("Invalid parameter");
+ return COMPLICATION_ERROR_INVALID_PARAMETER;
+ }
+
+ int re = COMPLICATION_ERROR_NONE;
+ IEditable* ed = static_cast<IEditable*>(handle);
+ if (new_context) {
+ std::unique_ptr<Bundle> b(new Bundle(new_context));
+ if (b.get() == nullptr)
+ return COMPLICATION_ERROR_OUT_OF_MEMORY;
+ re = ed->SetContext(std::move(b));
+ } else {
+ re = ed->SetContext(std::unique_ptr<Bundle>{});
+ }
+ return re;
+}
+
+extern "C" EXPORT_API int editor_is_setup_app_exist(const editable_h handle,
+ bool *exist) {
+ if (handle == NULL) {
+ LOGE("Invalid parameter");
+ return COMPLICATION_ERROR_INVALID_PARAMETER;
+ }
+ IEditable* ed = static_cast<IEditable*>(handle);
+ std::string appid = ed->GetSetupAppId();
+ if (appid.empty())
+ *exist = false;
+ *exist = true;
+ return COMPLICATION_ERROR_NONE;
+}
+
+static int _add_extra_data(app_control_h* service, const char* key, const char* value) {
+ int ret = app_control_add_extra_data(*service, key, value);
+ if (ret != APP_CONTROL_ERROR_NONE) {
+ if (ret == APP_CONTROL_ERROR_OUT_OF_MEMORY) {
+ LOGE("Fail to get context data");
+ return COMPLICATION_ERROR_OUT_OF_MEMORY;
+ }
+ LOGE("Fail to get context data");
+ return COMPLICATION_ERROR_INVALID_PARAMETER;
+ }
+ return COMPLICATION_ERROR_NONE;
+}
+
+extern "C" EXPORT_API int editor_launch_setup_app(const editable_h handle,
+ on_setup_result cb, void* user_data) {
+
+ if (handle == NULL || cb == NULL) {
+ LOGE("Invalid parameter");
+ return COMPLICATION_ERROR_INVALID_PARAMETER;
+ }
+
+ IEditable* ed = static_cast<IEditable*>(handle);
+ std::string appid = ed->GetSetupAppId();
+ app_control_h service = NULL;
+ Bundle* context_data;
+ char ed_id[256] = {0,};
+ if(APP_CONTROL_ERROR_NONE != app_control_create(&service)) {
+ LOGE("Fail to create app control");
+ return COMPLICATION_ERROR_IO_ERROR;
+ }
+
+ LOGI("LAUNCH !!! %s", appid.c_str());
+ context_data = (ed->GetContext()).get();
+ app_control_set_app_id(service, appid.c_str());
+
+ int ret = _add_extra_data(&service, SETUP_EDITOR_APPID_KEY,
+ ComplicationConnector::GetInst().GetAppId().c_str());
+ if (ret != COMPLICATION_ERROR_NONE) {
+ LOGE("Fail to add appid ");
+ app_control_destroy(service);
+ return ret;
+ }
+
+ snprintf(ed_id, sizeof(ed_id), "%d", ed->GetId());
+ LOGI("add ed_id %s", ed_id);
+ ret = _add_extra_data(&service, SETUP_EDITABLE_ID_KEY, ed_id);
+ if (ret != COMPLICATION_ERROR_NONE) {
+ LOGE("Fail to add ed_id %s", ed_id);
+ app_control_destroy(service);
+ return ret;
+ }
+
+ ret = _add_extra_data(&service, SETUP_CONTEXT_DATA_KEY,
+ context_data == nullptr ? "" : context_data->ToString());
+
+ ret = app_control_send_launch_request(service, NULL, NULL);
+ if (ret != APP_CONTROL_ERROR_NONE) {
+ LOGE("Failed to launch:%d", ret);
+ app_control_destroy(service);
+ return COMPLICATION_ERROR_IO_ERROR;
+ }
+ app_control_destroy(service);
+
+ if (__stub == nullptr)
+ __stub = std::unique_ptr<EditablesEditorStub>(new EditablesEditorStub());
+
+ auto ci = new SetupCallbackInfo(cb, user_data);
+ __stub->AddSetupCallbackInfo(ci);
+
+ return COMPLICATION_ERROR_NONE;
+}
\ No newline at end of file