Add error callback for provider error case 74/186374/11
authorhyunho <hhstark.kang@samsung.com>
Thu, 9 Aug 2018 07:45:11 +0000 (16:45 +0900)
committerhyunho <hhstark.kang@samsung.com>
Tue, 14 Aug 2018 02:02:04 +0000 (11:02 +0900)
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 <hhstark.kang@samsung.com>
18 files changed:
packaging/libwatchface-complication.spec
unittest/src/test_complication.cc
watchface-common/include/watchface-common.h
watchface-complication-provider/complication-provider-event-interface.h
watchface-complication/CMakeLists.txt
watchface-complication/complication-connector-implementation.h
watchface-complication/complication-connector.cc
watchface-complication/complication-connector.h
watchface-complication/complication-implementation.h
watchface-complication/complication.cc
watchface-complication/complication.h
watchface-complication/db-manager.cc
watchface-complication/db-manager.h
watchface-complication/editables-manager.cc
watchface-complication/editables-manager.h
watchface-complication/include/watchface-complication.h
watchface-complication/watchface-complication.cc
watchface-complication/watchface-editable.cc

index 29067ed..186aa77 100644 (file)
@@ -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)
index 709b7e2..78fc318 100644 (file)
@@ -75,23 +75,6 @@ TEST_F(WC, GetEditableId)
   EXPECT_EQ(WC::complication->GetEditableId(), 1);
 }
 
-TEST_F(WC, GetCandidates)
-{
-  WC::complication->UpdateCandidatesInfo();
-  std::list<std::unique_ptr<Bundle>> 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);
 }
index aa41791..60a90d8 100644 (file)
@@ -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;
 
 /**
index e21c314..df0b6f4 100644 (file)
@@ -28,6 +28,8 @@ class EXPORT_API IComplicationProviderEvent {
  public:
   virtual void OnDataUpdated(const std::string& provider_id,
                 ComplicationType type, const std::unique_ptr<Bundle>& data) = 0;
+  virtual void OnProviderError(const std::string& provider_id,
+                ComplicationType type, int error) = 0;
   virtual void OnNotifyDataUpdate() = 0;
 };
 
index 3d99838..db80d86 100644 (file)
@@ -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})
index 2f7f360..47ed701 100644 (file)
@@ -18,6 +18,7 @@
 #define WATCHFACE_COMPLICATION_COMPLICATION_CONNECTOR_IMPLEMENTATION_H_
 
 #include <gio/gio.h>
+#include <dlog.h>
 
 #include <memory>
 #include <string>
 #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<IPackageEventListener*> package_listener_list_;
+  static std::list<std::string> package_app_list_;
+  static std::string current_pkg_event_;
 };
 
 }  // namespace watchface_complication
index 3c61bfa..ce49c79 100644 (file)
@@ -18,6 +18,8 @@
 #include <glib.h>
 #include <unistd.h>
 #include <aul.h>
+#include <package-manager.h>
+#include <pkgmgr-info.h>
 
 #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::IPackageEventListener*> ComplicationConnector::Impl::package_listener_list_;
+std::list<std::string> 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) {
index 731f90b..ee25155 100644 (file)
@@ -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> impl_;
 };
index a6dc149..e54b1ea 100644 (file)
@@ -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<IEditable::Highlight> highlight_;
+  std::string cur_provider_appid_;
   std::string cur_provider_id_;
   ComplicationType cur_type_;
   std::string last_provider_id_;
index d1367c2..884fbe0 100644 (file)
 #include <aul.h>
 #include <aul_complication.h>
 #include <appsvc.h>
+#include <pkgmgr-info.h>
 #include <stdexcept>
 
-#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<Bundle> 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<ComplicationType>(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<ComplicationType>(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<int>(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<std::unique_ptr<Bundle>> candidates_list) {
-  return UpdateCandidatesInfo();
+  return impl_->UpdateCandidatesInfo();
 }
 
 std::list<std::unique_ptr<Bundle>> 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<std::string> 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<Bundle>& 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<std::unique_ptr<ProviderInfo>> allowed_list) {
   impl_->allowed_list_ = std::move(allowed_list);
   impl_->candidates_list_.clear();
-  return UpdateCandidatesInfo();
+  return impl_->UpdateCandidatesInfo();
 }
 
 int Complication::ClearAllowedList() {
index bab18d7..7be8b12 100644 (file)
@@ -72,6 +72,8 @@ class EXPORT_API Complication : public IEditable
   void OnDataUpdated(const std::string& provider_id,
                     ComplicationType type,
                     const std::unique_ptr<Bundle>& 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<Bundle>& GetLastContext() const override;
   const std::string GetSetupAppId() override;
+
   int SendDataUpdateRequest();
   const char* GetCurProviderId();
   const char* GetProviderId(const Bundle* data);
index 0b1336f..6ecd268 100644 (file)
@@ -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<std::string> DBManager::GetProviderList(int support_type) {
   return provider_list;
 }
 
+std::list<std::string> DBManager::GetProviderListWithAppId(
+    const char* provider_id) {
+  int ret;
+  char* provider = NULL;
+  sqlite3_stmt* stmt;
+  sqlite3* db;
+  std::list<std::string> 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;
index a15b031..c247b4c 100644 (file)
@@ -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<std::string> GetProviderListWithAppId(const char* provider_id);
 
  private:
   DBManager();
index cd89125..caebc4d 100644 (file)
@@ -228,5 +228,34 @@ std::unique_ptr<Bundle> 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<Bundle> 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
index d0f2083..9c8a0f1 100644 (file)
@@ -34,6 +34,7 @@ class EXPORT_API EditablesManager {
   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);
+  int DeleteContext(int editable_id, const char* provider_id);
 
  private:
   EditablesManager();
index 6b6ff68..5f2517f 100644 (file)
@@ -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
index 620b6a1..9bb2201 100644 (file)
@@ -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<watchface_complication_type_e>(type),
+        static_cast<watchface_complication_error_e>(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<watchface_complication_type_e>(type),
+        static_cast<watchface_complication_error_e>(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<Bundle>& 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<SharedHandle<WatchComplicationStub>*>(handle);
   auto ptr = SharedHandle<WatchComplicationStub>::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;
index ab7a6e4..030e4ea 100644 (file)
@@ -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
+}