Bug 821584 - Part 1: readPBR and Refactor ICCContact. r=hsinyi
authorYoshi Huang <allstars.chh@mozilla.com>
Thu, 27 Dec 2012 19:06:29 +0800
changeset 119243 be757f2c314ee56a0a6cc9f85b535750c0d5a186
parent 119242 03fb2a777aec3418417a83991136b4c0fd803c15
child 119244 ca185542d941878cfc4848f50689c1f7e3009f2d
push id24195
push userMs2ger@gmail.com
push dateSat, 19 Jan 2013 16:10:11 +0000
treeherdermozilla-central@02e12a80aef9 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewershsinyi
bugs821584
milestone21.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 821584 - Part 1: readPBR and Refactor ICCContact. r=hsinyi
dom/system/gonk/ril_consts.js
dom/system/gonk/ril_worker.js
--- a/dom/system/gonk/ril_consts.js
+++ b/dom/system/gonk/ril_consts.js
@@ -528,16 +528,30 @@ this.ICC_USIM_EFANR_TAG   = 0xc4;
 this.ICC_USIM_EFPBC_TAG   = 0xc5;
 this.ICC_USIM_EFGRP_TAG   = 0xc6;
 this.ICC_USIM_EFAAS_TAG   = 0xc7;
 this.ICC_USIM_EFGSD_TAG   = 0xc8;
 this.ICC_USIM_EFUID_TAG   = 0xc9;
 this.ICC_USIM_EFEMAIL_TAG = 0xca;
 this.ICC_USIM_EFCCP1_TAG  = 0xcb;
 
+this.USIM_TAG_NAME = {};
+this.USIM_TAG_NAME[ICC_USIM_EFADN_TAG] = "adn";
+this.USIM_TAG_NAME[ICC_USIM_EFIAP_TAG] ="iap";
+this.USIM_TAG_NAME[ICC_USIM_EFEXT1_TAG] = "ext1";
+this.USIM_TAG_NAME[ICC_USIM_EFSNE_TAG] = "sne";
+this.USIM_TAG_NAME[ICC_USIM_EFANR_TAG] = "anr";
+this.USIM_TAG_NAME[ICC_USIM_EFPBC_TAG] = "pbc";
+this.USIM_TAG_NAME[ICC_USIM_EFGRP_TAG] = "grp";
+this.USIM_TAG_NAME[ICC_USIM_EFAAS_TAG] = "aas";
+this.USIM_TAG_NAME[ICC_USIM_EFGSD_TAG] = "gsd";
+this.USIM_TAG_NAME[ICC_USIM_EFUID_TAG] = "uid";
+this.USIM_TAG_NAME[ICC_USIM_EFEMAIL_TAG] = "email";
+this.USIM_TAG_NAME[ICC_USIM_EFCCP1_TAG] = "ccp1";
+
 /**
  * STK constants.
  */
 //  Tags for Ber Tlv.
 this.BER_UNKNOWN_TAG = 0x00;
 this.BER_PROACTIVE_COMMAND_TAG = 0xd0;
 this.BER_SMS_PP_DOWNLOAD_TAG = 0xd1;
 this.BER_MENU_SELECTION_TAG = 0xd3;
--- a/dom/system/gonk/ril_worker.js
+++ b/dom/system/gonk/ril_worker.js
@@ -1304,43 +1304,42 @@ let RIL = {
       return [pnnEntry.fullName, pnnEntry.shortName];
     }
     return null;
   },
 
   /**
    * Get UICC Phonebook.
    *
-   * @params contactType
-   *         "ADN" or "FDN".
+   * @param contactType
+   *        "ADN" or "FDN".
+   * @param requestId
+   *        Request id from RadioInterfaceLayer.
    */
   getICCContacts: function getICCContacts(options) {
     if (!this.appType) {
       options.rilMessageType = "icccontacts";
       options.errorMsg = GECKO_ERROR_REQUEST_NOT_SUPPORTED;
       this.sendDOMMessage(options);
     }
 
-    let type = options.contactType;
-    switch (type) {
-      case "ADN":
-        switch (this.appType) {
-          case CARD_APPTYPE_SIM:
-            options.fileId = ICC_EF_ADN;
-            ICCRecordHelper.getADN(options);
-            break;
-          case CARD_APPTYPE_USIM:
-            ICCRecordHelper.getPBR(options);
-            break;
-        }
-        break;
-      case "FDN":
-        ICCRecordHelper.getFDN(options);
-        break;
-    }
+    ICCContactHelper.readICCContacts(
+      this.appType,
+      options.contactType,
+      function onsuccess(contacts) {
+        // Reuse 'options' to get 'requestId' and 'contactType'.
+        options.rilMessageType = "icccontacts";
+        options.contacts = contacts;
+        RIL.sendDOMMessage(options);
+      }.bind(this),
+      function onerror(errorMsg) {
+        options.rilMessageType = "icccontacts";
+        options.errorMsg = errorMsg;
+        RIL.sendDOMMessage(options);
+      }.bind(this));
   },
 
   /**
    * Request the phone's radio power to be switched on or off.
    *
    * @param on
    *        Boolean indicating the desired power state.
    */
@@ -4468,40 +4467,26 @@ RIL[REQUEST_SETUP_DATA_CALL] = function 
     return;
   }
   // Pass `options` along. That way we retain the APN and other info about
   // how the data call was set up.
   this[REQUEST_DATA_CALL_LIST](length, options);
 };
 RIL[REQUEST_SIM_IO] = function REQUEST_SIM_IO(length, options) {
   if (!length) {
-    if (options.onerror) {
-      options.errorMsg = RIL_ERROR_TO_GECKO_ERROR[options.rilRequestError];
-      options.onerror(options);
-    }
+    ICCIOHelper.processICCIOError(options);
     return;
   }
 
   // Don't need to read rilRequestError since we can know error status from
   // sw1 and sw2.
   options.sw1 = Buf.readUint32();
   options.sw2 = Buf.readUint32();
   if (options.sw1 != ICC_STATUS_NORMAL_ENDING) {
-    // See GSM11.11, TS 51.011 clause 9.4, and ISO 7816-4 for the error
-    // description.
-    let msg = "ICC I/O Error EF id = " + options.fileId.toString(16) +
-              " command = " + options.command.toString(16) +
-              "(" + options.sw1.toString(16) + "/" + options.sw2.toString(16) + ")"
-    if (DEBUG) {
-      debug(msg);
-    }
-    if (options.onerror) {
-      options.errorMsg = msg;
-      options.onerror(options);
-    }
+    ICCIOHelper.processICCIOError(options);
     return;
   }
   ICCIOHelper.processICCIO(options);
 };
 RIL[REQUEST_SEND_USSD] = function REQUEST_SEND_USSD(length, options) {
   if (DEBUG) {
     debug("REQUEST_SEND_USSD " + JSON.stringify(options));
   }
@@ -8519,16 +8504,33 @@ let ICCIOHelper = {
   /**
    * Process a ICC_COMMAND_READ_BINARY type command for REQUEST_SIM_IO.
    */
   processICCIOReadBinary: function processICCIOReadBinary(options) {
     if (options.callback) {
       options.callback(options);
     }
   },
+
+  /**
+   * Process ICC IO error.
+   */
+  processICCIOError: function processICCIOError(options) {
+    let error = options.onerror || debug;
+
+    // See GSM11.11, TS 51.011 clause 9.4, and ISO 7816-4 for the error
+    // description.
+    let errorMsg = "ICC I/O Error code " +
+                   RIL_ERROR_TO_GECKO_ERROR[options.rilRequestError] +
+                   "EF id = " + options.fileId.toString(16) +
+                   " command = " + options.command.toString(16) +
+                   "(" + options.sw1.toString(16) +
+                   "/" + options.sw2.toString(16) + ")";
+    error(errorMsg);
+  },
 };
 ICCIOHelper[ICC_COMMAND_SEEK] = null;
 ICCIOHelper[ICC_COMMAND_READ_BINARY] = function ICC_COMMAND_READ_BINARY(options) {
   this.processICCIOReadBinary(options);
 };
 ICCIOHelper[ICC_COMMAND_READ_RECORD] = function ICC_COMMAND_READ_RECORD(options) {
   this.processICCIOReadRecord(options);
 };
@@ -8739,99 +8741,76 @@ let ICCRecordHelper = {
     }
 
     // ICC_EF_UST has the same value with ICC_EF_SST.
     ICCIOHelper.loadTransparentEF({fileId: ICC_EF_SST,
                                    callback: callback.bind(this)});
   },
 
   /**
-   *  Get ICC FDN.
-   *
-   *  @param requestId
-   *         Request id from RadioInterfaceLayer.
-   */
-  getFDN: function getFDN(options) {
+   * Read ICC FDN.
+   *
+   * @param onsuccess   Callback to be called when success.
+   * @param onerror     Callback to be called when error.
+   */
+  readFDN: function readFDN(onsuccess, onerror) {
     function callback(options) {
       let contact = GsmPDUHelper.readAlphaIdDiallingNumber(options.recordSize);
       if (contact) {
-        RIL.iccInfo.fdn.push(contact);
+        contacts.push(contact);
+      }
+
+      if (options.p1 < options.totalRecords) {
+        ICCIOHelper.loadNextRecord(options);
+      } else {
+        if (onsuccess) {
+          onsuccess(contacts);
+        }
+      }
+    }
+
+    let contacts = [];
+    ICCIOHelper.loadLinearFixedEF({fileId: ICC_EF_FDN,
+                                   callback: callback.bind(this),
+                                   onerror: onerror});
+  },
+
+  /**
+   * Read ICC ADN.
+   *
+   * @param fileId      EF id of the ADN.
+   * @param onsuccess   Callback to be called when success.
+   * @param onerror     Callback to be called when error.
+   */
+  readADN: function readADN(fileId, onsuccess, onerror) {
+    function callback(options) {
+      let contact = GsmPDUHelper.readAlphaIdDiallingNumber(options.recordSize);
+      if (contact) {
+        contact.recordId = options.p1;
+        contacts.push(contact);
       }
 
       if (options.p1 < options.totalRecords) {
         ICCIOHelper.loadNextRecord(options);
       } else {
         if (DEBUG) {
-          for (let i = 0; i < RIL.iccInfo.fdn.length; i++) {
-            debug("FDN[" + i + "] alphaId = " + RIL.iccInfo.fdn[i].alphaId +
-                                " number  = " + RIL.iccInfo.fdn[i].number);
+          for (let i = 0; i < contacts.length; i++) {
+            debug("ADN[" + i + "] " + JSON.stringify(contacts[i]));
           }
         }
-        // To prevent DataCloneError when sending parcels, we need to delete
-        // those properties which are not 'Structured Clone Data', in this case,
-        // those callback functions.
-        delete options.callback;
-        delete options.onerror;
-        options.rilMessageType = "icccontacts";
-        options.contacts = RIL.iccInfo.fdn;
-        RIL.sendDOMMessage(options);
-      }
-    }
-
-    RIL.iccInfo.fdn = [];
-    options.fileId = ICC_EF_FDN;
-    options.callback = callback.bind(this);
-    ICCIOHelper.loadLinearFixedEF(options);
-  },
-
-  /**
-   *  Get ICC ADN.
-   *
-   *  @param fileId
-   *         EF id of the ADN.
-   *  @param requestId
-   *         Request id from RadioInterfaceLayer.
-   */
-  getADN: function getADN(options) {
-    function callback(options) {
-      let contact = GsmPDUHelper.readAlphaIdDiallingNumber(options.recordSize);
-      if (contact) {
-        RIL.iccInfo.adn.push(contact);
-      }
-
-      if (options.p1 < options.totalRecords) {
-        ICCIOHelper.loadNextRecord(options);
-      } else {
-        if (DEBUG) {
-          for (let i = 0; i < RIL.iccInfo.adn.length; i++) {
-            debug("ADN[" + i + "] " + JSON.stringify(RIL.iccInfo.adn[i]));
-          }
+        if (onsuccess) {
+          onsuccess(contacts);
         }
-        // To prevent DataCloneError when sending parcels, we need to delete
-        // those properties which are not 'Structured Clone Data', in this case,
-        // those callback functions.
-        delete options.callback;
-        delete options.onerror;
-        options.rilMessageType = "icccontacts";
-        options.contacts = RIL.iccInfo.adn;
-        RIL.sendDOMMessage(options);
-      }
-    }
-
-    function error(options) {
-      delete options.callback;
-      delete options.onerror;
-      options.rilMessageType = "icccontacts";
-      RIL.sendDOMMessage(options);
-    }
-
-    RIL.iccInfo.adn = [];
-    options.callback = callback.bind(this);
-    options.onerror = error.bind(this);
-    ICCIOHelper.loadLinearFixedEF(options);
+      }
+    }
+
+    let contacts = [];
+    ICCIOHelper.loadLinearFixedEF({fileId: fileId,
+                                   callback: callback.bind(this),
+                                   onerror: onerror});
   },
 
   /**
    * Get ICC MBDN. (Mailbox Dialling Number)
    *
    * @see TS 131.102, clause 4.2.60
    */
   getMBDN: function getMBDN() {
@@ -8848,47 +8827,60 @@ let ICCRecordHelper = {
       RIL.sendDOMMessage(contact);
     }
 
     ICCIOHelper.loadLinearFixedEF({fileId: ICC_EF_MBDN,
                                    callback: callback.bind(this)});
   },
 
   /**
-   * Get USIM Phonebook.
-   *
-   * @param requestId
-   *         Request id from RadioInterfaceLayer.
-   */
-  getPBR: function getPBR(options) {
+   * Read USIM Phonebook.
+   *
+   * @param onsuccess   Callback to be called when success.
+   * @param onerror     Callback to be called when error.
+   */
+  readPBR: function readPBR(onsuccess, onerror) {
     function callback(options) {
-      let bufLen = Buf.readUint32();
-
-      let tag = GsmPDUHelper.readHexOctet();
-      let length = GsmPDUHelper.readHexOctet();
-      let value = ICCUtilsHelper.decodeSimTlvs(length);
-
-      let adn = ICCUtilsHelper.searchForIccUsimTag(value, ICC_USIM_EFADN_TAG);
-      options.fileId = (adn.value[0] << 8) | adn.value[1];
-      Buf.readStringDelimiter(bufLen);
-
-      this.getADN(options);
-    }
-
-    function error(options) {
-      delete options.callback;
-      delete options.onerror;
-      options.rilMessageType = "icccontacts";
-      RIL.sendDOMMessage(options);
-    }
-
-    options.fileId = ICC_EF_PBR;
-    options.callback = callback.bind(this);
-    options.onerror = error.bind(this);
-    ICCIOHelper.loadLinearFixedEF(options);
+      let strLen = Buf.readUint32();
+      let octetLen = strLen / 2, readLen = 0;
+
+      let pbrTlvs = [];
+      while (readLen < octetLen) {
+        let tag = GsmPDUHelper.readHexOctet();
+        if (tag == 0xff) {
+          readLen++;
+          Buf.seekIncoming((octetLen - readLen) * PDU_HEX_OCTET_SIZE);
+          break;
+        }
+
+        let tlvLen = GsmPDUHelper.readHexOctet();
+        let tlvs = ICCUtilsHelper.decodeSimTlvs(tlvLen);
+        pbrTlvs.push({tag: tag,
+                      length: tlvLen,
+                      value: tlvs});
+
+        readLen += tlvLen + 2; // +2 for tag and tlvLen
+      }
+      Buf.readStringDelimiter(strLen);
+
+      if (pbrTlvs.length == 0) {
+        let error = onerror || debug;
+        error("Cannot access Phonebook.");
+        return;
+      }
+
+      let pbr = ICCUtilsHelper.parsePbrTlvs(pbrTlvs);
+      if (onsuccess) {
+        onsuccess(pbr);
+      }
+    }
+
+    ICCIOHelper.loadLinearFixedEF({fileId : ICC_EF_PBR,
+                                   callback: callback.bind(this),
+                                   onerror: onerror});
   },
 
   /**
    * Read the PLMNsel (Public Land Mobile Network) from the ICC.
    *
    * See ETSI TS 100.977 section 10.3.4 EF_PLMNsel
    */
   getPLMNSelector: function getPLMNSelector() {
@@ -9342,23 +9334,48 @@ let ICCUtilsHelper = {
       };
       simTlv.value = GsmPDUHelper.readHexOctetArray(simTlv.length)
       tlvs.push(simTlv);
       index += simTlv.length + 2 /* The length of 'tag' and 'length' field */;
     }
     return tlvs;
   },
 
-  searchForIccUsimTag: function searchForIccUsimTag(tlvs, tag) {
-    for (let i = 0; i < tlvs.length; i++) {
-      if (tlvs[i].tag == tag) {
-        return tlvs[i];
-      }
-    }
-    return null;
+  /**
+   * Parse those TLVs and convert it to an object.
+   */
+  parsePbrTlvs: function parsePbrTlvs(pbrTlvs) {
+    let pbr = {};
+    for (let i = 0; i < pbrTlvs.length; i++) {
+      let pbrTlv = pbrTlvs[i];
+      for (let j = 0; j < pbrTlv.value.length; j++) {
+        let tlv = pbrTlv.value[j];
+        let tagName = USIM_TAG_NAME[tlv.tag];
+
+        // ANR could have multiple files.
+        if (tlv.tag == ICC_USIM_EFANR_TAG) {
+          if (!pbr.anr) {
+            pbr.anr = [];
+          }
+          pbr.anr.push(tlv);
+        } else {
+          pbr[tagName] = tlv;
+        }
+
+        pbr[tagName].fileType = pbrTlv.tag;
+        pbr[tagName].fileId = (tlv.value[0] << 8) | tlv.value[1];
+
+        // For Type 2, the order of files is in the same order in IAP.
+        if (pbrTlv.tag == ICC_USIM_TYPE2_TAG) {
+          pbr[tagName].indexInIAP = j;
+        }
+      }
+    }
+
+    return pbr;
   },
 
   /**
    * Update the ICC information to RadioInterfaceLayer.
    */
   handleICCInfoChange: function handleICCInfoChange() {
     RIL.iccInfo.rilMessageType = "iccinfochange";
     RIL.sendDOMMessage(RIL.iccInfo);
@@ -9451,16 +9468,77 @@ let ICCUtilsHelper = {
       }
     }
 
     return true;
   },
 };
 
 /**
+ * Helper for ICC Contacts.
+ */
+let ICCContactHelper = {
+  /**
+   * Helper function to read ICC contacts.
+   *
+   * @param appType       CARD_APPTYPE_SIM or CARD_APPTYPE_USIM.
+   * @param contactType   "ADN" or "FDN"
+   * @param onsuccess     Callback to be called when success.
+   * @param onerror       Callback to be called when error.
+   */
+  readICCContacts: function readICCContacts(appType, contactType, onsuccess, onerror) {
+    switch (contactType) {
+      case "ADN":
+        switch (appType) {
+          case CARD_APPTYPE_SIM:
+            this.readSimContacts(onsuccess, onerror);
+            break;
+          case CARD_APPTYPE_USIM:
+            this.readUSimContacts(onsuccess, onerror);
+            break;
+        }
+        break;
+      case "FDN":
+        ICCRecordHelper.readFDN(onsuccess, onerror);
+        break;
+    }
+  },
+
+  /**
+   * Read contacts from USIM.
+   *
+   * @param onsuccess     Callback to be called when success.
+   * @param onerror       Callback to be called when error.
+   */
+  readUSimContacts: function readUSimContacts(onsuccess, onerror) {
+    let gotPbrCb = function gotPbrCb(pbr) {
+      if (pbr.adn) {
+        let fileId = pbr.adn.fileId;
+        ICCRecordHelper.readADN(fileId, onsuccess, onerror);
+      } else {
+        let error = onerror || debug;
+        error("Cannot access ADN.");
+      }
+    }.bind(this);
+
+    ICCRecordHelper.readPBR(gotPbrCb, onerror);
+  },
+
+  /**
+   * Read contacts from SIM.
+   *
+   * @param onsuccess     Callback to be called when success.
+   * @param onerror       Callback to be called when error.
+   */
+  readSimContacts: function readSimContacts(onsuccess, onerror) {
+    ICCRecordHelper.readADN(ICC_EF_ADN, onsuccess, onerror);
+  },
+};
+
+/**
  * Global stuff.
  */
 
 if (!this.debug) {
   // Debugging stub that goes nowhere.
   this.debug = function debug(message) {
     dump("RIL Worker: " + message + "\n");
   };