Bug 816564 - Silent SMS to Authenticate Device for Mobile Billing. Part 1: RIL. sr=vicamo
authorFernando Jiménez <ferjmoreno@gmail.com>
Tue, 30 Jul 2013 00:50:22 +0200
changeset 152668 bbbf11b2b3a8262a80482284b9d5c1b9998e4f98
parent 152667 933bd505fe4a516dcfc1779728d1fa59fe119bd1
child 152669 e660fb3f8481190efb9842cf65752d62825e3fb7
push id2859
push userakeybl@mozilla.com
push dateMon, 16 Sep 2013 19:14:59 +0000
treeherdermozilla-beta@87d3c51cd2bf [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersvicamo
bugs816564
milestone25.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 816564 - Silent SMS to Authenticate Device for Mobile Billing. Part 1: RIL. sr=vicamo
dom/system/gonk/RadioInterfaceLayer.js
dom/system/gonk/nsIRadioInterfaceLayer.idl
--- a/dom/system/gonk/RadioInterfaceLayer.js
+++ b/dom/system/gonk/RadioInterfaceLayer.js
@@ -46,16 +46,17 @@ const RADIOINTERFACE_CID =
 const RILNETWORKINTERFACE_CID =
   Components.ID("{3bdd52a9-3965-4130-b569-0ac5afed045e}");
 
 const nsIAudioManager = Ci.nsIAudioManager;
 const nsITelephonyProvider = Ci.nsITelephonyProvider;
 
 const kNetworkInterfaceStateChangedTopic = "network-interface-state-changed";
 const kSmsReceivedObserverTopic          = "sms-received";
+const kSilentSmsReceivedObserverTopic    = "silent-sms-received";
 const kSmsSendingObserverTopic           = "sms-sending";
 const kSmsSentObserverTopic              = "sms-sent";
 const kSmsFailedObserverTopic            = "sms-failed";
 const kSmsDeliverySuccessObserverTopic   = "sms-delivery-success";
 const kSmsDeliveryErrorObserverTopic     = "sms-delivery-error";
 const kMozSettingsChangedObserverTopic   = "mozsettings-changed";
 const kSysMsgListenerReadyObserverTopic  = "system-message-listener-ready";
 const kSysClockChangeObserverTopic       = "system-clock-change";
@@ -140,16 +141,20 @@ const RIL_IPC_CELLBROADCAST_MSG_NAMES = 
 XPCOMUtils.defineLazyServiceGetter(this, "gPowerManagerService",
                                    "@mozilla.org/power/powermanagerservice;1",
                                    "nsIPowerManagerService");
 
 XPCOMUtils.defineLazyServiceGetter(this, "gMobileMessageService",
                                    "@mozilla.org/mobilemessage/mobilemessageservice;1",
                                    "nsIMobileMessageService");
 
+XPCOMUtils.defineLazyServiceGetter(this, "gSmsService",
+                                   "@mozilla.org/sms/smsservice;1",
+                                   "nsISmsService");
+
 XPCOMUtils.defineLazyServiceGetter(this, "gMobileMessageDatabaseService",
                                    "@mozilla.org/mobilemessage/rilmobilemessagedatabaseservice;1",
                                    "nsIRilMobileMessageDatabaseService");
 
 XPCOMUtils.defineLazyServiceGetter(this, "ppmm",
                                    "@mozilla.org/parentprocessmessagemanager;1",
                                    "nsIMessageBroadcaster");
 
@@ -1883,16 +1888,41 @@ RadioInterface.prototype = {
     }
 
     message.type = "sms";
     message.sender = message.sender || null;
     message.receiver = this.getMsisdn();
     message.body = message.fullBody = message.fullBody || null;
     message.timestamp = Date.now();
 
+    if (gSmsService.isSilentNumber(message.sender)) {
+      message.id = -1;
+      message.threadId = 0;
+      message.delivery = DOM_MOBILE_MESSAGE_DELIVERY_RECEIVED;
+      message.deliveryStatus = RIL.GECKO_SMS_DELIVERY_STATUS_SUCCESS;
+      message.read = false;
+
+      let domMessage =
+        gMobileMessageService.createSmsMessage(message.id,
+                                               message.threadId,
+                                               message.delivery,
+                                               message.deliveryStatus,
+                                               message.sender,
+                                               message.receiver,
+                                               message.body,
+                                               message.messageClass,
+                                               message.timestamp,
+                                               message.read);
+
+      Services.obs.notifyObservers(domMessage,
+                                   kSilentSmsReceivedObserverTopic,
+                                   null);
+      return true;
+    }
+
     // TODO: Bug #768441
     // For now we don't store indicators persistently. When the mwi.discard
     // flag is false, we'll need to persist the indicator to EFmwis.
     // See TS 23.040 9.2.3.24.2
 
     let mwi = message.mwi;
     if (mwi) {
       mwi.returnNumber = message.sender;
@@ -1972,16 +2002,35 @@ RadioInterface.prototype = {
   handleSmsSent: function handleSmsSent(message) {
     if (DEBUG) this.debug("handleSmsSent: " + JSON.stringify(message));
 
     let options = this._sentSmsEnvelopes[message.envelopeId];
     if (!options) {
       return;
     }
 
+    if (options.silent) {
+      // There is no way to modify nsIDOMMozSmsMessage attributes as they are
+      // read only so we just create a new sms instance to send along with
+      // the notification.
+      let sms = options.sms;
+      options.request.notifyMessageSent(
+        gMobileMessageService.createSmsMessage(sms.id,
+                                               sms.threadId,
+                                               DOM_MOBILE_MESSAGE_DELIVERY_SENT,
+                                               sms.deliveryStatus,
+                                               sms.sender,
+                                               sms.receiver,
+                                               sms.body,
+                                               sms.messageClass,
+                                               sms.timestamp,
+                                               sms.read));
+      return;
+    }
+
     gMobileMessageDatabaseService.setMessageDelivery(options.sms.id,
                                                      null,
                                                      DOM_MOBILE_MESSAGE_DELIVERY_SENT,
                                                      options.sms.deliveryStatus,
                                                      function notifyResult(rv, domMessage) {
       // TODO bug 832140 handle !Components.isSuccessCode(rv)
       this.broadcastSmsSystemMessage("sms-sent", domMessage);
 
@@ -2001,16 +2050,20 @@ RadioInterface.prototype = {
     if (DEBUG) this.debug("handleSmsDelivery: " + JSON.stringify(message));
 
     let options = this._sentSmsEnvelopes[message.envelopeId];
     if (!options) {
       return;
     }
     delete this._sentSmsEnvelopes[message.envelopeId];
 
+    if (options.silent) {
+      return;
+    }
+
     gMobileMessageDatabaseService.setMessageDelivery(options.sms.id,
                                                      null,
                                                      options.sms.delivery,
                                                      message.deliveryStatus,
                                                      function notifyResult(rv, domMessage) {
       // TODO bug 832140 handle !Components.isSuccessCode(rv)
       let topic = (message.deliveryStatus == RIL.GECKO_SMS_DELIVERY_STATUS_SUCCESS)
                   ? kSmsDeliverySuccessObserverTopic
@@ -2030,16 +2083,21 @@ RadioInterface.prototype = {
 
     let error = Ci.nsIMobileMessageCallback.UNKNOWN_ERROR;
     switch (message.errorMsg) {
       case RIL.ERROR_RADIO_NOT_AVAILABLE:
         error = Ci.nsIMobileMessageCallback.NO_SIGNAL_ERROR;
         break;
     }
 
+    if (options.silent) {
+      options.request.notifySendMessageFailed(error);
+      return;
+    }
+
     gMobileMessageDatabaseService.setMessageDelivery(options.sms.id,
                                                      null,
                                                      DOM_MOBILE_MESSAGE_DELIVERY_ERROR,
                                                      RIL.GECKO_SMS_DELIVERY_STATUS_ERROR,
                                                      function notifyResult(rv, domMessage) {
       // TODO bug 832140 handle !Components.isSuccessCode(rv)
       options.request.notifySendMessageFailed(error);
       Services.obs.notifyObservers(domMessage, kSmsFailedObserverTopic, null);
@@ -3140,17 +3198,17 @@ RadioInterface.prototype = {
     }
 
     let result = gMobileMessageService.createSmsSegmentInfo(options.segmentMaxSeq,
                                                             options.segmentChars,
                                                             options.segmentChars - charsInLastSegment);
     return result;
   },
 
-  sendSMS: function sendSMS(number, message, request) {
+  sendSMS: function sendSMS(number, message, silent, request) {
     let strict7BitEncoding;
     try {
       strict7BitEncoding = Services.prefs.getBoolPref("dom.sms.strict7BitEncoding");
     } catch (e) {
       strict7BitEncoding = false;
     }
 
     let options = this._fragmentText(message, null, strict7BitEncoding);
@@ -3164,71 +3222,96 @@ RadioInterface.prototype = {
       requestStatusReport = true;
     }
     options.requestStatusReport = requestStatusReport;
     if (options.segmentMaxSeq > 1) {
       options.segmentRef16Bit = this.segmentRef16Bit;
       options.segmentRef = this.nextSegmentRef;
     }
 
+    let notifyResult = (function notifyResult(rv, domMessage) {
+      // TODO bug 832140 handle !Components.isSuccessCode(rv)
+      if (!silent) {
+        Services.obs.notifyObservers(domMessage, kSmsSendingObserverTopic, null);
+      }
+
+      // If the radio is disabled or the SIM card is not ready, just directly
+      // return with the corresponding error code.
+      let errorCode;
+      if (!PhoneNumberUtils.isPlainPhoneNumber(options.number)) {
+        if (DEBUG) this.debug("Error! Address is invalid when sending SMS: " +
+                              options.number);
+        errorCode = Ci.nsIMobileMessageCallback.INVALID_ADDRESS_ERROR;
+      } else if (!this._radioEnabled) {
+        if (DEBUG) this.debug("Error! Radio is disabled when sending SMS.");
+        errorCode = Ci.nsIMobileMessageCallback.RADIO_DISABLED_ERROR;
+      } else if (this.rilContext.cardState != "ready") {
+        if (DEBUG) this.debug("Error! SIM card is not ready when sending SMS.");
+        errorCode = Ci.nsIMobileMessageCallback.NO_SIM_CARD_ERROR;
+      }
+      if (errorCode) {
+        if (silent) {
+          request.notifySendMessageFailed(errorCode);
+          return;
+        }
+
+        gMobileMessageDatabaseService
+          .setMessageDelivery(domMessage.id,
+                              null,
+                              DOM_MOBILE_MESSAGE_DELIVERY_ERROR,
+                              RIL.GECKO_SMS_DELIVERY_STATUS_ERROR,
+                              function notifyResult(rv, domMessage) {
+          // TODO bug 832140 handle !Components.isSuccessCode(rv)
+          request.notifySendMessageFailed(errorCode);
+          Services.obs.notifyObservers(domMessage, kSmsFailedObserverTopic, null);
+        });
+        return;
+      }
+
+      // Keep current SMS message info for sent/delivered notifications
+      options.envelopeId = this.createSmsEnvelope({
+        request: request,
+        sms: domMessage,
+        requestStatusReport: options.requestStatusReport,
+        silent: silent
+      });
+
+      // This is the entry point starting to send SMS.
+      this.worker.postMessage(options);
+    }).bind(this);
+
     let sendingMessage = {
       type: "sms",
       sender: this.getMsisdn(),
       receiver: number,
       body: message,
       deliveryStatusRequested: options.requestStatusReport,
       timestamp: Date.now()
     };
 
+    if (silent) {
+      let deliveryStatus = RIL.GECKO_SMS_DELIVERY_STATUS_PENDING;
+      let delivery = DOM_MOBILE_MESSAGE_DELIVERY_SENDING;
+      let domMessage =
+        gMobileMessageService.createSmsMessage(-1, // id
+                                               0,  // threadId
+                                               delivery,
+                                               deliveryStatus,
+                                               sendingMessage.sender,
+                                               sendingMessage.receiver,
+                                               sendingMessage.body,
+                                               "normal", // message class
+                                               sendingMessage.timestamp,
+                                               false);
+      notifyResult(Cr.NS_OK, domMessage);
+      return;
+    }
+
     let id = gMobileMessageDatabaseService.saveSendingMessage(
-      sendingMessage,
-      function notifyResult(rv, domMessage) {
-
-        // TODO bug 832140 handle !Components.isSuccessCode(rv)
-        Services.obs.notifyObservers(domMessage, kSmsSendingObserverTopic, null);
-
-        // If the radio is disabled or the SIM card is not ready, just directly
-        // return with the corresponding error code.
-        let errorCode;
-        if (!PhoneNumberUtils.isPlainPhoneNumber(options.number)) {
-          if (DEBUG) this.debug("Error! Address is invalid when sending SMS: " +
-                                options.number);
-          errorCode = Ci.nsIMobileMessageCallback.INVALID_ADDRESS_ERROR;
-        } else if (!this._radioEnabled) {
-          if (DEBUG) this.debug("Error! Radio is disabled when sending SMS.");
-          errorCode = Ci.nsIMobileMessageCallback.RADIO_DISABLED_ERROR;
-        } else if (this.rilContext.cardState != "ready") {
-          if (DEBUG) this.debug("Error! SIM card is not ready when sending SMS.");
-          errorCode = Ci.nsIMobileMessageCallback.NO_SIM_CARD_ERROR;
-        }
-        if (errorCode) {
-          gMobileMessageDatabaseService
-            .setMessageDelivery(domMessage.id,
-                                null,
-                                DOM_MOBILE_MESSAGE_DELIVERY_ERROR,
-                                RIL.GECKO_SMS_DELIVERY_STATUS_ERROR,
-                                function notifyResult(rv, domMessage) {
-            // TODO bug 832140 handle !Components.isSuccessCode(rv)
-            request.notifySendMessageFailed(errorCode);
-            Services.obs.notifyObservers(domMessage, kSmsFailedObserverTopic, null);
-          });
-          return;
-        }
-
-        // Keep current SMS message info for sent/delivered notifications
-        options.envelopeId = this.createSmsEnvelope({
-          request: request,
-          sms: domMessage,
-          requestStatusReport: options.requestStatusReport
-        });
-
-        // This is the entry point starting to send SMS.
-        this.worker.postMessage(options);
-
-      }.bind(this));
+      sendingMessage, notifyResult);
   },
 
   registerDataCallCallback: function registerDataCallCallback(callback) {
     if (this._datacall_callbacks) {
       if (this._datacall_callbacks.indexOf(callback) != -1) {
         throw new Error("Already registered this callback!");
       }
     } else {
--- a/dom/system/gonk/nsIRadioInterfaceLayer.idl
+++ b/dom/system/gonk/nsIRadioInterfaceLayer.idl
@@ -74,17 +74,17 @@ interface nsIRilContext : nsISupports
 
   readonly attribute nsIDOMMozIccInfo iccInfo;
 
   readonly attribute nsIDOMMozMobileConnectionInfo voice;
 
   readonly attribute nsIDOMMozMobileConnectionInfo data;
 };
 
-[scriptable, uuid(6dde3eaf-243d-4afa-abdb-95c94c2b1c7a)]
+[scriptable, uuid(715c972b-97c5-48fd-a8b1-d50e6852153a)]
 interface nsIRadioInterface : nsISupports
 {
   /**
    * Activates or deactivates radio power.
    */
   void setRadioEnabled(in bool value);
 
   readonly attribute nsIRilContext rilContext;
@@ -114,16 +114,17 @@ interface nsIRadioInterface : nsISupport
 
   /**
    * SMS-related functionality.
    */
   nsIDOMMozSmsSegmentInfo getSegmentInfoForText(in DOMString text);
 
   void sendSMS(in DOMString number,
                in DOMString message,
+               in boolean silent,
                in nsIMobileMessageCallback request);
 };
 
 [scriptable, uuid(44b03951-1444-4c03-bd37-0bcb3a01b56f)]
 interface nsIRadioInterfaceLayer : nsISupports
 {
   readonly attribute unsigned long numRadioInterfaces;