Bug 790547 - Part 3: Add send Location Status Event in RIL. r=philikon
authorYoshi Huang <allstars.chh@mozilla.com>
Tue, 11 Sep 2012 10:34:36 +0800
changeset 108706 c249961afd99b2a287794402309046ad767ffc08
parent 108705 c2e9422b1be8551645183faa9d5d3b30fbbd6860
child 108707 48d10ef28d529be510ad6771a5e4d8d6a50493d7
push id82
push usershu@rfrn.org
push dateFri, 05 Oct 2012 13:20:22 +0000
reviewersphilikon
bugs790547
milestone18.0a1
Bug 790547 - Part 3: Add send Location Status Event in RIL. r=philikon
dom/system/gonk/RILContentHelper.js
dom/system/gonk/RadioInterfaceLayer.js
dom/system/gonk/ril_consts.js
dom/system/gonk/ril_worker.js
--- a/dom/system/gonk/RILContentHelper.js
+++ b/dom/system/gonk/RILContentHelper.js
@@ -448,16 +448,25 @@ RILContentHelper.prototype = {
     if (window == null) {
       throw Components.Exception("Can't get window object",
                                   Cr.NS_ERROR_UNEXPECTED);
     }
     cpmm.sendAsyncMessage("RIL:SendStkMenuSelection", {itemIdentifier: itemIdentifier,
                                                        helpRequested: helpRequested});
   },
 
+  sendStkEventDownload: function sendStkEventDownload(window,
+                                                      event) {
+    if (window == null) {
+      throw Components.Exception("Can't get window object",
+                                  Cr.NS_ERROR_UNEXPECTED);
+    }
+    cpmm.sendAsyncMessage("RIL:SendStkEventDownload", {event: event});
+  },
+
   _telephonyCallbacks: null,
   _voicemailCallbacks: null,
   _enumerateTelephonyCallbacks: null,
 
   voicemailStatus: null,
   voicemailNumber: null,
   voicemailDisplayName: null,
 
--- a/dom/system/gonk/RadioInterfaceLayer.js
+++ b/dom/system/gonk/RadioInterfaceLayer.js
@@ -68,16 +68,17 @@ const RIL_IPC_MOBILECONNECTION_MSG_NAMES
   "RIL:SelectNetworkAuto",
   "RIL:GetCardLock",
   "RIL:UnlockCardLock",
   "RIL:SetCardLock",
   "RIL:SendUSSD",
   "RIL:CancelUSSD",
   "RIL:SendStkResponse",
   "RIL:SendStkMenuSelection",
+  "RIL:SendStkEventDownload",
 ];
 
 XPCOMUtils.defineLazyServiceGetter(this, "gSmsService",
                                    "@mozilla.org/sms/smsservice;1",
                                    "nsISmsService");
 
 XPCOMUtils.defineLazyServiceGetter(this, "gSmsRequestManager",
                                    "@mozilla.org/sms/smsrequestmanager;1",
@@ -379,16 +380,19 @@ RadioInterfaceLayer.prototype = {
         this.cancelUSSD(msg.json);
         break;
       case "RIL:SendStkResponse":
         this.sendStkResponse(msg.json);
         break;
       case "RIL:SendStkMenuSelection":
         this.sendStkMenuSelection(msg.json);
         break;
+      case "RIL:SendStkEventDownload":
+        this.sendStkEventDownload(msg.json);
+        break;
     }
   },
 
   onerror: function onerror(event) {
     debug("Got an error: " + event.filename + ":" +
           event.lineno + ": " + event.message + "\n");
     event.preventDefault();
   },
@@ -1525,16 +1529,21 @@ RadioInterfaceLayer.prototype = {
     this.worker.postMessage(message);
   },
 
   sendStkMenuSelection: function sendStkMenuSelection(message) {
     message.rilMessageType = "sendStkMenuSelection";
     this.worker.postMessage(message);
   },
 
+  sendStkEventDownload: function sendStkEventDownload(message) {
+    message.rilMessageType = "sendStkEventDownload";
+    this.worker.postMessage(message);
+  },
+
   get microphoneMuted() {
     return gAudioManager.microphoneMuted;
   },
   set microphoneMuted(value) {
     if (value == this.microphoneMuted) {
       return;
     }
     gAudioManager.microphoneMuted = value;
--- a/dom/system/gonk/ril_consts.js
+++ b/dom/system/gonk/ril_consts.js
@@ -535,18 +535,20 @@ const COMPREHENSIONTLV_TAG_RESULT = 0x03
 const COMPREHENSIONTLV_TAG_DURATION = 0x04;
 const COMPREHENSIONTLV_TAG_ALPHA_ID = 0x05;
 const COMPREHENSIONTLV_TAG_ADDRESS = 0x06;
 const COMPREHENSIONTLV_TAG_SMS_TPDU = 0x0b;
 const COMPREHENSIONTLV_TAG_TEXT_STRING = 0x0d;
 const COMPREHENSIONTLV_TAG_ITEM = 0x0f;
 const COMPREHENSIONTLV_TAG_ITEM_ID = 0x10;
 const COMPREHENSIONTLV_TAG_RESPONSE_LENGTH = 0x11;
+const COMPREHENSIONTLV_TAG_LOCATION_INFO = 0x13;
 const COMPREHENSIONTLV_TAG_HELP_REQUEST = 0x15;
 const COMPREHENSIONTLV_TAG_DEFAULT_TEXT = 0x17;
+const COMPREHENSIONTLV_TAG_LOCATION_STATUS = 0x1b;
 const COMPREHENSIONTLV_TAG_EVENT_LIST = 0x19;
 const COMPREHENSIONTLV_TAG_ICON_ID = 0x1e;
 const COMPREHENSIONTLV_TAG_ICON_ID_LIST = 0x1f;
 const COMPREHENSIONTLV_TAG_IMMEDIATE_RESPONSE = 0x2b;
 const COMPREHENSIONTLV_TAG_URL = 0x31;
 
 // Device identifiers, see TS 11.14, clause 12.7
 const STK_DEVICE_ID_KEYPAD = 0x01;
@@ -720,16 +722,21 @@ const STK_EVENT_TYPE_BROWSER_TERMINATION
 const STK_EVENT_TYPE_DATA_AVAILABLE = 0x09;
 const STK_EVENT_TYPE_CHANNEL_STATUS = 0x0a;
 const STK_EVENT_TYPE_SINGLE_ACCESS_TECHNOLOGY_CHANGED = 0x0b;
 const STK_EVENT_TYPE_DISPLAY_PARAMETER_CHANGED = 0x0c;
 const STK_EVENT_TYPE_LOCAL_CONNECTION = 0x0d;
 const STK_EVENT_TYPE_NETWORK_SEARCH_MODE_CHANGED = 0x0e;
 const STK_EVENT_TYPE_BROWSING_STATUS = 0x0f;
 
+// STK Service state of Location Status.
+const STK_SERVICE_STATE_NORMAL      = 0x00;
+const STK_SERVICE_STATE_LIMITED     = 0x01;
+const STK_SERVICE_STATE_UNAVAILABLE = 0x02;
+
 /**
  * (U)SIM Services.
  *
  * @see 3GPP TS 51.011 10.3.7 (SIM) and 3GPP TS 31.102 4.2.8 (USIM).
  */
 const GECKO_ICC_SERVICES = {
   sim: {
     ADN: 2,
--- a/dom/system/gonk/ril_worker.js
+++ b/dom/system/gonk/ril_worker.js
@@ -46,16 +46,26 @@ let DEBUG = DEBUG_WORKER;
 const INT32_MAX   = 2147483647;
 const UINT8_SIZE  = 1;
 const UINT16_SIZE = 2;
 const UINT32_SIZE = 4;
 const PARCEL_SIZE_SIZE = UINT32_SIZE;
 
 const PDU_HEX_OCTET_SIZE = 4;
 
+const TLV_COMMAND_DETAILS_SIZE = 5;
+const TLV_DEVICE_ID_SIZE = 4;
+const TLV_RESULT_SIZE = 3;
+const TLV_ITEM_ID_SIZE = 3;
+const TLV_HELP_REQUESTED_SIZE = 2;
+const TLV_EVENT_LIST_SIZE = 3;
+const TLV_LOCATION_STATUS_SIZE = 3;
+const TLV_LOCATION_INFO_GSM_SIZE = 9;
+const TLV_LOCATION_INFO_UMTS_SIZE = 11;
+
 const DEFAULT_EMERGENCY_NUMBERS = ["112", "911"];
 
 let RILQUIRKS_CALLSTATE_EXTRA_UINT32 = libcutils.property_get("ro.moz.ril.callstate_extra_int");
 // This may change at runtime since in RIL v6 and later, we get the version
 // number via the UNSOLICITED_RIL_CONNECTED parcel.
 let RILQUIRKS_V5_LEGACY = libcutils.property_get("ro.moz.ril.v5_legacy");
 let RILQUIRKS_REQUEST_USE_DIAL_EMERGENCY_CALL = libcutils.property_get("ro.moz.ril.dial_emergency_call");
 let RILQUIRKS_MODEM_DEFAULTS_TO_EMERGENCY_MODE = libcutils.property_get("ro.moz.ril.emergency_by_default");
@@ -2252,20 +2262,20 @@ let RIL = {
           textLen = bits * 7 / 8 + (bits % 8 ? 1 : 0);
         } else {
           textLen = response.input.length;
         }
       }
     }
 
     // 1 octets = 2 chars.
-    let size = (5 + /* Size of Command Details TLV */
-                4 + /* Size of Device Identifier TLV */
-                3 + /* Size of Result */
-                (response.itemIdentifier ? 3 : 0) +
+    let size = (TLV_COMMAND_DETAILS_SIZE +
+                TLV_DEVICE_ID_SIZE +
+                TLV_RESULT_SIZE +
+                (response.itemIdentifier ? TLV_ITEM_ID_SIZE : 0) +
                 (textLen ? textLen + 3 : 0)) * 2;
     Buf.writeUint32(size);
 
     // Command Details
     GsmPDUHelper.writeHexOctet(COMPREHENSIONTLV_TAG_COMMAND_DETAILS |
                                COMPREHENSIONTLV_FLAG_CR);
     GsmPDUHelper.writeHexOctet(3);
     if (response.command) {
@@ -2361,28 +2371,64 @@ let RIL = {
     command.deviceId = {
       sourceId :STK_DEVICE_ID_KEYPAD,
       destinationId: STK_DEVICE_ID_SIM
     };
     this.sendICCEnvelopeCommand(command);
   },
 
   /**
+   * Send STK Envelope(Event Download) command.
+   * @param event
+   */
+  sendStkEventDownload: function sendStkEventDownload(command) {
+    command.tag = BER_EVENT_DOWNLOAD_TAG;
+    command.eventList = command.event.eventType;
+    switch (command.eventList) {
+      case STK_EVENT_TYPE_LOCATION_STATUS:
+        command.deviceId = {
+          sourceId :STK_DEVICE_ID_ME,
+          destinationId: STK_DEVICE_ID_SIM
+        };
+        command.locationStatus = command.event.locationStatus;
+        // Location info should only be provided when locationStatus is normal.
+        if (command.locationStatus == STK_SERVICE_STATE_NORMAL) {
+          command.locationInfo = command.event.locationInfo;
+        }
+        break;
+    }
+    this.sendICCEnvelopeCommand(command);
+  },
+
+  /**
    * Send REQUEST_STK_SEND_ENVELOPE_COMMAND to ICC.
    *
    * @param tag
    * @patam deviceId
    * @param [optioanl] itemIdentifier
    * @param [optional] helpRequested
+   * @param [optional] eventList
+   * @param [optional] locationStatus
+   * @param [optional] locationInfo
    */
   sendICCEnvelopeCommand: function sendICCEnvelopeCommand(options) {
+    if (DEBUG) {
+      debug("Stk Envelope " + JSON.stringify(options));
+    }
     let token = Buf.newParcel(REQUEST_STK_SEND_ENVELOPE_COMMAND);
-    let berLen = 4 + /* Size of Device Identifier TLV */
-                 (options.itemIdentifier ? 3 : 0) +
-                 (options.helpRequested ? 2 : 0);
+    let berLen = TLV_DEVICE_ID_SIZE + /* Size of Device Identifier TLV */
+                 (options.itemIdentifier ? TLV_ITEM_ID_SIZE : 0) +
+                 (options.helpRequested ? TLV_HELP_REQUESTED_SIZE : 0) +
+                 (options.eventList ? TLV_EVENT_LIST_SIZE : 0) +
+                 (options.locationStatus ? TLV_LOCATION_STATUS_SIZE : 0) +
+                 (options.locationInfo ?
+                    (options.locationInfo.gsmCellId > 0xffff ?
+                      TLV_LOCATION_INFO_UMTS_SIZE :
+                      TLV_LOCATION_INFO_GSM_SIZE) :
+                    0);
     let size = (2 + berLen) * 2;
 
     Buf.writeUint32(size);
 
     // Write a BER-TLV
     GsmPDUHelper.writeHexOctet(options.tag);
     GsmPDUHelper.writeHexOctet(berLen);
 
@@ -2404,16 +2450,38 @@ let RIL = {
     // Help Request
     if (options.helpRequested) {
       GsmPDUHelper.writeHexOctet(COMPREHENSIONTLV_TAG_HELP_REQUEST |
                                  COMPREHENSIONTLV_FLAG_CR);
       GsmPDUHelper.writeHexOctet(0);
       // Help Request doesn't have value
     }
 
+    // Event List
+    if (options.eventList) {
+      GsmPDUHelper.writeHexOctet(COMPREHENSIONTLV_TAG_EVENT_LIST |
+                                 COMPREHENSIONTLV_FLAG_CR);
+      GsmPDUHelper.writeHexOctet(1);
+      GsmPDUHelper.writeHexOctet(options.eventList);
+    }
+
+    // Location Status
+    if (options.locationStatus) {
+      let len = options.locationStatus.length;
+      GsmPDUHelper.writeHexOctet(COMPREHENSIONTLV_TAG_LOCATION_STATUS |
+                                 COMPREHENSIONTLV_FLAG_CR);
+      GsmPDUHelper.writeHexOctet(1);
+      GsmPDUHelper.writeHexOctet(options.locationStatus);
+    }
+
+    // Location Info
+    if (options.locationInfo) {
+      ComprehensionTlvHelper.writeLocationInfoTlv(options.locationInfo);
+    }
+
     Buf.writeUint32(0);
     Buf.sendParcel();
   },
 
   /**
    * Check a given number against the list of emergency numbers provided by the RIL.
    *
    * @param number
@@ -6664,17 +6732,78 @@ let ComprehensionTlvHelper = {
     let index = 0;
     while (index < length) {
       let tlv = this.decode();
       chunks.push(tlv);
       index += tlv.length;
       index += tlv.hlen;
     }
     return chunks;
-  }
+  },
+
+  /**
+   * Write Location Info Comprehension TLV.
+   *
+   * @param loc location Information.
+   */
+  writeLocationInfoTlv: function writeLocationInfoTlv(loc) {
+    GsmPDUHelper.writeHexOctet(COMPREHENSIONTLV_TAG_LOCATION_INFO |
+                               COMPREHENSIONTLV_FLAG_CR);
+    GsmPDUHelper.writeHexOctet(loc.gsmCellId > 0xffff ? 9 : 7);
+    // From TS 11.14, clause 12.19
+    // "The mobile country code (MCC), the mobile network code (MNC),
+    // the location area code (LAC) and the cell ID are
+    // coded as in TS 04.08."
+    // And from TS 04.08 and TS 24.008,
+    // the format is as follows:
+    //
+    // MCC = MCC_digit_1 + MCC_digit_2 + MCC_digit_3
+    //
+    //   8  7  6  5    4  3  2  1
+    // +-------------+-------------+
+    // | MCC digit 2 | MCC digit 1 | octet 2
+    // | MNC digit 3 | MCC digit 3 | octet 3
+    // | MNC digit 2 | MNC digit 1 | octet 4
+    // +-------------+-------------+
+    //
+    // Also in TS 24.008
+    // "However a network operator may decide to
+    // use only two digits in the MNC in the LAI over the
+    // radio interface. In this case, bits 5 to 8 of octet 3
+    // shall be coded as '1111'".
+
+    // MCC & MNC, 3 octets
+    let mcc = loc.mcc.toString();
+    let mnc = loc.mnc.toString();
+    if (mnc.length == 1) {
+      mnc = "F0" + mnc;
+    } else if (mnc.length == 2) {
+      mnc = "F" + mnc;
+    } else {
+      mnc = mnc[2] + mnc[0] + mnc[1];
+    }
+    GsmPDUHelper.writeSwappedNibbleBCD(mcc + mnc);
+
+    // LAC, 2 octets
+    GsmPDUHelper.writeHexOctet((loc.gsmLocationAreaCode >> 8) & 0xff);
+    GsmPDUHelper.writeHexOctet(loc.gsmLocationAreaCode & 0xff);
+
+    // Cell Id
+    if (loc.gsmCellId > 0xffff) {
+      // UMTS/WCDMA, gsmCellId is 28 bits.
+      GsmPDUHelper.writeHexOctet((loc.gsmCellId >> 24) & 0xff);
+      GsmPDUHelper.writeHexOctet((loc.gsmCellId >> 16) & 0xff);
+      GsmPDUHelper.writeHexOctet((loc.gsmCellId >> 8) & 0xff);
+      GsmPDUHelper.writeHexOctet(loc.gsmCellId & 0xff);
+    } else {
+      // GSM, gsmCellId is 16 bits.
+      GsmPDUHelper.writeHexOctet((loc.gsmCellId >> 8) & 0xff);
+      GsmPDUHelper.writeHexOctet(loc.gsmCellId & 0xff);
+    }
+  },
 };
 
 let BerTlvHelper = {
   /**
    * Decode Ber TLV.
    *
    * @param dataLen
    *        The length of data in bytes.