From: hyunho Date: Thu, 9 Aug 2018 07:45:11 +0000 (+0900) Subject: Add error callback for provider error case X-Git-Tag: accepted/tizen/unified/20180824.062653~16 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=0c863dadeabf69c98c620ef5d9b33984a05e0357;p=platform%2Fcore%2Fappfw%2Fwatchface-complication.git Add error callback for provider error case When every candidate provider is not available for some reason(disabled/uninstalled) watch application should know it for handling error. Change-Id: Ia60bdb6b0d4fc4917d22c96c6c388730f3dbef31 Signed-off-by: hyunho --- diff --git a/packaging/libwatchface-complication.spec b/packaging/libwatchface-complication.spec index 29067ed..186aa77 100644 --- a/packaging/libwatchface-complication.spec +++ b/packaging/libwatchface-complication.spec @@ -22,6 +22,7 @@ BuildRequires: pkgconfig(appsvc) BuildRequires: pkgconfig(capi-appfw-app-common) BuildRequires: pkgconfig(libtzplatform-config) BuildRequires: pkgconfig(pkgmgr-info) +BuildRequires: pkgconfig(pkgmgr) BuildRequires: pkgconfig(pkgmgr-installer) BuildRequires: pkgconfig(capi-appfw-app-control) BuildRequires: pkgconfig(cynara-client) diff --git a/unittest/src/test_complication.cc b/unittest/src/test_complication.cc index 709b7e2..78fc318 100644 --- a/unittest/src/test_complication.cc +++ b/unittest/src/test_complication.cc @@ -75,23 +75,6 @@ TEST_F(WC, GetEditableId) EXPECT_EQ(WC::complication->GetEditableId(), 1); } -TEST_F(WC, GetCandidates) -{ - WC::complication->UpdateCandidatesInfo(); - std::list> const& list = WC::complication->GetCandidates(); - EXPECT_NE(list.empty(), true); -} - -TEST_F(WC, GetData) -{ - WC::complication->UpdateCandidatesInfo(); - const Bundle* curData = WC::complication->GetCurData(); - const Bundle* nthData = WC::complication->GetNthData(0); - - EXPECT_NE(curData->GetConstRaw(), nullptr); - EXPECT_NE(nthData->GetConstRaw(), nullptr); -} - TEST_F(WC, DataIdx) { EXPECT_EQ(WC::complication->GetCurDataIdx(), 0); @@ -141,6 +124,12 @@ void _on_complication_update_cb(int complication_id, const char* provider_id, void* user_data) { } +void _on_complication_error_cb(int complication_id, const char* provider_id, + watchface_complication_type_e type, + watchface_complication_error_e error, + void* user_data) { +} + TEST_F(WFC, Create) { EXPECT_NE(WFC::complication, nullptr); @@ -148,7 +137,7 @@ TEST_F(WFC, Create) TEST_F(WFC, Callback) { - EXPECT_EQ(watchface_complication_add_updated_cb(WFC::complication, _on_complication_update_cb, NULL), 0); + EXPECT_EQ(watchface_complication_add_updated_cb(WFC::complication, _on_complication_update_cb, _on_complication_error_cb, NULL), 0); EXPECT_EQ(watchface_complication_send_update_request(WFC::complication), WATCHFACE_COMPLICATION_ERROR_IO_ERROR); EXPECT_EQ(watchface_complication_remove_updated_cb(WFC::complication, _on_complication_update_cb), 0); } diff --git a/watchface-common/include/watchface-common.h b/watchface-common/include/watchface-common.h index aa41791..60a90d8 100644 --- a/watchface-common/include/watchface-common.h +++ b/watchface-common/include/watchface-common.h @@ -56,6 +56,7 @@ typedef enum _complication_error { WATCHFACE_COMPLICATION_ERROR_EDIT_NOT_READY = TIZEN_ERROR_COMPLICATION | 0x3, /**< Edit not ready */ WATCHFACE_COMPLICATION_ERROR_EXIST_ID = TIZEN_ERROR_COMPLICATION | 0x4, /**< ID already exist */ WATCHFACE_COMPLICATION_ERROR_NOT_EXIST = TIZEN_ERROR_COMPLICATION | 0x5, /**< Not exist */ + WATCHFACE_COMPLICATION_ERROR_PROVIDER_NOT_AVAILABLE = TIZEN_ERROR_COMPLICATION | 0x6, /**< Provider is not available, it could be uninstalled or disabled */ } watchface_complication_error_e; /** diff --git a/watchface-complication-provider/complication-provider-event-interface.h b/watchface-complication-provider/complication-provider-event-interface.h index e21c314..df0b6f4 100644 --- a/watchface-complication-provider/complication-provider-event-interface.h +++ b/watchface-complication-provider/complication-provider-event-interface.h @@ -28,6 +28,8 @@ class EXPORT_API IComplicationProviderEvent { public: virtual void OnDataUpdated(const std::string& provider_id, ComplicationType type, const std::unique_ptr& data) = 0; + virtual void OnProviderError(const std::string& provider_id, + ComplicationType type, int error) = 0; virtual void OnNotifyDataUpdate() = 0; }; diff --git a/watchface-complication/CMakeLists.txt b/watchface-complication/CMakeLists.txt index 3d99838..db80d86 100644 --- a/watchface-complication/CMakeLists.txt +++ b/watchface-complication/CMakeLists.txt @@ -21,6 +21,8 @@ pkg_check_modules(watchface-complication REQUIRED pkgmgr-installer cynara-client cynara-creds-gdbus + pkgmgr + pkgmgr-info ) FOREACH(flag ${watchface-complication_CFLAGS}) diff --git a/watchface-complication/complication-connector-implementation.h b/watchface-complication/complication-connector-implementation.h index 2f7f360..47ed701 100644 --- a/watchface-complication/complication-connector-implementation.h +++ b/watchface-complication/complication-connector-implementation.h @@ -18,6 +18,7 @@ #define WATCHFACE_COMPLICATION_COMPLICATION_CONNECTOR_IMPLEMENTATION_H_ #include +#include #include #include @@ -26,6 +27,13 @@ #include "watchface-complication/complication.h" #include "watchface-complication/complication-connector.h" +#ifdef LOG_TAG +#undef LOG_TAG +#endif + +#define LOG_TAG "WATCHFACE_COMPLICATION" +#define LOG_TAG "WATCHFACE_COMPLICATION" + namespace watchface_complication { class ComplicationConnector::Impl { @@ -61,10 +69,86 @@ class ComplicationConnector::Impl { rs->OnAppear(name, name_owner); } + static int PackageAppinfoCallback(const pkgmgrinfo_appinfo_h handle, + void* user_data) { + char* appid = NULL; + int ret = pkgmgrinfo_appinfo_get_appid(handle, &appid); + if (ret < 0) { + LOGE("Failed to get appid"); + return 0; + } + LOGI("add (%s) for delete/disable list", appid); + package_app_list_.push_back(appid); + return 0; + } + + static int HandlingPackageCb(const char* pkgname, const char* val) { + pkgmgrinfo_appinfo_filter_h handle; + int ret = pkgmgrinfo_appinfo_filter_create(&handle); + if (ret != PMINFO_R_OK) { + LOGE("filter create failed [%d]", ret); + return WATCHFACE_COMPLICATION_ERROR_IO_ERROR; + } + + ret = pkgmgrinfo_appinfo_filter_add_string(handle, + PMINFO_APPINFO_PROP_APP_PACKAGE, pkgname); + if (ret != PMINFO_R_OK) { + LOGE("filter add pkgname failed [%d]", ret); + return WATCHFACE_COMPLICATION_ERROR_IO_ERROR; + } + + ret = pkgmgrinfo_appinfo_filter_foreach_appinfo(handle, + PackageAppinfoCallback, NULL); + if (ret != PMINFO_R_OK) { + LOGE("foreach failed [%d]", ret); + return WATCHFACE_COMPLICATION_ERROR_IO_ERROR; + } + + return 0; + } + + static int PkgmgrPackageStatusCb(uid_t target_uid, int req_id, + const char* pkg_type, const char* pkgid, const char* key, + const char* val, const void* pmsg, void* data) { + LOGI("%s, (%s : %s)", pkgid, key, val); + if (strcmp(key, "start") == 0) { + if (strcmp(val, "disable_app") == 0 || strcmp(val, "uninstall") == 0) { + current_pkg_event_ = std::string(val); + HandlingPackageCb(pkgid, current_pkg_event_.c_str()); + } else { + current_pkg_event_ = ""; + } + } else if (strcmp(key, "end") == 0) { + if (strcmp(val, "ok") == 0 && + (strcmp(current_pkg_event_.c_str(), "disable_app") == 0 || + strcmp(current_pkg_event_.c_str(), "uninstall") == 0)) { + LOGW("handling package event (%s)", current_pkg_event_.c_str()); + for (std::string& appid : package_app_list_) { + for (IPackageEventListener* pe : package_listener_list_) { + if (strcmp(current_pkg_event_.c_str(), "disable_app") == 0) { + LOGI("disabled cb (%s)", appid.c_str()); + pe->OnAppDisabled(appid); + } else if (strcmp(current_pkg_event_.c_str(), "uninstall") == 0) { + LOGI("uninstalled cb (%s)", appid.c_str()); + pe->OnAppUninstalled(appid); + } + } + } + } + package_app_list_.clear(); + } + + return 0; + } + private: + pkgmgr_client* pkgmgr_client_ = NULL; GDBusConnection* conn_ = nullptr; IEventListener* listener_ = nullptr; std::string appid_; + static std::list package_listener_list_; + static std::list package_app_list_; + static std::string current_pkg_event_; }; } // namespace watchface_complication diff --git a/watchface-complication/complication-connector.cc b/watchface-complication/complication-connector.cc index 3c61bfa..ce49c79 100644 --- a/watchface-complication/complication-connector.cc +++ b/watchface-complication/complication-connector.cc @@ -18,6 +18,8 @@ #include #include #include +#include +#include #include "watchface-complication/complication-connector.h" #include "watchface-complication/complication-connector-implementation.h" @@ -39,6 +41,9 @@ #define MAX_PACKAGE_STR_SIZE 512 namespace watchface_complication { +std::list ComplicationConnector::Impl::package_listener_list_; +std::list ComplicationConnector::Impl::package_app_list_; +std::string ComplicationConnector::Impl::current_pkg_event_; ComplicationConnector& ComplicationConnector::GetInst() { static ComplicationConnector w_inst; @@ -56,6 +61,35 @@ ComplicationConnector::ComplicationConnector() = default; ComplicationConnector::~ComplicationConnector() = default; ComplicationConnector::Impl::Impl() = default; +void ComplicationConnector::AddPackageEventListener(IPackageEventListener* pe) { + if (impl_->pkgmgr_client_ == NULL) { + impl_->pkgmgr_client_ = pkgmgr_client_new(PC_LISTENING); + + if (impl_->pkgmgr_client_ == NULL) { + LOGE("fail to create pkgmgr client"); + return; + } + + if (pkgmgr_client_listen_status(impl_->pkgmgr_client_ , + impl_->PkgmgrPackageStatusCb, NULL) <= 0) { + LOGE("fail to listen pkg status"); + pkgmgr_client_free(impl_->pkgmgr_client_); + return; + } + LOGI("listen pkg status"); + } + + impl_->package_listener_list_.push_back(pe); +} + +void ComplicationConnector::RemovePackageEventListener(IPackageEventListener* pe) { + impl_->package_listener_list_.remove(pe); + if (impl_->package_listener_list_.size() == 0) { + pkgmgr_client_free(impl_->pkgmgr_client_); + impl_->pkgmgr_client_ = NULL; + } +} + std::string ComplicationConnector::GetAppId() { return impl_->appid_; } @@ -224,6 +258,7 @@ int ComplicationConnector::Init() { LOGE("Out of memory"); return WATCHFACE_COMPLICATION_ERROR_OUT_OF_MEMORY; } + tmp_impl->conn_ = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, &error); if (tmp_impl->conn_ == NULL) { if (error != NULL) { diff --git a/watchface-complication/complication-connector.h b/watchface-complication/complication-connector.h index 731f90b..ee25155 100644 --- a/watchface-complication/complication-connector.h +++ b/watchface-complication/complication-connector.h @@ -58,6 +58,12 @@ class EXPORT_API ComplicationConnector { const std::string& name_owner) = 0; }; + class IPackageEventListener { + public: + virtual void OnAppDisabled(const std::string& appid) = 0; + virtual void OnAppUninstalled(const std::string& appid) = 0; + }; + static ComplicationConnector& GetInst(); int Watch(std::string id, IEventListener* listener); void UnWatch(int watcher_id); @@ -68,6 +74,8 @@ class EXPORT_API ComplicationConnector { void UnSubscribeSignal(int subscribe_id); std::string GetAppId(); std::string GetCmdStr(CmdType type); + void AddPackageEventListener(IPackageEventListener* pe); + void RemovePackageEventListener(IPackageEventListener* pe); private: ComplicationConnector(); @@ -82,6 +90,7 @@ class EXPORT_API ComplicationConnector { }; std::string EncodeStr(EncodeType type, std::string appid); std::string EncodeStr(EncodeType type, std::string appid, int compid); + class Impl; std::unique_ptr impl_; }; diff --git a/watchface-complication/complication-implementation.h b/watchface-complication/complication-implementation.h index a6dc149..e54b1ea 100644 --- a/watchface-complication/complication-implementation.h +++ b/watchface-complication/complication-implementation.h @@ -36,7 +36,8 @@ namespace watchface_complication { -class Complication::Impl : ComplicationConnector::IEventListener { +class Complication::Impl : ComplicationConnector::IEventListener, + ComplicationConnector::IPackageEventListener { public: void OnSignal(GDBusConnection* connection, const std::string& sender_name, @@ -46,6 +47,8 @@ class Complication::Impl : ComplicationConnector::IEventListener { GVariant* parameters) override; void OnVanish(const std::string& name) override; void OnAppear(const std::string& name, const std::string& name_owner) override; + void OnAppDisabled(const std::string& appid) override; + void OnAppUninstalled(const std::string& appid) override; virtual ~Impl(); private: @@ -66,16 +69,26 @@ class Complication::Impl : ComplicationConnector::IEventListener { int MakeCandidatesList(); int LoadPeriod(); int LoadLabel(); + int LoadContext(); + int LoadCurProviderAppid(); + int LoadCurDataIdx(); + int LoadPrevProviderInfo(); + int LoadDefaultProviderInfo(); int UpdateLastDataFields(); + int UpdateProviderInfo(); + int DeleteAppContext(const char* appid); + int ReplaceUnavailableProvider(const char* deleted_appid); private: Complication* parent_; int complication_id_ = -1; int editable_id_ = -1; int support_types_ = -1; + std::string default_provider_appid_; std::string default_provider_id_; ComplicationType default_type_; std::unique_ptr highlight_; + std::string cur_provider_appid_; std::string cur_provider_id_; ComplicationType cur_type_; std::string last_provider_id_; diff --git a/watchface-complication/complication.cc b/watchface-complication/complication.cc index d1367c2..884fbe0 100644 --- a/watchface-complication/complication.cc +++ b/watchface-complication/complication.cc @@ -19,11 +19,12 @@ #include #include #include +#include #include -#include "watchface-common/watchface-util.h" #include "watchface-complication/complication.h" #include "watchface-complication/complication-implementation.h" +#include "watchface-common/watchface-util.h" #include "watchface-complication/include/watchface-complication-internal.h" #ifdef LOG_TAG @@ -42,9 +43,11 @@ Complication::Complication(int id, int support_types, const std::string& default_provider_id, ComplicationType default_type) : impl_(new Impl(this, id, support_types, default_provider_id, default_type)) { + ComplicationConnector::GetInst().AddPackageEventListener(impl_.get()); } Complication::~Complication() { + ComplicationConnector::GetInst().RemovePackageEventListener(impl_.get()); } Complication::Impl::Impl(Complication* parent, int id, @@ -53,19 +56,25 @@ Complication::Impl::Impl(Complication* parent, int id, ComplicationType default_type) : parent_(parent), complication_id_(id), support_types_(support_types), default_provider_id_(default_provider_id), default_type_(default_type) { - RestoreStateOrSetDefault(); - LoadPeriod(); - LoadLabel(); - if (cur_type_ != NoData) { - try { - subscribe_id_ = ComplicationConnector::GetInst().SubscribeSignal( - ComplicationConnector::Complication, cur_provider_id_, - -1, this); - } catch (...) { - throw; - } + int ret; + ret = LoadPrevProviderInfo(); + if (ret == WATCHFACE_COMPLICATION_ERROR_PROVIDER_NOT_AVAILABLE) { + ret = LoadDefaultProviderInfo(); + if (ret != WATCHFACE_COMPLICATION_ERROR_NONE) + THROW(ret); + } + + UpdateCandidatesInfo(); + ret = UpdateProviderInfo(); + if (ret != WATCHFACE_COMPLICATION_ERROR_NONE) + THROW(ret); + + default_provider_appid_ = + DBManager::GetProviderAppId(cur_provider_id_.c_str()); + if (default_provider_appid_.empty()) { + LOGE("fail to get default provider info"); + THROW(WATCHFACE_COMPLICATION_ERROR_PROVIDER_NOT_AVAILABLE); } - LOGI("subscribe signal %d %d ", subscribe_id_, cur_type_); } Complication::Impl::~Impl() { @@ -112,7 +121,7 @@ void Complication::Impl::OnSignal(GDBusConnection* connection, return; } std::string provider_appid = - DBManager::GetProviderAppId(cur_provider_id_.c_str()); + DBManager::GetProviderAppId(cur_provider_id_.c_str()); if (provider_appid.empty()) { LOGI("invalid provider_appid"); return; @@ -194,47 +203,90 @@ int Complication::Impl::FindCandidateDataIdx(std::string provider_id, return ret; } -void Complication::Impl::RestoreStateOrSetDefault() { +int Complication::Impl::LoadContext() { + context_data_ = EditablesManager::GetInst().LoadContext(complication_id_, + cur_provider_id_.c_str()); + try { + if (context_data_ != nullptr) + last_context_data_.reset(new Bundle(context_data_.get()->GetRaw())); + } catch (...) { + LOGE("Out of memory"); + return WATCHFACE_COMPLICATION_ERROR_OUT_OF_MEMORY; + } + return WATCHFACE_COMPLICATION_ERROR_NONE; +} + +int Complication::Impl::LoadCurProviderAppid() { + std::string appid = DBManager::GetProviderAppId(cur_provider_id_.c_str()); + if (appid.empty()) { + LOGE("Fail to get provider appid"); + return WATCHFACE_COMPLICATION_ERROR_PROVIDER_NOT_AVAILABLE; + } + cur_provider_appid_ = appid; + LOGI("cur provider appid (%s)", cur_provider_appid_.c_str()); + return WATCHFACE_COMPLICATION_ERROR_NONE; +} + +int Complication::Impl::LoadCurDataIdx() { + int ret = FindCandidateDataIdx(cur_provider_id_, cur_type_); + if (ret == -1) { + LOGE("Fail to find data index (%s)(%d)", cur_provider_id_.c_str(), cur_type_); + return WATCHFACE_COMPLICATION_ERROR_NO_DATA; + } + + cur_data_idx_ = ret; + return WATCHFACE_COMPLICATION_ERROR_NONE; +} + +int Complication::Impl::LoadPrevProviderInfo() { char* prev_provider_id = NULL; char* prev_provider_type = NULL; + std::string prev_provider_id_str; std::unique_ptr setting_data; try { setting_data = EditablesManager::GetInst().LoadSetting(complication_id_); - } catch (...) { - throw; + } catch (watchface_complication::Exception &ex) { + LOGE("%s %d", ex.what(), ex.GetErrorCode()); + return ex.GetErrorCode(); } - if (setting_data == nullptr) { - cur_provider_id_ = default_provider_id_; - cur_type_ = default_type_; - } else { + if (setting_data != nullptr) { 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_; + if (prev_provider_id) + prev_provider_id_str = std::string(prev_provider_id); - LOGI("prev provider info %s, %s", prev_provider_id, prev_provider_type); + LOGI("get setting from bundle %s, %s", prev_provider_id, prev_provider_type); } - cur_data_idx_ = FindCandidateDataIdx(cur_provider_id_, cur_type_); - context_data_ = EditablesManager::GetInst().LoadContext(complication_id_, - cur_provider_id_.c_str()); - try { - if (context_data_ != nullptr) - last_context_data_.reset(new Bundle(context_data_.get()->GetRaw())); - } catch (...) { - throw; + if (prev_provider_id && + DBManager::IsProviderExist(prev_provider_id_str, + atoi((const char*)prev_provider_type))) { + cur_provider_id_ = std::string(prev_provider_id); + cur_type_ = static_cast(atoi((const char*)prev_provider_type)); + LOGI("Successfully get previous provider info"); + return WATCHFACE_COMPLICATION_ERROR_NONE; } + + return WATCHFACE_COMPLICATION_ERROR_PROVIDER_NOT_AVAILABLE; +} + +int Complication::Impl::LoadDefaultProviderInfo() { + if (!DBManager::IsProviderExist(default_provider_id_, + static_cast(default_type_))) { + LOGE("Default provider do not exist (%s)(%d)", + default_provider_id_.c_str(), default_type_); + return WATCHFACE_COMPLICATION_ERROR_PROVIDER_NOT_AVAILABLE; + } + + cur_type_ = default_type_; + cur_provider_id_ = default_provider_id_; + + LOGI("Successfully get default provider info"); + return WATCHFACE_COMPLICATION_ERROR_NONE; } int Complication::Impl::StoreSetting(int comp_id, std::string& provider_id, @@ -300,7 +352,7 @@ IEditable::Highlight* Complication::GetHighlight() { int Complication::SetCandidates( std::list> candidates_list) { - return UpdateCandidatesInfo(); + return impl_->UpdateCandidatesInfo(); } std::list> const& Complication::GetCandidates() const { @@ -343,6 +395,63 @@ int Complication::GetLastDataIdx() { return impl_->last_data_idx_; } +int Complication::Impl::DeleteAppContext(const char* appid) { + int ret = WATCHFACE_COMPLICATION_ERROR_NONE; + std::list list = DBManager::GetProviderListWithAppId(appid); + for (std::string& info : list) { + ret = EditablesManager::GetInst().DeleteContext(editable_id_, info.c_str()); + if (ret != WATCHFACE_COMPLICATION_ERROR_NONE) { + LOGE("delete editable context fail %d", ret); + return ret; + } else { + LOGI("delete context for (%d)(%s) done", editable_id_, info.c_str()); + } + } + return ret; +} + +int Complication::Impl::ReplaceUnavailableProvider(const char* deleted_appid) { + int ret = WATCHFACE_COMPLICATION_ERROR_NONE; + + if (strcmp(deleted_appid, cur_provider_appid_.c_str()) != 0) { + LOGI("it is not current provider skip replace process (%s)(%s)", + deleted_appid, cur_provider_appid_.c_str()); + return ret; + } + + LOGI("current provider is uninstalled try to replace it with default"); + if (strcmp(deleted_appid, default_provider_appid_.c_str()) == 0) { + LOGE("deleted provider is default provider (%s)", + default_provider_appid_.c_str()); + ret = WATCHFACE_COMPLICATION_ERROR_PROVIDER_NOT_AVAILABLE; + } else { + ret = LoadDefaultProviderInfo(); + } + + if (ret == WATCHFACE_COMPLICATION_ERROR_PROVIDER_NOT_AVAILABLE) { + parent_->OnProviderError(default_provider_id_, default_type_, + WATCHFACE_COMPLICATION_ERROR_PROVIDER_NOT_AVAILABLE); + } else { + ret = UpdateProviderInfo(); + } + + return ret; +} + +void Complication::Impl::OnAppDisabled(const std::string& appid) { + ReplaceUnavailableProvider(appid.c_str()); +} + +void Complication::Impl::OnAppUninstalled(const std::string& appid) { + pkgmgrinfo_appinfo_h app_handle; + + int ret = pkgmgrinfo_appinfo_get_disabled_appinfo(appid.c_str(), &app_handle); + if (ret != PMINFO_R_OK) + DeleteAppContext(appid.c_str()); + + ReplaceUnavailableProvider(appid.c_str()); +} + int Complication::Impl::UpdateLastDataFields() { int ret; @@ -353,7 +462,47 @@ int Complication::Impl::UpdateLastDataFields() { if (ret != WATCHFACE_COMPLICATION_ERROR_NONE) return ret; ret = LoadLabel(); - return ret;; + return ret; +} + +/* +* update provider relate information according to +* cur_provider_id_, cur_provider_type_ +*/ +int Complication::Impl::UpdateProviderInfo() { + int ret = LoadCurDataIdx(); + if (ret != WATCHFACE_COMPLICATION_ERROR_NONE) + return ret; + + ret = LoadCurProviderAppid(); + if (ret != WATCHFACE_COMPLICATION_ERROR_NONE) + return ret; + + ret = LoadContext(); + if (ret != WATCHFACE_COMPLICATION_ERROR_NONE) + return ret; + + ret = LoadPeriod(); + if (ret != WATCHFACE_COMPLICATION_ERROR_NONE) + return ret; + + ret = LoadLabel(); + if (ret != WATCHFACE_COMPLICATION_ERROR_NONE) + return ret; + + if (cur_type_ != NoData) { + try { + subscribe_id_ = ComplicationConnector::GetInst().SubscribeSignal( + ComplicationConnector::Complication, cur_provider_id_, + -1, this); + } catch (Exception &ex) { + LOGE("%s %d", ex.what(), ex.GetErrorCode()); + return ex.GetErrorCode(); + } + LOGI("subscribe signal %d %d ", subscribe_id_, cur_type_); + } + + return ret; } int Complication::Impl::LoadLabel() { @@ -408,6 +557,7 @@ int Complication::UpdateLastData() { int Complication::SetCurDataIdx(int cur_data_idx) { char* provider_id = NULL; char* type = NULL; + int ret = WATCHFACE_COMPLICATION_ERROR_NONE; if (impl_->cur_data_idx_ == cur_data_idx) { LOGI("Same with cur data idx skip setting process %d, %d", @@ -445,13 +595,11 @@ int Complication::SetCurDataIdx(int cur_data_idx) { if (impl_->cur_type_ == NoData) { impl_->subscribe_id_ = -1; } else { - impl_->subscribe_id_ = ComplicationConnector::GetInst().SubscribeSignal( - ComplicationConnector::Complication, - impl_->cur_provider_id_, -1, impl_.get()); + ret = impl_->UpdateProviderInfo(); LOGI("subscribe signal %d", impl_->subscribe_id_); } - return WATCHFACE_COMPLICATION_ERROR_NONE; + return ret; } const char* Complication::GetCurProviderId() { @@ -512,6 +660,10 @@ void Complication::OnEditableUpdated(int selected_idx, } } +void Complication::OnProviderError(const std::string& provider_id, + ComplicationType type, int error) { +} + void Complication::OnDataUpdated(const std::string& provider_id, ComplicationType type, const std::unique_ptr& data) { @@ -623,8 +775,7 @@ int Complication::UpdateLastContext() { } try { - impl_->last_context_data_.reset( - new Bundle((impl_->context_data_.get())->GetRaw())); + impl_->last_context_data_.reset(new Bundle((impl_->context_data_.get())->GetRaw())); } catch (const std::bad_alloc &ba) { LOGE("Bundle::Exception bad_alloc"); return WATCHFACE_COMPLICATION_ERROR_OUT_OF_MEMORY; @@ -789,16 +940,15 @@ int Complication::Impl::MakeCandidatesList() { return WATCHFACE_COMPLICATION_ERROR_NONE; } -int Complication::UpdateCandidatesInfo() { - int ret = impl_->MakeCandidatesList(); +int Complication::Impl::UpdateCandidatesInfo() { + int ret = MakeCandidatesList(); if (ret != WATCHFACE_COMPLICATION_ERROR_NONE) return ret; - int idx = impl_->FindCandidateDataIdx( - impl_->cur_provider_id_, impl_->cur_type_); + int idx = FindCandidateDataIdx(cur_provider_id_, cur_type_); if (idx != -1) { - impl_->cur_data_idx_ = idx; - ret = impl_->UpdateLastDataFields(); + cur_data_idx_ = idx; + ret = UpdateLastDataFields(); } return ret; @@ -808,7 +958,7 @@ int Complication::ApplyAllowedList( std::list> allowed_list) { impl_->allowed_list_ = std::move(allowed_list); impl_->candidates_list_.clear(); - return UpdateCandidatesInfo(); + return impl_->UpdateCandidatesInfo(); } int Complication::ClearAllowedList() { diff --git a/watchface-complication/complication.h b/watchface-complication/complication.h index bab18d7..7be8b12 100644 --- a/watchface-complication/complication.h +++ b/watchface-complication/complication.h @@ -72,6 +72,8 @@ class EXPORT_API Complication : public IEditable void OnDataUpdated(const std::string& provider_id, ComplicationType type, const std::unique_ptr& data) override; + void OnProviderError(const std::string& provider_id, ComplicationType type, + int error) override; void OnNotifyDataUpdate() override; int GetComplicationId(); int GetEditableId() override; @@ -84,6 +86,7 @@ class EXPORT_API Complication : public IEditable int UpdateLastContext() override; std::unique_ptr& GetLastContext() const override; const std::string GetSetupAppId() override; + int SendDataUpdateRequest(); const char* GetCurProviderId(); const char* GetProviderId(const Bundle* data); diff --git a/watchface-complication/db-manager.cc b/watchface-complication/db-manager.cc index 0b1336f..6ecd268 100644 --- a/watchface-complication/db-manager.cc +++ b/watchface-complication/db-manager.cc @@ -143,6 +143,44 @@ int DBManager::GetProviderPeriod(std::string& provider_id, int* period) { return WATCHFACE_COMPLICATION_ERROR_NONE; } +bool DBManager::IsProviderExist(std::string& provider_id, + int support_type) { + int ret; + std::string appid; + sqlite3_stmt* stmt = NULL; + sqlite3* db; + bool is_exist = false; + + static const char query[] = + "SELECT DISTINCT appid FROM complication_provider " + "WHERE provider_id=? AND support_type=?"; + + db = OpenDB(); + if (db == NULL) { + LOGE("parser db not exist"); + return false; + } + + ret = sqlite3_prepare_v2(db, query, strlen(query), + &stmt, NULL); + if (ret != SQLITE_OK) { + LOGE("prepare error: %s", sqlite3_errmsg(db)); + CloseDB(db); + return false; + } + + sqlite3_bind_text(stmt, 1, provider_id.c_str(), -1, SQLITE_TRANSIENT); + sqlite3_bind_int(stmt, 2, support_type); + + if (sqlite3_step(stmt) == SQLITE_ROW) + is_exist = true; + + sqlite3_finalize(stmt); + CloseDB(db); + + return is_exist; +} + std::string DBManager::GetProviderAppId(const char* provider_id) { int ret; std::string appid; @@ -259,6 +297,45 @@ std::list DBManager::GetProviderList(int support_type) { return provider_list; } +std::list DBManager::GetProviderListWithAppId( + const char* provider_id) { + int ret; + char* provider = NULL; + sqlite3_stmt* stmt; + sqlite3* db; + std::list provider_list; + + static const char query[] = + "SELECT DISTINCT provider_id FROM complication_provider " + "WHERE appid=?"; + + db = OpenDB(); + if (db == NULL) { + LOGE("parser db not exist"); + return provider_list; + } + + ret = sqlite3_prepare_v2(db, query, strlen(query), + &stmt, NULL); + if (ret != SQLITE_OK) { + LOGE("prepare error: %s", sqlite3_errmsg(db)); + CloseDB(db); + return provider_list; + } + + sqlite3_bind_text(stmt, 1, provider_id, -1, SQLITE_TRANSIENT); + + while (sqlite3_step(stmt) == SQLITE_ROW) { + provider = (char*)sqlite3_column_text(stmt, 0); + provider_list.push_back(std::string(provider)); + } + + sqlite3_finalize(stmt); + CloseDB(db); + + return provider_list; +} + int DBManager::GetSupportTypes(std::string& provider_id, int* types) { int ret; int support_types = 0; diff --git a/watchface-complication/db-manager.h b/watchface-complication/db-manager.h index a15b031..c247b4c 100644 --- a/watchface-complication/db-manager.h +++ b/watchface-complication/db-manager.h @@ -57,6 +57,8 @@ class EXPORT_API DBManager { static int GetProviderPeriod(std::string& provider_id, int* period); static std::string GetLabel(const char* provider_id); static std::string GetSetupAppId(const char* provider_id); + static bool IsProviderExist(std::string& provider_id, int support_type); + static std::list GetProviderListWithAppId(const char* provider_id); private: DBManager(); diff --git a/watchface-complication/editables-manager.cc b/watchface-complication/editables-manager.cc index cd89125..caebc4d 100644 --- a/watchface-complication/editables-manager.cc +++ b/watchface-complication/editables-manager.cc @@ -228,5 +228,34 @@ std::unique_ptr EditablesManager::LoadContext(int editable_id, return std::move(context_data); } +int EditablesManager::DeleteContext(int editable_id, + const char* provider_id) { + char query[QUERY_MAXLEN]; + std::unique_ptr context_data = nullptr; + sqlite3_stmt* stmt; + int ret; + + if (impl_->context_db_ == NULL) + return WATCHFACE_COMPLICATION_ERROR_DB; + + sqlite3_snprintf(QUERY_MAXLEN, query, + "DELETE FROM editable_context WHERE " \ + "editable_id = %d AND provider_id = %Q ", editable_id, provider_id); + LOGI("editable context delete : (%d)(%s)", editable_id, provider_id); + ret = sqlite3_prepare_v2(impl_->context_db_, + query, strlen(query), &stmt, NULL); + + ret = sqlite3_step(stmt); + if (ret != SQLITE_DONE) { + LOGE("execute fail %s", sqlite3_errmsg(impl_->context_db_)); + sqlite3_close_v2(impl_->context_db_); + sqlite3_finalize(stmt); + return WATCHFACE_COMPLICATION_ERROR_DB; + } + sqlite3_finalize(stmt); + + return WATCHFACE_COMPLICATION_ERROR_NONE; +} + } // namespace watchface_complication diff --git a/watchface-complication/editables-manager.h b/watchface-complication/editables-manager.h index d0f2083..9c8a0f1 100644 --- a/watchface-complication/editables-manager.h +++ b/watchface-complication/editables-manager.h @@ -34,6 +34,7 @@ class EXPORT_API EditablesManager { std::unique_ptr LoadSetting(int editable_id); int StoreContext(int editable_id, const char* provider_id, Bundle& context); std::unique_ptr LoadContext(int editable_id, const char* provider_id); + int DeleteContext(int editable_id, const char* provider_id); private: EditablesManager(); diff --git a/watchface-complication/include/watchface-complication.h b/watchface-complication/include/watchface-complication.h index 6b6ff68..5f2517f 100644 --- a/watchface-complication/include/watchface-complication.h +++ b/watchface-complication/include/watchface-complication.h @@ -61,6 +61,26 @@ typedef void (*watchface_complication_updated_cb)( void *user_data); /** + * @brief Called when the complication provider error is occured. + * @since_tizen 5.0 + * @param[in] complication_id A number that identifies the complication + * @param[in] provider_id The name of the provider. + * The @a provider_id can be used only in the callback. To use outside, make a copy. + * @param[in] type The type shown in the complication + * @param[in] error The error related with complication provider \n + * #WATCHFACE_COMPLICATION_ERROR_PROVIDER_NOT_AVAILABLE : Provider aplication is not available now for some reason. (eg. uninstall, disable) \n + * #WATCHFACE_COMPLICATION_ERROR_IO_ERROR : Provider aplication is not responding for update request. \n + * #WATCHFACE_COMPLICATION_ERROR_OUT_OF_MEMORY : Out of memory \n + * @param[in] user_data The user data passed from the callback function + */ +typedef void (*watchface_complication_error_cb)( + int complication_id, + const char *provider_id, + watchface_complication_type_e type, + watchface_complication_error_e error, + void *user_data); + +/** * @brief Gets the id of provider in the complication. * @since_tizen 5.0 * @remarks The @a cur_provider should be released using free(). @@ -135,6 +155,7 @@ int watchface_complication_get_current_type(complication_h handle, * @since_tizen 5.0 * @param[in] handle Complication handle * @param[in] cb The callback function + * @param[in] error_cb The error callback function * @param[in] user_data The user data to pass to the callback function * @return #WATCHFACE_COMPLICATION_ERROR_NONE if success, other value if failure * @retval #WATCHFACE_COMPLICATION_ERROR_NONE Success @@ -166,6 +187,7 @@ int watchface_complication_get_current_type(complication_h handle, */ int watchface_complication_add_updated_cb(complication_h handle, watchface_complication_updated_cb cb, + watchface_complication_error_cb error_cb, void *user_data); /** @@ -242,7 +264,9 @@ int watchface_complication_send_update_request(complication_h handle); * If user selects the other provider and type, they are no longer used. * You can specify support_types by combining the types you want to show in the complication. * @since_tizen 5.0 + * @privilege http://tizen.org/privilege/packagemanager.info * @remarks The @a created_handle should be released using watchface_complication_destroy(). + * Package manager privliege is needed to lookup provider application. * @param[in] complication_id A number that identifies the complication * @param[in] default_provider_id The default provider id * @param[in] default_type The default type to display @@ -256,7 +280,9 @@ int watchface_complication_send_update_request(complication_h handle); * @retval #WATCHFACE_COMPLICATION_ERROR_NOT_EXIST Provider does not exist * @retval #WATCHFACE_COMPLICATION_ERROR_OUT_OF_MEMORY Out of memory * @retval #WATCHFACE_COMPLICATION_ERROR_DB Database error + * @retval #WATCHFACE_COMPLICATION_ERROR_PERMISSION_DENIED Permission denied * @retval #WATCHFACE_COMPLICATION_ERROR_NOT_SUPPORTED Not supported + * @retval #WATCHFACE_COMPLICATION_ERROR_PROVIDER_NOT_AVAILABLE Provider aplication is not available now for some reason. (eg. uninstall, disable) * @see watchface_complication_type_e * @par Sample code: * @code diff --git a/watchface-complication/watchface-complication.cc b/watchface-complication/watchface-complication.cc index 620b6a1..9bb2201 100644 --- a/watchface-complication/watchface-complication.cc +++ b/watchface-complication/watchface-complication.cc @@ -42,8 +42,9 @@ struct complication_allowed_list_ { using namespace watchface_complication; class CallbackInfo { public: - CallbackInfo(watchface_complication_updated_cb cb, void* user_data) - : cb_(cb), user_data_(user_data) { + CallbackInfo(watchface_complication_updated_cb cb, + watchface_complication_error_cb error_cb, void* user_data) + : cb_(cb), error_cb_(error_cb), user_data_(user_data) { } void Invoke(int complication_id, @@ -54,12 +55,48 @@ class CallbackInfo { data.get() == NULL ? NULL : data.get()->GetConstRaw(), user_data_); } + void InvokeErrorCallback(int complication_id, + const std::string& provider_id, + ComplicationType type, int error) { + error_cb_(complication_id, + provider_id.c_str(), static_cast(type), + static_cast(error), user_data_); + } + watchface_complication_updated_cb GetCallback() { return cb_; } + watchface_complication_error_cb GetErrorCallback() { + return error_cb_; + } + private: watchface_complication_updated_cb cb_; + watchface_complication_error_cb error_cb_; + void* user_data_; +}; + +class ErrorCallbackInfo { + public: + ErrorCallbackInfo(watchface_complication_error_cb cb, void* user_data) + : cb_(cb), user_data_(user_data) { + } + + void Invoke(int complication_id, + const std::string& provider_id, + ComplicationType type, int error) { + cb_(complication_id, + provider_id.c_str(), static_cast(type), + static_cast(error), user_data_); + } + + watchface_complication_error_cb GetCallback() { + return cb_; + } + + private: + watchface_complication_error_cb cb_; void* user_data_; }; @@ -73,6 +110,14 @@ class WatchComplicationStub : public Complication { virtual ~WatchComplicationStub() = default; + void OnProviderError(const std::string& provider_id, ComplicationType type, + int error) override { + for (auto& i : cb_list_) { + i->InvokeErrorCallback(GetComplicationId(), provider_id, type, error); + } + LOGI("update call!! done"); + } + void OnDataUpdated(const std::string& provider_id, ComplicationType type, const std::unique_ptr& data) override { for (auto& i : cb_list_) { @@ -108,15 +153,17 @@ class WatchComplicationStub : public Complication { extern "C" EXPORT_API int watchface_complication_add_updated_cb( complication_h handle, watchface_complication_updated_cb cb, - void* user_data) { - if (handle == NULL || cb == NULL) + watchface_complication_error_cb error_cb, void* user_data) { + if (handle == NULL || cb == NULL || error_cb == NULL) return WATCHFACE_COMPLICATION_ERROR_INVALID_PARAMETER; int ret; auto sh = static_cast*>(handle); auto ptr = SharedHandle::Share(sh); try { - ret = ptr.get()->AddCallbackInfo(new CallbackInfo(cb, user_data)); + ret = ptr.get()->AddCallbackInfo(new CallbackInfo(cb, error_cb, user_data)); + if (ret != WATCHFACE_COMPLICATION_ERROR_NONE) + return ret; } catch (const std::bad_alloc &ba) { LOGE("WatchComplicationProviderStub::Exception bad_alloc"); return WATCHFACE_COMPLICATION_ERROR_OUT_OF_MEMORY; diff --git a/watchface-complication/watchface-editable.cc b/watchface-complication/watchface-editable.cc index ab7a6e42..030e4ea 100644 --- a/watchface-complication/watchface-editable.cc +++ b/watchface-complication/watchface-editable.cc @@ -447,7 +447,7 @@ extern "C" EXPORT_API int watchface_editable_load_current_data( setting_data = EditablesManager::GetInst().LoadSetting(editable_id); } catch (watchface_complication::Exception &ex) { LOGE("%s %d", ex.what(), ex.GetErrorCode()); - return ex.GetErrorCode();; + return ex.GetErrorCode(); } if (setting_data != nullptr) { *selected_data = bundle_dup(setting_data.get()->GetRaw()); @@ -661,4 +661,4 @@ extern "C" EXPORT_API int watchface_editable_get_highlight( *highlight = hi; return WATCHFACE_COMPLICATION_ERROR_NONE; -} \ No newline at end of file +}