From b9d5aa3b8562a3ddf31036d6644dd4da448d364d Mon Sep 17 00:00:00 2001 From: ByungWoo Lee Date: Fri, 6 Feb 2015 10:10:37 +0900 Subject: [PATCH] [Account] Initial implementation. [Verification] Code compiles, TCT pass rate: 57/89. Change-Id: I1ddb7d67b6cc1b619b5b6a12c31cf907dc17fe9c --- packaging/webapi-plugins.spec | 6 +- src/account/account.gyp | 30 +++ src/account/account_api.js | 421 +++++++++++++++++++++++++++++++ src/account/account_extension.cc | 31 +++ src/account/account_extension.h | 19 ++ src/account/account_instance.cc | 324 ++++++++++++++++++++++++ src/account/account_instance.h | 57 +++++ src/account/account_manager.cc | 382 ++++++++++++++++++++++++++++ src/account/account_manager.h | 56 ++++ src/tizen-wrt.gyp | 1 + 10 files changed, 1326 insertions(+), 1 deletion(-) create mode 100644 src/account/account.gyp create mode 100644 src/account/account_api.js create mode 100644 src/account/account_extension.cc create mode 100644 src/account/account_extension.h create mode 100644 src/account/account_instance.cc create mode 100644 src/account/account_instance.h create mode 100644 src/account/account_manager.cc create mode 100644 src/account/account_manager.h diff --git a/packaging/webapi-plugins.spec b/packaging/webapi-plugins.spec index a2b0f313..97d25be3 100644 --- a/packaging/webapi-plugins.spec +++ b/packaging/webapi-plugins.spec @@ -18,7 +18,7 @@ Source0: %{name}-%{version}.tar.gz #################################################################### %if "%{?profile}" == "mobile" -%define tizen_feature_account_support 0 +%define tizen_feature_account_support 1 %define tizen_feature_archive_support 0 %define tizen_feature_badge_support 0 %define tizen_feature_bluetooth_support 0 @@ -187,6 +187,10 @@ BuildRequires: pkgconfig(capi-appfw-app-manager) BuildRequires: pkgconfig(capi-appfw-package-manager) BuildRequires: pkgconfig(wrt-plugins-ipc-message) +%if 0%{?tizen_feature_account_support} +BuildRequires: pkgconfig(accounts-svc) +%endif + %if 0%{?tizen_feature_datacontrol_support} BuildRequires: pkgconfig(capi-data-control) %endif diff --git a/src/account/account.gyp b/src/account/account.gyp new file mode 100644 index 00000000..3a5a3020 --- /dev/null +++ b/src/account/account.gyp @@ -0,0 +1,30 @@ +{ + 'includes':[ + '../common/common.gypi', + ], + 'targets': [ + { + 'target_name': 'tizen_account', + 'type': 'loadable_module', + 'sources': [ + 'account_api.js', + 'account_extension.cc', + 'account_extension.h', + 'account_instance.cc', + 'account_instance.h', + 'account_manager.cc', + 'account_manager.h', + ], + 'conditions': [ + ['tizen == 1', { + 'variables': { + 'packages': [ + 'capi-appfw-package-manager', + 'accounts-svc', + ] + }, + }], + ], + }, + ], +} diff --git a/src/account/account_api.js b/src/account/account_api.js new file mode 100644 index 00000000..01061e04 --- /dev/null +++ b/src/account/account_api.js @@ -0,0 +1,421 @@ +/* global tizen, xwalk, extension */ + +// Copyright 2015 Samsung Electronics Co, Ltd. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + + +var validator_ = xwalk.utils.validator; +var types_ = validator_.Types; + +var callbackId = 0; +var callbacks = {}; + +var lastAccountChangeListenerId = -1; +var accountChangeListener = {}; + +function invokeListener(result) { + if (result.listener === 'accountChange') { + for (var listenerId in accountChangeListener) { + console.log("[Account][invokeListener] AccountChangeListenerId: " + listenerId); + var listener = callbacks[accountChangeListener[listenerId]]; + listener(result); + } + } +} + +extension.setMessageListener(function(json) { + var result = JSON.parse(json); + + if (result.hasOwnProperty('listener')) { + console.log("[Account][setMessageListener] Call listner"); + invokeListener(result); + } else { + console.log("[Account][setMessageListener] Call callback"); + var callback = callbacks[result.callbackId]; + callback(result); + } +}); + +function nextCallbackId() { + return callbackId++; +} + +function nextAccountChangeListenerId() { + return ++lastAccountChangeListenerId; +} + +function callNative(cmd, args) { + var json = {'cmd': cmd, 'args': args}; + var argjson = JSON.stringify(json); + var resultString = extension.internal.sendSyncMessage(argjson); + var result = JSON.parse(resultString); + + if (typeof result !== 'object') { + throw new tizen.WebAPIException(tizen.WebAPIException.UNKNOWN_ERR); + } + + if (result.status === 'success') { + if (result.result) { + return result.result; + } + return true; + } else if (result.status === 'error') { + var err = result.error; + if (err) { + throw new tizen.WebAPIException(err.name, err.message); + } + return false; + } +} + + +function callNativeWithCallback(cmd, args, callback) { + if (callback) { + var id = nextCallbackId(); + args.callbackId = id; + callbacks[id] = callback; + } + + return callNative(cmd, args); +} + +function SetReadOnlyProperty(obj, n, v){ + if (v) + Object.defineProperty(obj, n, {value:v, writable: false, enumerable: true, configurable: true}); + else + Object.defineProperty(obj, n, {writable: false, enumerable: true, configurable: true}); +} + +function AccountProvider(providerInfo) { + SetReadOnlyProperty(this, 'applicationId', providerInfo.applicationId); // read only property + SetReadOnlyProperty(this, 'displayName', providerInfo.displayName); // read only property + SetReadOnlyProperty(this, 'iconUri', providerInfo.iconUri); // read only property + SetReadOnlyProperty(this, 'smallIconUri', providerInfo.smallIconUri); // read only property + SetReadOnlyProperty(this, 'capabilities', providerInfo.capabilities); // read only property + SetReadOnlyProperty(this, 'isMultipleAccountSupported', providerInfo.isMultipleAccountSupported); // read only property +} + +function SetAccountId(account, accountId) { + + Object.defineProperty(account, 'id', {writable: true}); + account.id = accountId; + Object.defineProperty(account, 'id', {writable: false}); + + return account; +} + +function Account(provider, accountInitDict) { + console.log("[Constructor of Account] Enter"); + + var args = validator_.validateArgs(arguments, [ + {'name' : 'provider', 'type' : types_.PLATFORM_OBJECT, 'values' : AccountProvider}, + {'name' : 'accountInitDict', + 'type' : types_.DICTIONARY, + 'optional' : true, + 'nullable' : true + } + ]); + + SetReadOnlyProperty(this, 'id', null); // read only property + SetReadOnlyProperty(this, 'provider', provider); // read only property + if(arguments.length > 1) { + this.userName = accountInitDict.userName; + this.iconUri = accountInitDict.iconUri; + } else { + this.userName = null; + this.iconUri = null; + } +} + +function MakeAccountObject(obj) { + console.log("[Account][MakeAccountObject] Enter"); + var account = new Account(new AccountProvider(obj.provider), obj.accountInitDict); + return SetAccountId(account, obj.id); +} + +Account.prototype.setExtendedData = function(key, value) { + var args = validator_.validateArgs(arguments, [ + {'name': 'key', 'type': types_.STRING}, + {'name': 'value', 'type': types_.STRING} + ]); + + var nativeParam = { + 'key': args.key, + 'value': args.value + }; + + + try { + var syncResult = callNative('Account_setExtendedData', nativeParam); + // if you need synchronous result from native function using 'syncResult'. + } catch (e) { + throw e; + } + +}; + +Account.prototype.getExtendedData = function(key) { + var args = validator_.validateArgs(arguments, [ + {'name': 'key', 'type': types_.STRING} + ]); + + var nativeParam = { + 'key': args.key + }; + + + try { + var syncResult = callNative('Account_getExtendedData', nativeParam); + // if you need synchronous result from native function using 'syncResult'. + } catch (e) { + throw e; + } + +}; + +Account.prototype.getExtendedData = function(successCallback, errorCallback) { + var args = validator_.validateArgs(arguments, [ + {'name': 'successCallback', 'type': types_.LISTENER, 'values': ['onsuccess']}, + {'name': 'errorCallback', 'type': types_.FUNCTION} + ]); + + var nativeParam = { + }; + + + try { + var syncResult = callNative('Account_getExtendedData', nativeParam); + // if you need synchronous result from native function using 'syncResult'. + } catch (e) { + throw e; + } + +}; + + + +function AccountManager() { + // constructor of AccountManager + +} + + +AccountManager.prototype.add = function(account) { + var args = validator_.validateArgs(arguments, [ + {'name': 'account', 'type': types_.PLATFORM_OBJECT, 'values': Account} + ]); + + var nativeParam = { + }; + + + try { + var syncResult = callNative('AccountManager_add', nativeParam); + // if you need synchronous result from native function using 'syncResult'. + } catch (e) { + throw e; + } + +}; + +AccountManager.prototype.remove = function(accountId) { + var args = validator_.validateArgs(arguments, [ + {'name': 'accountId', 'type': types_.LONG} + ]); + + var nativeParam = { + 'accountId': args.accountId + }; + + + try { + var syncResult = callNative('AccountManager_remove', nativeParam); + // if you need synchronous result from native function using 'syncResult'. + } catch (e) { + throw e; + } + +}; + +AccountManager.prototype.update = function(account) { + var args = validator_.validateArgs(arguments, [ + {'name': 'account', 'type': types_.PLATFORM_OBJECT, 'values': Account} + ]); + + var nativeParam = { + }; + + + try { + var syncResult = callNative('AccountManager_update', nativeParam); + // if you need synchronous result from native function using 'syncResult'. + } catch (e) { + throw e; + } + +}; + +AccountManager.prototype.getAccount = function(accountId) { + console.log("[AccountManager][getAccount] Enter"); + var args = validator_.validateArgs(arguments, [ + {'name': 'accountId', 'type': types_.UNSIGNED_LONG} + ]); + + var nativeParam = { + 'accountId': args.accountId + }; + + try { + var syncResult = callNative('AccountManager_getAccount', nativeParam); + // if you need synchronous result from native function using 'syncResult'. + } catch (e) { + throw e; + } + + var returnObject = new Account(); + return returnObject; +}; + +AccountManager.prototype.getAccounts = function(successCallback, errorCallback, applicationId) { + var args = validator_.validateArgs(arguments, [ + {'name': 'successCallback', 'type': types_.LISTENER, 'values': ['onsuccess']}, + {'name': 'errorCallback', 'type': types_.FUNCTION}, + {'name': 'applicationId', 'type': types_.STRING} + ]); + + var nativeParam = { + }; + + if (args.applicationId) { + nativeParam.applicationId = args.applicationId; + } + + try { + var syncResult = callNative('AccountManager_getAccounts', nativeParam); + // if you need synchronous result from native function using 'syncResult'. + } catch (e) { + throw e; + } + +}; + +AccountManager.prototype.getProvider = function(applicationId) { + var args = validator_.validateArgs(arguments, [ + {'name': 'applicationId', 'type': types_.STRING} + ]); + + var nativeParam = { + 'applicationId': args.applicationId + }; + + try { + var syncResult = callNative('AccountManager_getProvider', nativeParam); + return new AccountProvider(syncResult); + } catch (e) { + throw e; + } +}; + +AccountManager.prototype.getProviders = function(successCallback, errorCallback, capability) { + var args = validator_.validateArgs(arguments, [ + {'name' : 'successCallback', 'type' : types_.FUNCTION}, + {'name' : 'errorCallback', 'type' : types_.FUNCTION, 'optional' : true, 'nullable' : true}, + {'name' : 'capability', 'type' : types_.STRING, 'optional' : true, 'nullable' : true} + ]); + + var nativeParam = { + }; + + if (args.capability) { + nativeParam.capability = args.capability; + } + + try { + var syncResult = callNativeWithCallback( + 'AccountManager_getProviders', + nativeParam, + function(param) { + if (param.status == 'success') { + for (var i = 0; i < param.result.length; i++) { + param.result[i] = new AccountProvider(param.result[i]); + } + args.successCallback(param.result); + } else if (param.status == 'error') { + var err = param.error; + if (err) { + args.errorCallback(new tizen.WebAPIError(err.name, err.message)); + return; + } + } + + delete callbacks[param.callbackId]; + }); + } catch (e) { + throw e; + } +}; + +AccountManager.prototype.addAccountListener = function(callback) { + var args = validator_.validateArgs( + arguments, + [ + {'name' : 'callback', + 'type' : types_.LISTENER, + 'values' : ['onadded', 'onremoved', 'onupdated']} + ]); + + var nativeParam = { + }; + + try { + var syncResult = callNativeWithCallback( + 'AccountManager_addAccountListener', + nativeParam, + function(param) { + if (param.status === 'added') { + args.callback.onadded(MakeAccountObject(param.result)); + } else if (param.status === 'removed') { + args.callback.onremoved(param.result); + } else if (param.status === 'updated') { + args.callback.onupdated(MakeAccountObject(param.result)); + } + }); + + console.log("[Account][addAccountListener] callbackId: " + nativeParam.callbackId); + var listenerId = nextAccountChangeListenerId(); + accountChangeListener[listenerId] = nativeParam.callbackId; + console.log("[Account][addAccountListener] listenerId: " + listenerId); + return listenerId; + } catch (e) { + throw e; + } +}; + +AccountManager.prototype.removeAccountListener = function(accountListenerId) { + var args = validator_.validateArgs(arguments, [ + {'name': 'accountListenerId', 'type': types_.LONG} + ]); + + var nativeParam = { + }; + + try { + if (args.accountListenerId in accountChangeListener) { + delete callbacks[accountChangeListener[args.accountListenerId]]; + delete accountChangeListener[args.accountListenerId]; + } + + if (Object.keys(accountChangeListener).length === 0) { + console.log("[Account][removeAccountListener] Unscribe native notification"); + var syncResult = callNative('AccountManager_removeAccountListener', nativeParam); + } + } catch (e) { + throw e; + } +}; + +tizen.Account = Account; + +exports = new AccountManager(); + diff --git a/src/account/account_extension.cc b/src/account/account_extension.cc new file mode 100644 index 00000000..532229be --- /dev/null +++ b/src/account/account_extension.cc @@ -0,0 +1,31 @@ +// Copyright 2015 Samsung Electronics Co, Ltd. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "account/account_extension.h" + +#include "account/account_instance.h" + +// This will be generated from account_api.js +extern const char kSource_account_api[]; + +common::Extension* CreateExtension() { + return new AccountExtension; +} + +AccountExtension::AccountExtension() { + SetExtensionName("tizen.account"); + SetJavaScriptAPI(kSource_account_api); + + const char* entry_points[] = { + "tizen.Account", + NULL + }; + SetExtraJSEntryPoints(entry_points); +} + +AccountExtension::~AccountExtension() {} + +common::Instance* AccountExtension::CreateInstance() { + return new extension::account::AccountInstance; +} \ No newline at end of file diff --git a/src/account/account_extension.h b/src/account/account_extension.h new file mode 100644 index 00000000..b0754554 --- /dev/null +++ b/src/account/account_extension.h @@ -0,0 +1,19 @@ +// Copyright 2015 Samsung Electronics Co, Ltd. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ACCOUNT_ACCOUNT_EXTENSION_H_ +#define ACCOUNT_ACCOUNT_EXTENSION_H_ + +#include "common/extension.h" + +class AccountExtension : public common::Extension { + public: + AccountExtension(); + virtual ~AccountExtension(); + + private: + virtual common::Instance* CreateInstance(); +}; + +#endif // ACCOUNT_ACCOUNT_EXTENSION_H_ diff --git a/src/account/account_instance.cc b/src/account/account_instance.cc new file mode 100644 index 00000000..e6779ba4 --- /dev/null +++ b/src/account/account_instance.cc @@ -0,0 +1,324 @@ +// Copyright 2015 Samsung Electronics Co, Ltd. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "account/account_instance.h" + +#include "string.h" + +#include + +#include "common/picojson.h" +#include "common/logger.h" +#include "common/task-queue.h" +#include "common/platform_exception.h" + +namespace extension { +namespace account { + +using common::TaskQueue; +using common::TypeMismatchException; +using common::UnknownException; +using common::SecurityException; + +namespace { +// The privileges that required in Account API +const std::string kPrivilegeAccountRead = + "http://tizen.org/privilege/account.read"; +const std::string kPrivilegeAccountWrite = + "http://tizen.org/privilege/account.write"; + +void CheckAccess(const std::string& privilege, picojson::object* out) { + LoggerD("Enter"); + + /* TODO: Need to check privilege + ReportError( + SecurityException("This application does not have " \ + "the privilege to call this method"), + out); + return; + */ +} + +} // namespace + +#define CHECK_EXIST(args, name, out) \ + if (!args.contains(name)) {\ + ReportError(TypeMismatchException(name" is required argument"), out);\ + return;\ + } + +AccountInstance::AccountInstance() { + LoggerD("Enter"); + + manager_ = new AccountManager; + subscribe_ = NULL; + + using namespace std::placeholders; + #define REGISTER_SYNC(c,x) \ + RegisterSyncHandler(c, std::bind(&AccountInstance::x, this, _1, _2)); + REGISTER_SYNC("AccountManager_removeAccountListener", AccountManagerRemoveAccountListener); + REGISTER_SYNC("AccountManager_update", AccountManagerUpdate); + REGISTER_SYNC("AccountManager_remove", AccountManagerRemove); +// REGISTER_SYNC("Account_constructor", AccountConstructor); + REGISTER_SYNC("AccountManager_getAccount", AccountManagerGetAccount); + REGISTER_SYNC("AccountManager_getProvider", AccountManagerGetProvider); + REGISTER_SYNC("Account_setExtendedData", AccountSetExtendedData); + REGISTER_SYNC("AccountManager_addAccountListener", AccountManagerAddAccountListener); + REGISTER_SYNC("AccountManager_add", AccountManagerAdd); + REGISTER_SYNC("AccountManager_getAccounts", AccountManagerGetAccounts); + REGISTER_SYNC("Account_getExtendedData", AccountGetExtendedData); + REGISTER_SYNC("AccountManager_getProviders", AccountManagerGetProviders); + #undef REGISTER_SYNC +} + +AccountInstance::~AccountInstance() { + LoggerD("Enter"); + delete manager_; + if (subscribe_) { + account_unsubscribe_notification(subscribe_); + } +} + +AccountManager* AccountInstance::GetAccountManager() { + LoggerD("Enter"); + return manager_; +} + +void AccountInstance::AccountSetExtendedData(const picojson::value& args, + picojson::object& out) { + LoggerD("Enter"); + + CheckAccess(kPrivilegeAccountWrite, &out); + + CHECK_EXIST(args, "key", out) + CHECK_EXIST(args, "value", out) + + const std::string& key = args.get("key").get(); + const std::string& value = args.get("value").get(); + + // implement it + + // if success + // ReportSuccess(out); + // if error + // ReportError(out); +} + +void AccountInstance::AccountGetExtendedData(const picojson::value& args, + picojson::object& out) { + LoggerD("Enter"); + + CheckAccess(kPrivilegeAccountRead, &out); + + CHECK_EXIST(args, "key", out) + + const std::string& key = args.get("key").get(); + + // implement it + + // if success + // ReportSuccess(out); + // if error + // ReportError(out); +} + +void AccountInstance::AccountManagerAdd(const picojson::value& args, + picojson::object& out) { + LoggerD("Enter"); + + CheckAccess(kPrivilegeAccountWrite, &out); + + // implement it + + // if success + // ReportSuccess(out); + // if error + // ReportError(out); +} + +void AccountInstance::AccountManagerRemove(const picojson::value& args, + picojson::object& out) { + LoggerD("Enter"); + + CheckAccess(kPrivilegeAccountWrite, &out); + + // implement it + + // if success + // ReportSuccess(out); + // if error + // ReportError(out); +} + +void AccountInstance::AccountManagerUpdate(const picojson::value& args, + picojson::object& out) { + LoggerD("Enter"); + + CheckAccess(kPrivilegeAccountWrite, &out); + + // implement it + + // if success + // ReportSuccess(out); + // if error + // ReportError(out); +} + +void AccountInstance::AccountManagerGetAccount(const picojson::value& args, + picojson::object& out) { + LoggerD("Enter"); + + CheckAccess(kPrivilegeAccountRead, &out); + + // implement it + + // if success + // ReportSuccess(out); + // if error + // ReportError(out); +} + +void AccountInstance::AccountManagerGetAccounts(const picojson::value& args, + picojson::object& out) { + LoggerD("Enter"); + + CheckAccess(kPrivilegeAccountRead, &out); + + // implement it + + // if success + // ReportSuccess(out); + // if error + // ReportError(out); +} + +void AccountInstance::AccountManagerGetProvider(const picojson::value& args, + picojson::object& out) { + LoggerD("Enter"); + + CheckAccess(kPrivilegeAccountRead, &out); + + std::string application_id = args.get("applicationId").get(); + LoggerD("application_id [%s]", application_id.c_str()); + + manager_->GetProviderInfo(application_id, out); +} + +void AccountInstance::AccountManagerGetProviders(const picojson::value& args, + picojson::object& out) { + LoggerD("Enter"); + + CheckAccess(kPrivilegeAccountRead, &out); + + CHECK_EXIST(args, "callbackId", out) + int callback_id = static_cast(args.get("callbackId").get()); + + const std::string capability = args.contains("capability") ? args.get("capability").get() : ""; + + LoggerD("capability [%s]", capability.c_str()); + + auto get_providers = [this, capability](const std::shared_ptr& result) { + this->manager_->GetProvidersInfo(capability, result->get()); + }; + + auto get_providers_result = [this, callback_id](const std::shared_ptr& result) { + result->get()["callbackId"] = picojson::value{static_cast(callback_id)}; + this->PostMessage(result->serialize().c_str()); + }; + + TaskQueue::GetInstance().Queue( + get_providers, + get_providers_result, + std::shared_ptr{new picojson::value{picojson::object()}}); + + ReportSuccess(out); +} + +void AccountInstance::InvokeListener(picojson::object& param) { + LoggerD("Enter"); + picojson::value result = picojson::value(param); + PostMessage(result.serialize().c_str()); +} + +static bool AccountEventCb(const char *event_type, int account_id, + void *user_data) { + LoggerD("Enter"); + + AccountInstance* instance = static_cast(user_data); + if (!instance) { + LoggerE("instance is NULL"); + return false; + } + + picojson::object result; + result["listenerId"] = picojson::value("accountChange"); + if (!strcmp(event_type, ACCOUNT_NOTI_NAME_INSERT)) { + LoggerD("Added"); + result["status"] = picojson::value("added"); + picojson::object info; + instance->GetAccountManager()->GetAccountInfo(account_id, info); + result["result"] = picojson::value(info["result"]); + instance->InvokeListener(result); + } else if (!strcmp(event_type, ACCOUNT_NOTI_NAME_UPDATE)) { + LoggerD("Updated"); + result["status"] = picojson::value("updated"); + picojson::object info; + instance->GetAccountManager()->GetAccountInfo(account_id, info); + result["result"] = picojson::value(info["result"]); + instance->InvokeListener(result); + } else if (!strcmp(event_type, ACCOUNT_NOTI_NAME_DELETE)) { + LoggerD("Deleted"); + result["status"] = picojson::value("removed"); + result["result"] = picojson::value("account_id"); + instance->InvokeListener(result); + } + + return true; +} + +void AccountInstance::AccountManagerAddAccountListener( + const picojson::value& args, picojson::object& out) { + LoggerD("Enter"); + + CheckAccess(kPrivilegeAccountRead, &out); + + int ret = 0; + if (!subscribe_) { + ret = account_subscribe_create(&subscribe_); + if (ret != ACCOUNT_ERROR_NONE) { + LoggerE("Failed to create account subscribe"); + ReportError(UnknownException(manager_->GetErrorMsg(ret)), out); + return; + } + + ret = account_subscribe_notification(subscribe_, AccountEventCb, this); + if (ret != ACCOUNT_ERROR_NONE) { + LoggerE("Failed to subscribe notification"); + ReportError(UnknownException(manager_->GetErrorMsg(ret)), out); + return; + } + } + + ReportSuccess(out); +} + +void AccountInstance::AccountManagerRemoveAccountListener( + const picojson::value& args, picojson::object& out) { + LoggerD("Enter"); + + CheckAccess(kPrivilegeAccountRead, &out); + + if (subscribe_) { + if (account_unsubscribe_notification(subscribe_) != ACCOUNT_ERROR_NONE) { + LoggerE("Failed to unsubscribe notification"); + } + } + + ReportSuccess(out); +} + +#undef CHECK_EXIST + +} // namespace account +} // namespace extension diff --git a/src/account/account_instance.h b/src/account/account_instance.h new file mode 100644 index 00000000..048716ec --- /dev/null +++ b/src/account/account_instance.h @@ -0,0 +1,57 @@ +// Copyright 2015 Samsung Electronics Co, Ltd. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ACCOUNT_ACCOUNT_INSTANCE_H_ +#define ACCOUNT_ACCOUNT_INSTANCE_H_ + +#include + +#include "account/account_manager.h" +#include "common/extension.h" + +namespace extension { +namespace account { + +class AccountInstance : public common::ParsedInstance { + public: + AccountInstance(); + virtual ~AccountInstance(); + + AccountManager* GetAccountManager(); + void InvokeListener(picojson::object& param); + + private: + AccountManager* manager_; + account_subscribe_h subscribe_; + + void AccountManagerRemoveAccountListener( + const picojson::value& args, picojson::object& out); + void AccountManagerUpdate( + const picojson::value& args, picojson::object& out); + void AccountManagerRemove( + const picojson::value& args, picojson::object& out); + void AccountConstructor( + const picojson::value& args, picojson::object& out); + void AccountManagerGetAccount( + const picojson::value& args, picojson::object& out); + void AccountManagerGetProvider( + const picojson::value& args, picojson::object& out); + void AccountSetExtendedData( + const picojson::value& args, picojson::object& out); + void AccountManagerAddAccountListener( + const picojson::value& args, picojson::object& out); + void AccountManagerAdd( + const picojson::value& args, picojson::object& out); + void AccountManagerGetAccounts( + const picojson::value& args, picojson::object& out); + void AccountGetExtendedData( + const picojson::value& args, picojson::object& out); + void AccountManagerGetProviders( + const picojson::value& args, picojson::object& out); +}; + +} // namespace account +} // namespace extension + +#endif // ACCOUNT_ACCOUNT_INSTANCE_H_ diff --git a/src/account/account_manager.cc b/src/account/account_manager.cc new file mode 100644 index 00000000..b4754bd3 --- /dev/null +++ b/src/account/account_manager.cc @@ -0,0 +1,382 @@ +// Copyright 2014 Samsung Electronics Co, Ltd. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "account/account_manager.h" + +#include + +#include "common/logger.h" +#include "common/scope_exit.h" + +namespace extension { +namespace account { + +using common::ScopeExit; +using common::UnknownException; + +#define REPORT_ERROR(out, exception) \ + out["status"] = picojson::value("error"); \ + out["error"] = exception.ToJSON(); + +namespace { + +static bool ProviderCapabilitiesCb(char *app_id, char *key, void *user_data) { + LoggerD("Enter"); + + picojson::array* array_data = static_cast(user_data); + if (!array_data) { + LoggerE("user_data is NULL"); + return false; + } + + array_data->push_back(picojson::value(key)); + return true; +} + +static bool AccountProvidersGetCb(account_type_h provider, void *user_data) { + LoggerD("Enter"); + + picojson::array* array_data = static_cast(user_data); + if (!array_data) { + LoggerE("user_data is NULL"); + return false; + } + + picojson::object object_info; + if (AccountManager::ConvertProviderToObject(provider, object_info)) { + array_data->push_back(picojson::value(object_info)); + } + + return true; +} + +static bool GetAccountsCallback(account_h handle, void *user_data) { + LoggerD("Enter"); + + picojson::array* array_data = static_cast(user_data); + if (!array_data) { + LoggerE("user_data is NULL"); + return false; + } + + picojson::object object_info; + if (AccountManager::ConvertAccountToObject(handle, object_info)) { + array_data->push_back(picojson::value(object_info)); + } + + return true; +} + +} // namespace + +AccountManager::AccountManager() { + if (account_connect() != ACCOUNT_ERROR_NONE) { + LoggerE("Failed to connect account db"); + } +} + +AccountManager::~AccountManager() { + if (account_disconnect() != ACCOUNT_ERROR_NONE) { + LoggerE("Failed to disconnect account db"); + } +} + +std::string AccountManager::GetErrorMsg(int error) { + switch (error) { + case ACCOUNT_ERROR_OUT_OF_MEMORY: + return "Out of Memory"; + case ACCOUNT_ERROR_INVALID_PARAMETER: + return "Invalid Parameter"; + case ACCOUNT_ERROR_DUPLICATED: + return "Same user name exists in your application"; + case ACCOUNT_ERROR_NO_DATA: + return "Empty data"; + case ACCOUNT_ERROR_RECORD_NOT_FOUND: + return "Related record does not exist"; + case ACCOUNT_ERROR_DB_FAILED: + return "DB operation failed"; + case ACCOUNT_ERROR_DB_NOT_OPENED: + return "DB is not connected"; + case ACCOUNT_ERROR_QUERY_SYNTAX_ERROR: + return "DB query syntax error"; + case ACCOUNT_ERROR_ITERATOR_END: + return "Iterator has reached the end"; + case ACCOUNT_ERROR_NOTI_FAILED: + return "Notification failed"; + case ACCOUNT_ERROR_PERMISSION_DENIED: + return "Permission denied"; + case ACCOUNT_ERROR_XML_PARSE_FAILED: + return "XML parse failed"; + case ACCOUNT_ERROR_XML_FILE_NOT_FOUND: + return "XML file does not exist"; + case ACCOUNT_ERROR_EVENT_SUBSCRIPTION_FAIL: + return "Subscription failed"; + case ACCOUNT_ERROR_NOT_REGISTERED_PROVIDER: + return "Account provider is not registered"; + case ACCOUNT_ERROR_NOT_ALLOW_MULTIPLE: + return "Multiple accounts are not supported"; + case ACCOUNT_ERROR_DATABASE_BUSY: + return "SQLite busy handler expired"; + default: + return "Unknown Error"; + } +} + +void AccountManager::GetAccountsInfo(const std::string& application_id, + picojson::object& out) { + LoggerD("Enter"); + + picojson::array array_data; + int ret = ACCOUNT_ERROR_NONE; + + if ("" == application_id) { + ret = account_foreach_account_from_db(GetAccountsCallback, &array_data); + } else { + ret = account_query_account_by_package_name(GetAccountsCallback, + application_id.c_str(), + &array_data); + } + + if (ret == ACCOUNT_ERROR_NONE || ret == ACCOUNT_ERROR_RECORD_NOT_FOUND) { + out["status"] = picojson::value("success"); + out["result"] = picojson::value(array_data); + } else { + LoggerE("Failed to get accounts information"); + REPORT_ERROR(out, UnknownException(GetErrorMsg(ret))); + } +} + +bool AccountManager::GetAccountInfo(int account_id, picojson::object& out) { + LoggerD("Enter"); + + account_h account = NULL; + SCOPE_EXIT { + account_destroy(account); + }; + + int ret = account_create(&account); + if (ret != ACCOUNT_ERROR_NONE) { + LoggerE("Failed to create account info"); + REPORT_ERROR(out, UnknownException(GetErrorMsg(ret))); + return false; + } + + ret = account_query_account_by_account_id(account_id, &account); + if (ret != ACCOUNT_ERROR_NONE) { + LoggerE("Failed to get account info"); + REPORT_ERROR(out, UnknownException(GetErrorMsg(ret))); + return false; + } + + picojson::object info; + if (!ConvertAccountToObject(account, info)) { + LoggerE("Failed to convert account_h into object"); + REPORT_ERROR(out, UnknownException("Unknown error occurs")); + return false; + } + + out["status"] = picojson::value("success"); + out["result"] = picojson::value(info); + + return true; +} + +bool AccountManager::GetProviderInfo(const std::string& provider_id, + picojson::object& out) { + LoggerD("Enter"); + + account_type_h provider = NULL; + SCOPE_EXIT { + account_type_destroy(provider); + }; + + int ret = account_type_create(&provider); + if (ret != ACCOUNT_ERROR_NONE) { + LoggerE("Failed to create provider info"); + REPORT_ERROR(out, UnknownException(GetErrorMsg(ret))); + return false; + } + + ret = account_type_query_by_app_id(provider_id.c_str(), &provider); + if (ret != ACCOUNT_ERROR_NONE) { + LoggerE("Failed to get provider info"); + REPORT_ERROR(out, UnknownException(GetErrorMsg(ret))); + return false; + } + + picojson::object info; + if (!ConvertProviderToObject(provider, info)) { + LoggerE("Failed to convert account_type_h into object"); + REPORT_ERROR(out, UnknownException("Unknown error occurs")); + return false; + } + + out["status"] = picojson::value("success"); + out["result"] = picojson::value(info); + + return true; +} + +bool AccountManager::ConvertAccountToObject(account_h account, + picojson::object& out) { + LoggerD("Enter"); + + char* provider_id = NULL; + char* icon_path = NULL; + char* user_name = NULL; + + SCOPE_EXIT { + free(provider_id); + free(icon_path); + free(user_name); + }; + + int account_id = -1; + int ret = account_get_account_id(account, &account_id); + if (ret != ACCOUNT_ERROR_NONE) { + LoggerE("Failed to get account ID"); + REPORT_ERROR(out, UnknownException(GetErrorMsg(ret))); + return false; + } + out["id"] = picojson::value(static_cast(account_id)); + + ret = account_get_package_name(account, &provider_id); + if (ret != ACCOUNT_ERROR_NONE) { + LoggerE("Failed to get provider name"); + REPORT_ERROR(out, UnknownException(GetErrorMsg(ret))); + return false; + } + + picojson::object provider_info; + if (!GetProviderInfo(provider_id, provider_info)) { + LoggerE("Failed to get provider info"); + return false; + } + out["provider"] = provider_info["result"]; + + picojson::object account_init; + ret = account_get_icon_path(account, &icon_path); + if (ret != ACCOUNT_ERROR_NONE) { + LoggerE("Failed to get icon path"); + REPORT_ERROR(out, UnknownException(GetErrorMsg(ret))); + return false; + } + account_init["iconUri"] = picojson::value(icon_path); + + ret = account_get_user_name(account, &user_name); + if (ret != ACCOUNT_ERROR_NONE) { + LoggerE("Failed to get user name"); + REPORT_ERROR(out, UnknownException(GetErrorMsg(ret))); + return false; + } + account_init["userName"] = picojson::value(user_name); + out["accountInitDict"] = picojson::value(account_init); + + return true; +} + +bool AccountManager::ConvertProviderToObject(account_type_h provider, + picojson::object& out) { + LoggerD("Enter"); + + char* provider_id = NULL; + char* display_name = NULL; + char* icon_uri = NULL; + char* small_icon_uri = NULL; + bool is_multiple_account_supported = false; + picojson::array capabilities; + + int ret = account_type_get_app_id(provider, &provider_id); + if (ret != ACCOUNT_ERROR_NONE) { + LoggerE("Failed to get application id"); + REPORT_ERROR(out, UnknownException(GetErrorMsg(ret))); + return false; + } + out["applicationId"] = picojson::value(provider_id); + free(provider_id); + + // TODO: Which label should be returned? + ret = account_type_get_label_by_locale(provider, "default", &display_name); + if (ret == ACCOUNT_ERROR_NONE) { + out["displayName"] = picojson::value(display_name); + free(display_name); + } else if (ret == ACCOUNT_ERROR_RECORD_NOT_FOUND) { + LoggerD("There is no label"); + out["displayName"] = picojson::value(""); + } else { + LoggerE("Failed to get label"); + REPORT_ERROR(out, UnknownException(GetErrorMsg(ret))); + return false; + } + + ret = account_type_get_icon_path(provider, &icon_uri); + if (ret != ACCOUNT_ERROR_NONE) { + LoggerE("Failed to get icon"); + REPORT_ERROR(out, UnknownException(GetErrorMsg(ret))); + return false; + } + out["iconUri"] = picojson::value(icon_uri); + free(icon_uri); + + ret = account_type_get_small_icon_path(provider, &small_icon_uri); + if (ret != ACCOUNT_ERROR_NONE) { + LoggerE("Failed to get small icon"); + REPORT_ERROR(out, UnknownException(GetErrorMsg(ret))); + return false; + } + out["smallIconUri"] = picojson::value(small_icon_uri); + free(small_icon_uri); + + ret = account_type_get_provider_feature_all(provider, ProviderCapabilitiesCb, + &capabilities); + if (ret != ACCOUNT_ERROR_NONE) { + LoggerE("Failed to get capabilities"); + REPORT_ERROR(out, UnknownException(GetErrorMsg(ret))); + return false; + } + out["capabilities"] = picojson::value(capabilities); + + int supported = 0; + ret = account_type_get_multiple_account_support(provider, &supported); + if (ret != ACCOUNT_ERROR_NONE) { + LoggerE("Failed to get small icon"); + REPORT_ERROR(out, UnknownException(GetErrorMsg(ret))); + return false; + } + is_multiple_account_supported = (supported != 0); + out["isMultipleAccountSupported"] = picojson::value( + is_multiple_account_supported); + + return true; +} + +void AccountManager::GetProvidersInfo(const std::string& capability, + picojson::object& out) { + LoggerD("Enter"); + + picojson::array array_data; + int ret = ACCOUNT_ERROR_NONE; + + if ("" == capability) { + ret = account_type_foreach_account_type_from_db(AccountProvidersGetCb, + &array_data); + } else { + ret = account_type_query_by_provider_feature(AccountProvidersGetCb, + capability.c_str(), + &array_data); + } + + if (ret == ACCOUNT_ERROR_NONE || ret == ACCOUNT_ERROR_RECORD_NOT_FOUND) { + out["status"] = picojson::value("success"); + out["result"] = picojson::value(array_data); + } else { + LoggerE("Failed to get providers information"); + REPORT_ERROR(out, UnknownException(GetErrorMsg(ret))); + } +} + +#undef REPORT_ERROR + +} // namespace account +} // namespace extension diff --git a/src/account/account_manager.h b/src/account/account_manager.h new file mode 100644 index 00000000..2e2d2eab --- /dev/null +++ b/src/account/account_manager.h @@ -0,0 +1,56 @@ +// Copyright 2014 Samsung Electronics Co, Ltd. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ACCOUNT_ACCOUNT_MANAGER_H_ +#define ACCOUNT_ACCOUNT_MANAGER_H_ + +#include + +#include "common/extension.h" +#include "common/picojson.h" +#include "common/platform_exception.h" + +namespace extension { +namespace account { + +class AccountManager { + public: + AccountManager(); + virtual ~AccountManager(); + + /* out["status"] = "success" or "error" + * If status is "success", then the result(picojson::value) will be stored in out["result"]. + * If status is "error", then the error(picojson::value) will be stored in out["error"]. + */ + void GetAccountsInfo(const std::string& application_id, picojson::object& out); + + /* out["status"] = "success" or "error" + * If status is "success", then the result(picojson::value) will be stored in out["result"]. + * If status is "error", then the error(picojson::value) will be stored in out["error"]. + */ + bool GetAccountInfo(int account_id, picojson::object& out); + + /* out["status"] = "success" or "error" + * If status is "success", then the result(picojson::value) will be stored in out["result"]. + * If status is "error", then the error(picojson::value) will be stored in out["error"]. + */ + void GetProvidersInfo(const std::string& capability, picojson::object& out); + + /* out["status"] = "success" or "error" + * If status is "success", then the result(picojson::value) will be stored in out["result"]. + * If status is "error", then the error(picojson::value) will be stored in out["error"]. + */ + static bool GetProviderInfo(const std::string& provider_id, picojson::object& out); + + static bool ConvertAccountToObject(account_h account, picojson::object& out); + + static bool ConvertProviderToObject(account_type_h provider, picojson::object& out); + + static std::string GetErrorMsg(int error); +}; + +} // namespace account +} // namespace extension + +#endif // ACCOUNT_ACCOUNT_MANAGER_H_ diff --git a/src/tizen-wrt.gyp b/src/tizen-wrt.gyp index 221e8296..3b45a469 100644 --- a/src/tizen-wrt.gyp +++ b/src/tizen-wrt.gyp @@ -23,6 +23,7 @@ [ 'extension_host_os == "mobile"', { 'dependencies': [ + 'account/account.gyp:*', 'badge/badge.gyp:*', 'bluetooth/bluetooth.gyp:*', 'callhistory/callhistory.gyp:*', -- 2.34.1