Bug 1114937 - Part 2: IDL implementation in Gonk. r=echen
authorBevis Tseng <btseng@mozilla.com>
Tue, 16 Jun 2015 17:35:42 +0800
changeset 286390 0c3aa04443397e9baa8e30128aa302051f100fbd
parent 286389 44935ff56b63d73d92fa0c9e57d71f11182625bc
child 286391 244594f4817cb29cccc971b85f6d4a8701755fdb
push id5067
push userraliiev@mozilla.com
push dateMon, 21 Sep 2015 14:04:52 +0000
treeherdermozilla-beta@14221ffe5b2f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersechen
bugs1114937
milestone42.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1114937 - Part 2: IDL implementation in Gonk. r=echen
dom/icc/IccCallback.cpp
dom/icc/IccContact.cpp
dom/icc/IccContact.h
dom/icc/gonk/IccService.js
dom/icc/moz.build
--- a/dom/icc/IccCallback.cpp
+++ b/dom/icc/IccCallback.cpp
@@ -1,27 +1,120 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "IccCallback.h"
 
+#include "mozilla/dom/ContactsBinding.h"
 #include "mozilla/dom/IccCardLockError.h"
 #include "mozilla/dom/MozIccBinding.h"
 #include "mozilla/dom/Promise.h"
 #include "mozilla/dom/ToJSValue.h"
+#include "nsIIccContact.h"
 #include "nsJSUtils.h"
 #include "nsServiceManagerUtils.h"
 
 namespace mozilla {
 namespace dom {
 namespace icc {
 
+namespace {
+
+static nsresult
+IccContactToMozContact(JSContext* aCx, GlobalObject& aGlobal,
+                       nsIIccContact* aIccContact,
+                       mozContact** aMozContact)
+{
+  *aMozContact = nullptr;
+
+  ContactProperties properties;
+
+  // Names
+  char16_t** rawStringArray = nullptr;
+  uint32_t count = 0;
+  nsresult rv = aIccContact->GetNames(&count, &rawStringArray);
+  NS_ENSURE_SUCCESS(rv, rv);
+  if (count > 0) {
+    Sequence<nsString>& nameSeq = properties.mName.Construct().SetValue();
+    for (uint32_t i = 0; i < count; i++) {
+      nameSeq.AppendElement(nsDependentString(rawStringArray[i]), fallible);
+    }
+    NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(count, rawStringArray);
+  }
+
+  // Numbers
+  rawStringArray = nullptr;
+  count = 0;
+  rv = aIccContact->GetNumbers(&count, &rawStringArray);
+  NS_ENSURE_SUCCESS(rv, rv);
+  if (count > 0) {
+    Sequence<ContactTelField>& numberSeq = properties.mTel.Construct().SetValue();
+    for (uint32_t i = 0; i < count; i++) {
+      ContactTelField number;
+      number.mValue.Construct() = nsDependentString(rawStringArray[i]);
+      numberSeq.AppendElement(number, fallible);
+    }
+    NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(count, rawStringArray);
+  }
+
+  // Emails
+  rawStringArray = nullptr;
+  count = 0;
+  rv = aIccContact->GetEmails(&count, &rawStringArray);
+  NS_ENSURE_SUCCESS(rv, rv);
+  if (count > 0) {
+    Sequence<ContactField>& emailSeq = properties.mEmail.Construct().SetValue();
+    for (uint32_t i = 0; i < count; i++) {
+      ContactField email;
+      email.mValue.Construct() = nsDependentString(rawStringArray[i]);
+      emailSeq.AppendElement(email, fallible);
+    }
+    NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(count, rawStringArray);
+  }
+
+  ErrorResult er;
+  nsRefPtr<mozContact> contact
+    = mozContact::Constructor(aGlobal, aCx, properties, er);
+  NS_ENSURE_FALSE(er.Failed(), er.StealNSResult());
+
+  nsAutoString contactId;
+  rv = aIccContact->GetId(contactId);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  contact->SetId(contactId, er);
+  NS_ENSURE_FALSE(er.Failed(), er.StealNSResult());
+
+  contact.forget(aMozContact);
+
+  return NS_OK;
+}
+
+static NS_IMETHODIMP
+IccContactListToMozContactList(JSContext* aCx, GlobalObject& aGlobal,
+                               nsIIccContact** aContacts, uint32_t aCount,
+                               nsTArray<nsRefPtr<mozContact>>& aContactList)
+{
+  aContactList.SetCapacity(aCount);
+  for (uint32_t i = 0; i < aCount ; i++) {
+    nsRefPtr<mozContact> contact;
+    nsresult rv =
+      IccContactToMozContact(aCx, aGlobal, aContacts[i], getter_AddRefs(contact));
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    aContactList.AppendElement(contact);
+  }
+
+  return NS_OK;
+}
+
+} // anonymous namespace
+
 NS_IMPL_ISUPPORTS(IccCallback, nsIIccCallback)
 
 IccCallback::IccCallback(nsPIDOMWindow* aWindow, DOMRequest* aRequest,
                          bool aIsCardLockEnabled)
   : mWindow(aWindow)
   , mRequest(aRequest)
   , mIsCardLockEnabled(aIsCardLockEnabled)
 {
@@ -127,11 +220,69 @@ IccCallback::NotifyCardLockError(const n
 {
   nsRefPtr<IccCardLockError> error =
     new IccCardLockError(mWindow, aErrorMsg, aRetryCount);
   mRequest->FireDetailedError(error);
 
   return NS_OK;
 }
 
+NS_IMETHODIMP
+IccCallback::NotifyRetrievedIccContacts(nsIIccContact** aContacts,
+                                        uint32_t aCount)
+{
+  MOZ_ASSERT(aContacts);
+
+  AutoJSAPI jsapi;
+  if (NS_WARN_IF(!jsapi.Init(mWindow))) {
+    return NS_ERROR_FAILURE;
+  }
+
+  JSContext* cx = jsapi.cx();
+  nsCOMPtr<nsIGlobalObject> go = do_QueryInterface(mWindow);
+  GlobalObject global(cx, go->GetGlobalJSObject());
+
+  nsTArray<nsRefPtr<mozContact>> contactList;
+
+  nsresult rv =
+    IccContactListToMozContactList(cx, global, aContacts, aCount, contactList);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  JS::Rooted<JS::Value> jsResult(cx);
+
+  if (!ToJSValue(cx, contactList, &jsResult)) {
+    return NS_ERROR_FAILURE;
+  }
+
+  return NotifySuccess(jsResult);
+}
+
+NS_IMETHODIMP
+IccCallback::NotifyUpdatedIccContact(nsIIccContact* aContact)
+{
+  MOZ_ASSERT(aContact);
+
+  AutoJSAPI jsapi;
+  if (NS_WARN_IF(!jsapi.Init(mWindow))) {
+    return NS_ERROR_FAILURE;
+  }
+
+  JSContext* cx = jsapi.cx();
+  nsCOMPtr<nsIGlobalObject> go = do_QueryInterface(mWindow);
+  GlobalObject global(cx, go->GetGlobalJSObject());
+
+  nsRefPtr<mozContact> mozContact;
+  nsresult rv =
+    IccContactToMozContact(cx, global, aContact, getter_AddRefs(mozContact));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  JS::Rooted<JS::Value> jsResult(cx);
+
+  if (!ToJSValue(cx, mozContact, &jsResult)) {
+    return NS_ERROR_FAILURE;
+  }
+
+  return NotifySuccess(jsResult);
+}
+
 } // namespace icc
 } // namespace dom
 } // namespace mozilla
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/dom/icc/IccContact.cpp
@@ -0,0 +1,127 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "IccContact.h"
+#include "mozilla/dom/ContactsBinding.h"
+#include "nsReadableUtils.h"
+
+using namespace mozilla::dom::icc;
+
+using mozilla::dom::mozContact;
+
+NS_IMPL_ISUPPORTS(IccContact, nsIIccContact)
+
+/* static */ nsresult
+IccContact::Create(mozContact& aMozContact, nsIIccContact** aIccContact)
+{
+  *aIccContact = nullptr;
+  ErrorResult er;
+
+  // Id
+  nsAutoString id;
+  aMozContact.GetId(id, er);
+  NS_ENSURE_SUCCESS(er.StealNSResult(), NS_ERROR_FAILURE);
+
+  // Names
+  Nullable<nsTArray<nsString>> names;
+  aMozContact.GetName(names, er);
+  NS_ENSURE_SUCCESS(er.StealNSResult(), NS_ERROR_FAILURE);
+  if (names.IsNull()) {
+    // Set as Empty nsTarray<nsString> for IccContact constructor.
+    names.SetValue();
+  }
+
+  // Numbers
+  Nullable<nsTArray<ContactTelField>> nullableNumberList;
+  aMozContact.GetTel(nullableNumberList, er);
+  NS_ENSURE_SUCCESS(er.StealNSResult(), NS_ERROR_FAILURE);
+  nsTArray<nsString> numbers;
+  if (!nullableNumberList.IsNull()) {
+    const nsTArray<ContactTelField>& numberList = nullableNumberList.Value();
+    for (uint32_t i = 0; i < numberList.Length(); i++) {
+      if (numberList[i].mValue.WasPassed()) {
+        numbers.AppendElement(numberList[i].mValue.Value());
+      }
+    }
+  }
+
+  // Emails
+  Nullable<nsTArray<ContactField>> nullableEmailList;
+  aMozContact.GetEmail(nullableEmailList, er);
+  NS_ENSURE_SUCCESS(er.StealNSResult(), NS_ERROR_FAILURE);
+  nsTArray<nsString> emails;
+  if (!nullableEmailList.IsNull()) {
+    const nsTArray<ContactField>& emailList = nullableEmailList.Value();
+    for (uint32_t i = 0; i < emailList.Length(); i++) {
+      if (emailList[i].mValue.WasPassed()) {
+        emails.AppendElement(emailList[i].mValue.Value());
+      }
+    }
+  }
+
+  nsCOMPtr<nsIIccContact> iccContact = new IccContact(id,
+                                                      names.Value(),
+                                                      numbers,
+                                                      emails);
+  iccContact.forget(aIccContact);
+
+  return NS_OK;
+}
+
+IccContact::IccContact(const nsAString& aId,
+                       const nsTArray<nsString>& aNames,
+                       const nsTArray<nsString>& aNumbers,
+                       const nsTArray<nsString>& aEmails)
+  : mId(aId),
+    mNames(aNames),
+    mNumbers(aNumbers),
+    mEmails(aEmails)
+{
+}
+
+// nsIIccInfo implementation.
+
+NS_IMETHODIMP IccContact::GetId(nsAString & aId)
+{
+  aId = mId;
+  return NS_OK;
+}
+
+#define ICCCONTACT_IMPL_GET_CONTACT_FIELD(_field)                               \
+NS_IMETHODIMP IccContact::Get##_field(uint32_t* aCount, char16_t*** a##_field)  \
+{                                                                               \
+  NS_ENSURE_ARG_POINTER(aCount);                                                \
+  NS_ENSURE_ARG_POINTER(a##_field);                                             \
+                                                                                \
+  *aCount = 0;                                                                  \
+  *a##_field = nullptr;                                                         \
+                                                                                \
+  uint32_t count = m##_field.Length();                                          \
+  if (count == 0) {                                                             \
+    return NS_OK;                                                               \
+  }                                                                             \
+  char16_t** temp =                                                             \
+    static_cast<char16_t**>(moz_xmalloc(sizeof(char16_t*) * (count)));          \
+  if (temp == nullptr) {                                                        \
+    return NS_ERROR_OUT_OF_MEMORY;                                              \
+  }                                                                             \
+  for (uint32_t i = 0; i < count; i++) {                                        \
+    (temp)[i] = ToNewUnicode(m##_field[i]);                                     \
+    if (!(temp)[i]) {                                                           \
+      NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(i, temp);                           \
+      return NS_ERROR_OUT_OF_MEMORY;                                            \
+    }                                                                           \
+  }                                                                             \
+                                                                                \
+  *aCount = count;                                                              \
+  *a##_field = temp;                                                            \
+                                                                                \
+  return NS_OK;                                                                 \
+}
+
+ICCCONTACT_IMPL_GET_CONTACT_FIELD(Names)
+ICCCONTACT_IMPL_GET_CONTACT_FIELD(Numbers)
+ICCCONTACT_IMPL_GET_CONTACT_FIELD(Emails)
+
+#undef ICCCONTACT_GET_CONTACT_FIELD
new file mode 100644
--- /dev/null
+++ b/dom/icc/IccContact.h
@@ -0,0 +1,43 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_dom_icc_IccContact_h
+#define mozilla_dom_icc_IccContact_h
+
+#include "nsIIccContact.h"
+
+namespace mozilla {
+namespace dom {
+class mozContact;
+namespace icc {
+
+class IccContact : public nsIIccContact
+{
+public:
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIICCCONTACT
+
+  static nsresult
+  Create(mozContact& aMozContact,
+         nsIIccContact** aIccContact);
+
+private:
+  IccContact(const nsAString& aId,
+             const nsTArray<nsString>& aNames,
+             const nsTArray<nsString>& aNumbers,
+             const nsTArray<nsString>& aEmails);
+  virtual ~IccContact() {}
+
+  nsString mId;
+  nsTArray<nsString> mNames;
+  nsTArray<nsString> mNumbers;
+  nsTArray<nsString> mEmails;
+};
+
+} // namespace icc
+} // namespace dom
+} // namespace mozilla
+
+#endif // mozilla_dom_icc_IccContact_h
+
--- a/dom/icc/gonk/IccService.js
+++ b/dom/icc/gonk/IccService.js
@@ -75,16 +75,96 @@ CdmaIccInfo.prototype = {
                                          Ci.nsIIccInfo]),
 
   // nsICdmaIccInfo
 
   mdn: null,
   prlVersion: 0
 };
 
+function IccContact(aContact) {
+  this.id = aContact.contactId || null;
+  this._names = [];
+  this._numbers = [];
+  this._emails = [];
+
+  if (aContact.alphaId) {
+    this._names.push(aContact.alphaId);
+  }
+
+  if (aContact.number) {
+    this._numbers.push(aContact.number);
+  }
+
+  let anrLen = aContact.anr ? aContact.anr.length : 0;
+  for (let i = 0; i < anrLen; i++) {
+    this._numbers.push(anr[i]);
+  }
+
+  if (aContact.email) {
+    this._emails.push(aContact.email);
+  }
+}
+IccContact.prototype = {
+  QueryInterface: XPCOMUtils.generateQI([Ci.nsIIccContact]),
+
+  _names: null,
+  _numbers: null,
+  _emails: null,
+
+  // nsIIccContact
+
+  id: null,
+
+  getNames: function(aCount) {
+    if (!this._names) {
+      if (aCount) {
+        aCount.value = 0;
+      }
+      return null;
+    }
+
+    if (aCount) {
+      aCount.value = this._names.length;
+    }
+
+    return this._names.slice();
+  },
+
+  getNumbers: function(aCount) {
+    if (!this._numbers) {
+      if (aCount) {
+        aCount.value = 0;
+      }
+      return null;
+    }
+
+    if (aCount) {
+      aCount.value = this._numbers.length;
+    }
+
+    return this._numbers.slice();
+  },
+
+  getEmails: function(aCount) {
+    if (!this._emails) {
+      if (aCount) {
+        aCount.value = 0;
+      }
+      return null;
+    }
+
+    if (aCount) {
+      aCount.value = this._emails.length;
+    }
+
+    return this._emails.slice();
+  },
+};
+
 function IccService() {
   this._iccs = [];
 
   let numClients = gRadioInterfaceLayer.numRadioInterfaces;
   for (let i = 0; i < numClients; i++) {
     this._iccs.push(new Icc(i));
   }
 
@@ -595,12 +675,72 @@ Icc.prototype = {
         }
       });
   },
 
   sendStkEventDownload: function(aEvent) {
     this._radioInterface
       .sendWorkerMessage("sendStkEventDownload",
                          { event: gStkCmdFactory.createEventMessage(aEvent) });
-  }
+  },
+
+  readContacts: function(aContactType, aCallback) {
+    this._radioInterface
+      .sendWorkerMessage("readICCContacts",
+                         { contactType: aContactType },
+                         (aResponse) => {
+      if (aResponse.errorMsg) {
+        aCallback.notifyError(aResponse.errorMsg);
+        return;
+      }
+
+      let iccContacts = [];
+
+      aResponse.contacts.forEach(c => iccContacts.push(new IccContact(c)));
+
+      aCallback.notifyRetrievedIccContacts(iccContacts, iccContacts.length);
+    });
+  },
+
+  updateContact: function(aContactType, aContact, aPin2, aCallback) {
+    let iccContact = { contactId: aContact.id };
+    let count = { value: 0 };
+    let names = aContact.getNames(count);
+    if (count.value > 0) {
+      iccContact.alphaId = names[0];
+    }
+
+    let numbers = aContact.getNumbers(count);
+    if (count.value > 0) {
+      iccContact.number = numbers[0];
+
+      let anrArray = numbers.slice(1);
+      let length = anrArray.length;
+      if (length > 0) {
+        iccContact.anr = [];
+        for (let i = 0; i < length; i++) {
+          iccContact.anr.push(anrArray[i].value);
+        }
+      }
+    }
+
+    let emails = aContact.getEmails(count);
+    if (count.value > 0) {
+      iccContact.email = emails[0];
+    }
+
+    this._radioInterface
+      .sendWorkerMessage("updateICCContact",
+                         { contactType: aContactType,
+                           contact: iccContact,
+                           pin2: aPin2 },
+                         (aResponse) => {
+      if (aResponse.errorMsg) {
+        aCallback.notifyError(aResponse.errorMsg);
+        return;
+      }
+
+      aCallback.notifyUpdatedIccContact(new IccContact(aResponse.contact));
+    });
+  },
 };
 
 this.NSGetFactory = XPCOMUtils.generateNSGetFactory([IccService]);
--- a/dom/icc/moz.build
+++ b/dom/icc/moz.build
@@ -18,16 +18,17 @@ EXPORTS.mozilla.dom.icc += [
     'ipc/IccParent.h',
 ]
 
 UNIFIED_SOURCES += [
     'Assertions.cpp',
     'Icc.cpp',
     'IccCallback.cpp',
     'IccCardLockError.cpp',
+    'IccContact.cpp',
     "IccInfo.cpp",
     'IccListener.cpp',
     'IccManager.cpp',
     'ipc/IccChild.cpp',
     'ipc/IccIPCService.cpp',
     'ipc/IccParent.cpp',
 ]