Bug 778093 - Part 6/9: Support GSM CBS message paging. r=hsinyi, a=blocking-basecamp
authorVicamo Yang <vyang@mozilla.com>
Tue, 04 Dec 2012 10:41:35 +0800
changeset 118591 26bc0d59089f95eea5605af7ab3391ea6121af54
parent 118590 0a48e8d683ba7775b7fa267e134405cc0070153f
child 118592 94c099d6c23ad3efc746c2005b81e5fb2cf3b5af
push idunknown
push userunknown
push dateunknown
reviewershsinyi, blocking-basecamp
bugs778093
milestone19.0a2
Bug 778093 - Part 6/9: Support GSM CBS message paging. r=hsinyi, a=blocking-basecamp
dom/system/gonk/ril_worker.js
--- a/dom/system/gonk/ril_worker.js
+++ b/dom/system/gonk/ril_worker.js
@@ -688,16 +688,18 @@ let RIL = {
   _pendingSentSmsMap: {},
 
   /**
    * Index of the RIL_PREFERRED_NETWORK_TYPE_TO_GECKO. Its value should be
    * preserved over rild reset.
    */
   preferredNetworkType: null,
 
+  _receivedSmsCbPagesMap: {},
+
   initRILState: function initRILState() {
     /**
      * One of the RADIO_STATE_* constants.
      */
     this.radioState = GECKO_RADIOSTATE_UNAVAILABLE;
     this._isInitialRadioState = true;
 
     /**
@@ -4432,16 +4434,108 @@ let RIL = {
     let next = options.segmentSeq;
     options.body = options.segments[next].body;
     options.encodedBodyLength = options.segments[next].encodedBodyLength;
     options.segmentSeq = next + 1;
 
     this.sendSMS(options);
   },
 
+  _processReceivedSmsCbPage: function _processReceivedSmsCbPage(original) {
+    if (original.numPages <= 1) {
+      if (original.body) {
+        original.fullBody = original.body;
+        delete original.body;
+      } else if (original.data) {
+        original.fullData = original.data;
+        delete original.data;
+      }
+      return original;
+    }
+
+    // Hash = <serial>:<mcc>:<mnc>:<lac>:<cid>
+    let hash = original.serial + ":" + this.iccInfo.mcc + ":"
+               + this.iccInfo.mnc + ":";
+    switch (original.geographicalScope) {
+      case CB_GSM_GEOGRAPHICAL_SCOPE_CELL_WIDE_IMMEDIATE:
+      case CB_GSM_GEOGRAPHICAL_SCOPE_CELL_WIDE:
+        hash += this.voiceRegistrationState.cell.gsmLocationAreaCode + ":"
+             + this.voiceRegistrationState.cell.gsmCellId;
+        break;
+      case CB_GSM_GEOGRAPHICAL_SCOPE_LOCATION_AREA_WIDE:
+        hash += this.voiceRegistrationState.cell.gsmLocationAreaCode + ":";
+        break;
+      default:
+        hash += ":";
+        break;
+    }
+
+    let index = original.pageIndex;
+
+    let options = this._receivedSmsCbPagesMap[hash];
+    if (!options) {
+      options = original;
+      this._receivedSmsCbPagesMap[hash] = options;
+
+      options.receivedPages = 0;
+      options.pages = [];
+    } else if (options.pages[index]) {
+      // Duplicated page?
+      if (DEBUG) {
+        debug("Got duplicated page no." + index + " of a multipage SMSCB: "
+              + JSON.stringify(original));
+      }
+      return null;
+    }
+
+    if (options.encoding == PDU_DCS_MSG_CODING_8BITS_ALPHABET) {
+      options.pages[index] = original.data;
+      delete original.data;
+    } else {
+      options.pages[index] = original.body;
+      delete original.body;
+    }
+    options.receivedPages++;
+    if (options.receivedPages < options.numPages) {
+      if (DEBUG) {
+        debug("Got page no." + index + " of a multipage SMSCB: "
+              + JSON.stringify(options));
+      }
+      return null;
+    }
+
+    // Remove from map
+    delete this._receivedSmsCbPagesMap[hash];
+
+    // Rebuild full body
+    if (options.encoding == PDU_DCS_MSG_CODING_8BITS_ALPHABET) {
+      // Uint8Array doesn't have `concat`, so we have to merge all pages by hand.
+      let fullDataLen = 0;
+      for (let i = 1; i <= options.numPages; i++) {
+        fullDataLen += options.pages[i].length;
+      }
+
+      options.fullData = new Uint8Array(fullDataLen);
+      for (let d= 0, i = 1; i <= options.numPages; i++) {
+        let data = options.pages[i];
+        for (let j = 0; j < data.length; j++) {
+          options.fullData[d++] = data[j];
+        }
+      }
+    } else {
+      options.fullBody = options.pages.join("");
+    }
+
+    if (DEBUG) {
+      debug("Got full multipage SMSCB: " + JSON.stringify(options));
+    }
+
+    return options;
+  },
+
   /**
    * Handle incoming messages from the main UI thread.
    *
    * @param message
    *        Object containing the message. Messages are supposed
    */
   handleDOMMessage: function handleMessage(message) {
     if (DEBUG) debug("Received DOM message " + JSON.stringify(message));
@@ -5524,16 +5618,21 @@ RIL[UNSOLICITED_RESPONSE_NEW_BROADCAST_S
     message = GsmPDUHelper.readCbMessage(Buf.readUint32());
   } catch (e) {
     if (DEBUG) {
       debug("Failed to parse Cell Broadcast message: " + JSON.stringify(e));
     }
     return;
   }
 
+  message = this._processReceivedSmsCbPage(message);
+  if (!message) {
+    return;
+  }
+
   message.rilMessageType = "cellbroadcast-received";
   this.sendDOMMessage(message);
 };
 RIL[UNSOLICITED_CDMA_RUIM_SMS_STORAGE_FULL] = null;
 RIL[UNSOLICITED_RESTRICTED_STATE_CHANGED] = null;
 RIL[UNSOLICITED_ENTER_EMERGENCY_CALLBACK_MODE] = null;
 RIL[UNSOLICITED_CDMA_CALL_WAITING] = null;
 RIL[UNSOLICITED_CDMA_OTA_PROVISION_STATUS] = null;
@@ -6958,20 +7057,20 @@ let GsmPDUHelper = {
    * Read GSM CBS message serial number.
    *
    * @param msg
    *        message object for output.
    *
    * @see 3GPP TS 23.041 section 9.4.1.2.1
    */
   readCbSerialNumber: function readCbSerialNumber(msg) {
-    let serial = Buf.readUint8() << 8 | Buf.readUint8();
-    msg.geographicalScope = (serial >>> 14) & 0x03;
-    msg.messageCode = (serial >>> 4) & 0x03FF;
-    msg.updateNumber = serial & 0x0F;
+    msg.serial = Buf.readUint8() << 8 | Buf.readUint8();
+    msg.geographicalScope = (msg.serial >>> 14) & 0x03;
+    msg.messageCode = (msg.serial >>> 4) & 0x03FF;
+    msg.updateNumber = msg.serial & 0x0F;
   },
 
   /**
    * Read GSM CBS message message identifier.
    *
    * @param msg
    *        message object for output.
    *
@@ -7166,16 +7265,17 @@ let GsmPDUHelper = {
    *
    * @param pduLength
    *        total length of the incoming PDU in octets.
    */
   readCbMessage: function readCbMessage(pduLength) {
     // Validity                                                   GSM ETWS UMTS
     let msg = {
       // Internally used in ril_worker:
+      serial:               null,                              //  O   O    O
       updateNumber:         null,                              //  O   O    O
       format:               null,                              //  O   O    O
       dcs:                  0x0F,                              //  O   X    O
       encoding:             PDU_DCS_MSG_CODING_7BITS_ALPHABET, //  O   X    O
       hasLanguageIndicator: false,                             //  O   X    O
       data:                 null,                              //  O   X    O
       body:                 null,                              //  O   X    O
       pageIndex:            1,                                 //  O   X    X