[Application] Added APIs for listening status of applications 75/116475/5
authorTomasz Marciniak <t.marciniak@samsung.com>
Thu, 26 Jan 2017 12:23:10 +0000 (13:23 +0100)
committerTomasz Marciniak <t.marciniak@samsung.com>
Wed, 29 Mar 2017 13:00:16 +0000 (15:00 +0200)
[Verification] Code compiles.

Change-Id: I320493804fafd9efa26f1f6cbe3a4425a845d1a7
Signed-off-by: Tomasz Marciniak <t.marciniak@samsung.com>
src/application/application_api.js
src/application/application_instance.cc
src/application/application_instance.h
src/application/application_manager.cc
src/application/application_manager.h

index 77805ef87c68c4d309e7a170d523cee989cf8a39..ca329eba024ca64b9e02462d04e11c948c73f40d 100755 (executable)
@@ -592,6 +592,110 @@ ApplicationManager.prototype.removeAppInfoEventListener = function() {
   applicationEventListener.removeListener(args.watchId);
 };
 
+function StatusListenerManager(native, listenerName) {
+  this.listeners = {};
+  this.listenersCount = 0;
+  this.nextId = 1;
+  this.nativeSet = false;
+  this.native = native;
+  this.listenerName = listenerName;
+};
+
+StatusListenerManager.prototype.onListenerCalled = function(msg) {
+  var statusType = msg.statusType;
+  var app_id = msg.appId;
+
+  for (var watchId in this.listeners) {
+    if (this.listeners.hasOwnProperty(watchId)) {
+      var listener = this.listeners[watchId];
+      if (!listener.appId || listener.appId === app_id) {
+        listener.callback(app_id, statusType);
+      }
+    }
+  }
+};
+
+StatusListenerManager.prototype.addListener = function(callback, appId) {
+  if (!this.nativeSet) {
+    var result = this.native.callSync('ApplicationManager_addAppStatusChangeListener');
+    if (this.native.isFailure(result)) {
+      throw this.native.getErrorObject(result);
+    }
+
+    this.native.addListener(this.listenerName, this.onListenerCalled.bind(this));
+    this.nativeSet = true;
+  }
+
+  var listener = {
+    'callback' : callback,
+    'appId' : appId
+  };
+
+  var id = this.nextId++;
+  this.listeners[id] = listener;
+  this.listenersCount++;
+
+  return id;
+};
+
+StatusListenerManager.prototype.removeListener = function(watchId) {
+  if (this.listeners.hasOwnProperty(watchId)) {
+    if (this.listenersCount > 1) {
+      delete this.listeners[watchId];
+      this.listenersCount--;
+      return;
+    }
+
+    if (this.nativeSet) {
+      var result = this.native.callSync('ApplicationManager_removeStatusChangeListener');
+      if (this.native.isFailure(result)) {
+        throw this.native.getErrorObject(result);
+      }
+
+      delete this.listeners[watchId];
+      this.listenersCount--;
+
+      this.native.removeListener(this.listenerName);
+      this.nativeSet = false;
+    }
+  }
+};
+
+var APP_STATUS_CHANGE_LISTENER = 'AppStatusChangeListener';
+var appStatusChangeListener = new StatusListenerManager(native, APP_STATUS_CHANGE_LISTENER);
+
+ApplicationManager.prototype.addAppStatusChangeListener = function() {
+  var args = AV.validateMethod(arguments, [
+      {
+        name : 'statusChangeListener',
+        type : AV.Types.FUNCTION,
+      },
+      {
+        name : 'appId',
+        type : AV.Types.STRING,
+        optional : true,
+        nullable : true
+      }
+  ]);
+
+  if (args.appId !== undefined && args.appId !== null && !args.appId.length) {
+    throw new WebAPIException(WebAPIException.INVALID_VALUES_ERR, 'Application id is empty');
+  }
+
+  return appStatusChangeListener.addListener(args.statusChangeListener, args.appId);
+};
+
+ApplicationManager.prototype.removeAppStatusChangeListener = function() {
+  var args = AV.validateMethod(arguments, [
+      {
+        name : 'watchId',
+        type : AV.Types.LONG
+      }
+  ]);
+
+  appStatusChangeListener.removeListener(args.watchId);
+};
+
 // class Application ////////////////////////////////////////////////////
 
 function Application(data) {
index cb8d850ae56785343748ccdf27fcfddaddca77db..93a27e946ea1c82949ee4c820a762fea396929e6 100755 (executable)
@@ -61,6 +61,8 @@ ApplicationInstance::ApplicationInstance() :
   REGISTER_SYNC("ApplicationManager_getAppMetaData", GetAppMetaData);
   REGISTER_SYNC("ApplicationManager_addAppInfoEventListener", AddAppInfoEventListener);
   REGISTER_SYNC("ApplicationManager_removeAppInfoEventListener", RemoveAppInfoEventListener);
+  REGISTER_SYNC("ApplicationManager_addAppStatusChangeListener", AddStatusListener);
+  REGISTER_SYNC("ApplicationManager_removeStatusChangeListener", RemoveStatusListener);
 
   //Application
   REGISTER_SYNC("Application_getRequestedAppControl", GetRequestedAppControl);
@@ -287,5 +289,31 @@ void ApplicationInstance::RemoveEventListener(const picojson::value& args, picoj
   manager_.StopEventListener(event_name);
 }
 
+void ApplicationInstance::AddStatusListener(const picojson::value& args, picojson::object& out) {
+  LoggerD("Entered");
+
+  JsonCallback cb = [this](picojson::value* event) -> void {
+    Instance::PostMessage(this, event->serialize().c_str());
+  };
+
+  PlatformResult result = manager_.StartStatusListener(cb);
+  if (result) {
+    ReportSuccess(out);
+  } else {
+    LogAndReportError(result, &out);
+  }
+}
+
+void ApplicationInstance::RemoveStatusListener(const picojson::value& args, picojson::object& out) {
+  LoggerD("Entered");
+
+  PlatformResult result = manager_.StopStatusChangeListener();
+  if (result) {
+    ReportSuccess(out);
+  } else {
+    LogAndReportError(result, &out);
+  }
+}
+
 }  // namespace application
 }  // namespace extension
index cb99cbb4e99b65abddfc3517b52c0ac973df9af9..e96af8c2307a41ede29c1edb9be32dc9d0a6009f 100755 (executable)
@@ -54,6 +54,8 @@ class ApplicationInstance: public common::ParsedInstance {
   void BroadcastTrustedEvent(const picojson::value& args, picojson::object& out);
   void AddEventListener(const picojson::value& args, picojson::object& out);
   void RemoveEventListener(const picojson::value& args, picojson::object& out);
+  void AddStatusListener(const picojson::value& args, picojson::object& out);
+  void RemoveStatusListener(const picojson::value& args, picojson::object& out);
 
   ApplicationManager manager_;
   Application current_application_;
index 328d6ffd729cb211e04403cd7f32d7b6b2c886a3..8f34ce57598906c8c79c5d1c8b13697a3587f47e 100755 (executable)
@@ -20,7 +20,6 @@
 #include <unistd.h>
 
 #include <app_info.h>
-#include <app_manager.h>
 #include <app_manager_extension.h>
 #include <aul.h>
 #include <pkgmgr_installer.h>
@@ -68,6 +67,10 @@ const std::string kOnInstalled = "oninstalled";
 const std::string kOnUpdated = "onupdated";
 const std::string kOnUninstalled = "onuninstalled";
 const std::string kData = "data";
+const std::string kStatusType = "statusType";
+const std::string kAppId = "appId";
+const std::string kListenerId = "listenerId";
+const std::string kAppStatusChangeListener = "AppStatusChangeListener";
 
 const std::map<std::string, std::string> event_map_ = {
   {SYSTEM_EVENT_BATTERY_CHARGER_STATUS, EVENT_KEY_BATTERY_CHARGER_STATUS},
@@ -98,13 +101,22 @@ const std::map<std::string, std::string> event_map_ = {
 ApplicationManager::ApplicationManager(ApplicationInstance& instance) :
   pkgmgr_client_handle_(nullptr),
   pkgmgr_client_uninstall_handle_(nullptr),
-  instance_(instance) {
+  instance_(instance),
+  app_status_handle_(nullptr) {
     LoggerD("Enter");
 }
 
 ApplicationManager::~ApplicationManager() {
   LoggerD("Enter");
   StopAppInfoEventListener();
+  StopStatusChangeListener();
+
+  if (app_status_handle_) {
+    int ret = app_manager_event_destroy(app_status_handle_);
+    if (APP_MANAGER_ERROR_NONE != ret) {
+      LoggerE ("app_manager_event_destroy failed, error: %d", ret);
+    }
+  }
 }
 
 void ApplicationManager::GetCurrentApplication(const std::string& app_id,
@@ -1626,5 +1638,89 @@ void ApplicationManager::StopEventListener(const std::string& event_name) {
   }
 }
 
+void ApplicationManager::OnStatusEvent(const char *type, const char *app_id,
+                                       app_manager_event_type_e event_type,
+                                       app_manager_event_state_e event_state,
+                                       app_manager_event_h handle, void *user_data) {
+  LoggerD("Entered");
+
+  if (APP_MANAGER_EVENT_STATE_COMPLETED != event_state) {
+    LoggerD("State different from completed");
+    return;
+  }
+
+  ApplicationManager* manager = static_cast<ApplicationManager*>(user_data);
+
+  if (!manager || !manager->status_callback_) {
+    LoggerD("No event listener registered, skipping.");
+    return;
+  }
+
+  bool status_type;
+  switch (event_type) {
+    case APP_MANAGER_EVENT_ENABLE_APP:
+      status_type = true;
+      break;
+    case APP_MANAGER_EVENT_DISABLE_APP:
+      status_type = false;
+      break;
+    default:
+      LoggerD("Uknown status type skipping.");
+      return;
+  }
+
+  picojson::value event = picojson::value(picojson::object());
+  picojson::object& event_o = event.get<picojson::object>();
+
+  event_o[kStatusType] = picojson::value(status_type);
+  event_o[kAppId] = picojson::value(app_id);
+  event_o[kListenerId] = picojson::value(kAppStatusChangeListener);
+
+  manager->status_callback_(&event);
+}
+
+PlatformResult ApplicationManager::StartStatusListener(const JsonCallback& callback) {
+  LoggerD("Entered");
+
+  int ret = APP_MANAGER_ERROR_NONE;
+
+  if (!app_status_handle_) {
+    ret = app_manager_event_create(&app_status_handle_);
+    if (APP_MANAGER_ERROR_NONE != ret) {
+      return LogAndCreateResult(ErrorCode::ABORT_ERR, "Error while creating event handle",
+                                ("app_manager_event_create failed, error: %d", ret));
+    }
+
+    ret = app_manager_event_set_status(app_status_handle_, APP_MANAGER_EVENT_STATUS_TYPE_ALL);
+    if (APP_MANAGER_ERROR_NONE != ret) {
+      return LogAndCreateResult(ErrorCode::ABORT_ERR, "Error while setting status type",
+                                ("app_manager_event_set_status failed, error: %d", ret));
+    }
+  }
+
+  status_callback_ = callback;
+  ret = app_manager_set_event_cb(app_status_handle_, OnStatusEvent, this);
+  if (APP_MANAGER_ERROR_NONE != ret) {
+    return LogAndCreateResult(ErrorCode::ABORT_ERR, "Error while setting status listener",
+                              ("app_manager_set_event_cb failed, error: %d", ret));
+  }
+
+  return PlatformResult(ErrorCode::NO_ERROR);
+}
+
+PlatformResult ApplicationManager::StopStatusChangeListener() {
+  LoggerD("Entered");
+
+  if (app_status_handle_) {
+    int ret = app_manager_unset_event_cb(app_status_handle_);
+    if (APP_MANAGER_ERROR_NONE != ret) {
+      return LogAndCreateResult(ErrorCode::ABORT_ERR, "Error while removing status listener",
+                                ("app_manager_unset_event_cb failed, error: %d", ret));
+    }
+  }
+
+  return PlatformResult(ErrorCode::NO_ERROR);
+}
+
 } // namespace application
 } // namespace extension
index f5585b3c13fe2fbcf1e6fe8239993c9cf84bd34f..3dda24aa547e23181ff1ae89ec1b46e7882f5c38 100755 (executable)
@@ -18,6 +18,7 @@
 #define SRC_APPLICATION_APPLICATION_MANAGER_H__
 
 #include <app_event.h>
+#include <app_manager.h>
 #include <bundle.h>
 #include <functional>
 #include <memory>
@@ -61,6 +62,8 @@ class ApplicationManager {
   common::PlatformResult StartEventListener(const std::string& event_name,
                                             const JsonCallback& callback);
   void StopEventListener(const std::string& event_name);
+  common::PlatformResult StartStatusListener(const JsonCallback& callback);
+  common::PlatformResult StopStatusChangeListener();
 
  private:
   char* GetPackageId(const std::string& app_id);
@@ -68,12 +71,19 @@ class ApplicationManager {
   pkgmgr_client* pkgmgr_client_handle_;
   pkgmgr_client* pkgmgr_client_uninstall_handle_;
   ApplicationInstance& instance_;
+  app_manager_event_h app_status_handle_;
 
   JsonCallback event_callback_;
+  JsonCallback status_callback_;
   std::map<std::string, event_handler_h> event_handler_map_;
   static void OnEvent(const char* event_name,
                       bundle* event_data,
                       void* user_data);
+  static void OnStatusEvent(const char *type, const char *app_id,
+                            app_manager_event_type_e event_type,
+                            app_manager_event_state_e event_state,
+                            app_manager_event_h handle,
+                            void *user_data);
 };
 
 } // namespace application