From: Tomasz Marciniak Date: Thu, 26 Jan 2017 12:23:10 +0000 (+0100) Subject: [Application] Added APIs for listening status of applications X-Git-Tag: submit/tizen/20170426.113227~1^2 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=e79ebf73fec3624ad8e35d3caf741e1184f984d3;p=platform%2Fcore%2Fapi%2Fwebapi-plugins.git [Application] Added APIs for listening status of applications [Verification] Code compiles. Change-Id: I320493804fafd9efa26f1f6cbe3a4425a845d1a7 Signed-off-by: Tomasz Marciniak --- diff --git a/src/application/application_api.js b/src/application/application_api.js index 77805ef8..ca329eba 100755 --- a/src/application/application_api.js +++ b/src/application/application_api.js @@ -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) { diff --git a/src/application/application_instance.cc b/src/application/application_instance.cc index cb8d850a..93a27e94 100755 --- a/src/application/application_instance.cc +++ b/src/application/application_instance.cc @@ -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 diff --git a/src/application/application_instance.h b/src/application/application_instance.h index cb99cbb4..e96af8c2 100755 --- a/src/application/application_instance.h +++ b/src/application/application_instance.h @@ -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_; diff --git a/src/application/application_manager.cc b/src/application/application_manager.cc index 328d6ffd..8f34ce57 100755 --- a/src/application/application_manager.cc +++ b/src/application/application_manager.cc @@ -20,7 +20,6 @@ #include #include -#include #include #include #include @@ -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 event_map_ = { {SYSTEM_EVENT_BATTERY_CHARGER_STATUS, EVENT_KEY_BATTERY_CHARGER_STATUS}, @@ -98,13 +101,22 @@ const std::map 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(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(); + + 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 diff --git a/src/application/application_manager.h b/src/application/application_manager.h index f5585b3c..3dda24aa 100755 --- a/src/application/application_manager.h +++ b/src/application/application_manager.h @@ -18,6 +18,7 @@ #define SRC_APPLICATION_APPLICATION_MANAGER_H__ #include +#include #include #include #include @@ -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 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