[Account] Initial implementation.
authorByungWoo Lee <bw1212.lee@samsung.com>
Fri, 6 Feb 2015 01:10:37 +0000 (10:10 +0900)
committerPawel Andruszkiewicz <p.andruszkie@samsung.com>
Thu, 12 Feb 2015 12:32:25 +0000 (21:32 +0900)
[Verification] Code compiles, TCT pass rate: 57/89.

Change-Id: I1ddb7d67b6cc1b619b5b6a12c31cf907dc17fe9c

packaging/webapi-plugins.spec
src/account/account.gyp [new file with mode: 0644]
src/account/account_api.js [new file with mode: 0644]
src/account/account_extension.cc [new file with mode: 0644]
src/account/account_extension.h [new file with mode: 0644]
src/account/account_instance.cc [new file with mode: 0644]
src/account/account_instance.h [new file with mode: 0644]
src/account/account_manager.cc [new file with mode: 0644]
src/account/account_manager.h [new file with mode: 0644]
src/tizen-wrt.gyp

index a2b0f31338810567e12e832c689ba981d1add9d1..97d25be3a59d6f0db241231ffa3ba7028d3ccc1c 100644 (file)
@@ -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 (file)
index 0000000..3a5a302
--- /dev/null
@@ -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 (file)
index 0000000..01061e0
--- /dev/null
@@ -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 (file)
index 0000000..532229b
--- /dev/null
@@ -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 (file)
index 0000000..b075455
--- /dev/null
@@ -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 (file)
index 0000000..e6779ba
--- /dev/null
@@ -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 <functional>
+
+#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<std::string>();
+  const std::string& value = args.get("value").get<std::string>();
+
+  // 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<std::string>();
+
+  // 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<std::string>();
+  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<int>(args.get("callbackId").get<double>());
+
+  const std::string capability = args.contains("capability") ? args.get("capability").get<std::string>() : "";
+
+  LoggerD("capability [%s]", capability.c_str());
+
+  auto get_providers = [this, capability](const std::shared_ptr<picojson::value>& result) {
+    this->manager_->GetProvidersInfo(capability, result->get<picojson::object>());
+  };
+
+  auto get_providers_result = [this, callback_id](const std::shared_ptr<picojson::value>& result) {
+    result->get<picojson::object>()["callbackId"] = picojson::value{static_cast<double>(callback_id)};
+    this->PostMessage(result->serialize().c_str());
+  };
+
+  TaskQueue::GetInstance().Queue<picojson::value>(
+      get_providers,
+      get_providers_result,
+      std::shared_ptr<picojson::value>{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<AccountInstance*>(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 (file)
index 0000000..048716e
--- /dev/null
@@ -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 <account.h>
+
+#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 (file)
index 0000000..b4754bd
--- /dev/null
@@ -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 <functional>
+
+#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<picojson::array*>(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<picojson::array*>(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<picojson::array*>(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<double>(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 (file)
index 0000000..2e2d2ea
--- /dev/null
@@ -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 <account.h>
+
+#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_
index 221e8296d797482dbf4c95a71245229edbaa9b93..3b45a469259f86aeafdb3067a9bd4649fea90448 100644 (file)
@@ -23,6 +23,7 @@
         [
           'extension_host_os == "mobile"', {
             'dependencies': [
+              'account/account.gyp:*',
               'badge/badge.gyp:*',
               'bluetooth/bluetooth.gyp:*',
               'callhistory/callhistory.gyp:*',