Bug 1072808 - Part 2: Add SmsMessenger as a Wrapper for Sms-Related System Messages. r=echen
☠☠ backed out by c88725975388 ☠ ☠
authorBevis Tseng <btseng@mozilla.com>
Fri, 24 Oct 2014 11:33:01 +0800
changeset 241675 768b2ca4e1010960c53fa4c1a90a1654b8008c26
parent 241674 3f32bfdb0dbaa4ce3cb7f780ce95ed126326cefb
child 241676 fab00bedff2d03434ff55d1a20c29b31851235cf
push id4311
push userraliiev@mozilla.com
push dateMon, 12 Jan 2015 19:37:41 +0000
treeherdermozilla-beta@150c9fed433b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersechen
bugs1072808
milestone36.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 1072808 - Part 2: Add SmsMessenger as a Wrapper for Sms-Related System Messages. r=echen
dom/mobilemessage/interfaces/moz.build
dom/mobilemessage/interfaces/nsISmsMessenger.idl
dom/mobilemessage/interfaces/nsISmsService.idl
dom/system/gonk/RILSystemMessenger.jsm
dom/system/gonk/RILSystemMessengerHelper.js
dom/system/gonk/RadioInterfaceLayer.js
dom/system/gonk/tests/test_ril_system_messenger.js
--- a/dom/mobilemessage/interfaces/moz.build
+++ b/dom/mobilemessage/interfaces/moz.build
@@ -16,12 +16,13 @@ XPIDL_SOURCES += [
     'nsIMobileMessageService.idl',
     'nsISmsService.idl',
     'nsIWapPushApplication.idl',
 ]
 
 if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk' and CONFIG['MOZ_B2G_RIL']:
     XPIDL_SOURCES += [
         'nsIRilMobileMessageDatabaseService.idl',
+        'nsISmsMessenger.idl',
     ]
 
 XPIDL_MODULE = 'dom_mobilemessage'
 
new file mode 100644
--- /dev/null
+++ b/dom/mobilemessage/interfaces/nsISmsMessenger.idl
@@ -0,0 +1,69 @@
+/* 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 "domstubs.idl"
+#include "nsISupports.idl"
+
+[scriptable, uuid(f77ad4d4-68a9-11e4-920f-0b26b7a5e713)]
+interface nsISmsMessenger : nsISupports
+{
+  /* 'sms-received' system message */
+  const unsigned short NOTIFICATION_TYPE_RECEIVED = 0;
+  /* 'sms-sent' system message */
+  const unsigned short NOTIFICATION_TYPE_SENT = 1;
+  /* 'sms-delivery-success' system message */
+  const unsigned short NOTIFICATION_TYPE_DELIVERY_SUCCESS = 2;
+
+  /**
+   * To broadcast 'sms-received', 'sms-delivery-success', 'sms-sent' system message
+   *
+   * Note: Except aNotificationType, all parameters are the attributes of the
+   * nsIDOMMozSmsMessage generated by nsIMobileMessageService.createSmsMessage().
+   *
+   * @param aNotificationType
+   *        A predefined constant of nsISmsMessenger.NOTIFICATION_TYPE_*.
+   * @param aId
+   *        The unique identity of this message.
+   * @param aThreadId
+   *        The unique identity of the thread this message belongs to.
+   * @param aIccId
+   *        Integrated Circuit Card Identifier. null if ICC is not available.
+   * @param aDelivery
+   *        A predefined constant of nsISmsService.DELIVERY_TYPE_*.
+   * @param aDeliveryStatus
+   *        A predefined constant of nsISmsService.DELIVERY_STATUS_TYPE_*.
+   * @param aSender
+   *        Sender address. null if not available.
+   * @param aReceiver
+   *        Receiver address. null if not available.
+   * @param aBody
+   *        Text message body. null if not available.
+   * @param aMessageClass
+   *        A predefined constant of nsISmsService.MESSAGE_CLASS_TYPE_*.
+   * @param aTimestamp
+   *        The device system time when creating or saving this message.
+   * @param aSentTimestamp
+   *        The SMSC timestamp of the incoming message.
+   *        0 if not available.
+   * @param aDeliveryTimestamp
+   *        The delivery timestamp to the remote party of the sent message.
+   *        0 if not available.
+   * @param aRead
+   *        True if the message was read.
+   */
+  void notifySms(in unsigned short aNotificationType,
+                 in long aId,
+                 in unsigned long long aThreadId,
+                 in DOMString aIccId,
+                 in unsigned long aDelivery,
+                 in unsigned long aDeliveryStatus,
+                 in DOMString aSender,
+                 in DOMString aReceiver,
+                 in DOMString aBody,
+                 in unsigned long aMessageClass,
+                 in DOMTimeStamp aTimestamp,
+                 in DOMTimeStamp aSentTimestamp,
+                 in DOMTimeStamp aDeliveryTimestamp,
+                 in boolean aRead);
+};
--- a/dom/mobilemessage/interfaces/nsISmsService.idl
+++ b/dom/mobilemessage/interfaces/nsISmsService.idl
@@ -7,19 +7,45 @@
 interface nsIDOMMozSmsMessage;
 interface nsIMobileMessageCallback;
 
 %{C++
 #define SMS_SERVICE_CID { 0xbada3cb8, 0xa568, 0x4dff, { 0xb5, 0x43, 0x52, 0xbb, 0xb3, 0x14, 0x31, 0x21 } }
 #define SMS_SERVICE_CONTRACTID "@mozilla.org/sms/smsservice;1"
 %}
 
-[scriptable, builtinclass, uuid(cb7d7b60-01f1-4241-a0ae-2ff035c3fbe5)]
+[scriptable, builtinclass, uuid(8f86d068-698e-11e4-9470-8f75a088b84a)]
 interface nsISmsService : nsISupports
 {
+  /**
+   * Constant definitions of predefined GSM Message Class
+   * See 3GPP TS 23.038 clause 4 SMS Data Coding Scheme
+   */
+  const unsigned short MESSAGE_CLASS_TYPE_CLASS_0 = 0;
+  const unsigned short MESSAGE_CLASS_TYPE_CLASS_1 = 1;
+  const unsigned short MESSAGE_CLASS_TYPE_CLASS_2 = 2;
+  const unsigned short MESSAGE_CLASS_TYPE_CLASS_3 = 3;
+  const unsigned short MESSAGE_CLASS_TYPE_NORMAL  = 6;
+
+  /**
+   * Constant definitions of SMS Delivery
+   */
+  const unsigned short DELIVERY_TYPE_RECEIVED = 0;
+  const unsigned short DELIVERY_TYPE_SENDING  = 1;
+  const unsigned short DELIVERY_TYPE_SENT     = 2;
+  const unsigned short DELIVERY_TYPE_ERROR    = 3;
+
+  /**
+   * Constant definitions of SMS Delivery Status
+   */
+  const unsigned short DELIVERY_STATUS_TYPE_NOT_APPLICABLE = 0;
+  const unsigned short DELIVERY_STATUS_TYPE_SUCCESS        = 1;
+  const unsigned short DELIVERY_STATUS_TYPE_PENDING        = 2;
+  const unsigned short DELIVERY_STATUS_TYPE_ERROR          = 3;
+
   readonly attribute unsigned long smsDefaultServiceId;
 
   void getSegmentInfoForText(in DOMString text,
                              in nsIMobileMessageCallback request);
 
   void send(in unsigned long serviceId,
             in DOMString number,
             in DOMString message,
--- a/dom/system/gonk/RILSystemMessenger.jsm
+++ b/dom/system/gonk/RILSystemMessenger.jsm
@@ -1,14 +1,24 @@
 /* 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/. */
 
 "use strict";
 
+const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
+
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+
+XPCOMUtils.defineLazyGetter(this, "RIL", function () {
+  let obj = {};
+  Cu.import("resource://gre/modules/ril_consts.js", obj);
+  return obj;
+});
+
 /**
  * RILSystemMessenger
  */
 this.RILSystemMessenger = function() {};
 RILSystemMessenger.prototype = {
 
   /**
    * Hook of Broadcast function
@@ -43,14 +53,62 @@ RILSystemMessenger.prototype = {
       hangUpLocal: aHangUpLocal
     };
 
     if (aCdmaWaitingNumber != null) {
       data.secondNumber = aCdmaWaitingNumber;
     }
 
     this.broadcastMessage("telephony-call-ended", data);
+  },
+
+  _convertSmsMessageClass: function(aMessageClass) {
+    return RIL.GECKO_SMS_MESSAGE_CLASSES[aMessageClass] || null;
+  },
+
+  _convertSmsDelivery: function(aDelivery) {
+    return ["received", "sending", "sent", "error"][aDelivery] || null;
+  },
+
+  _convertSmsDeliveryStatus: function(aDeliveryStatus) {
+    return [
+      RIL.GECKO_SMS_DELIVERY_STATUS_NOT_APPLICABLE,
+      RIL.GECKO_SMS_DELIVERY_STATUS_SUCCESS,
+      RIL.GECKO_SMS_DELIVERY_STATUS_PENDING,
+      RIL.GECKO_SMS_DELIVERY_STATUS_ERROR
+    ][aDeliveryStatus] || null;
+  },
+
+  /**
+   * Wrapper to send 'sms-received', 'sms-delivery-success', 'sms-sent' system message.
+   */
+  notifySms: function(aNotificationType, aId, aThreadId, aIccId, aDelivery,
+                      aDeliveryStatus, aSender, aReceiver, aBody, aMessageClass,
+                      aTimestamp, aSentTimestamp, aDeliveryTimestamp, aRead) {
+    let msgType =
+      ["sms-received", "sms-sent", "sms-delivery-success"][aNotificationType];
+
+    if (!msgType) {
+      throw new Error("Invalid Notification Type: " + aNotificationType);
+    }
+
+    this.broadcastMessage(msgType, {
+      iccId:             aIccId,
+      type:              "sms",
+      id:                aId,
+      threadId:          aThreadId,
+      delivery:          this._convertSmsDelivery(aDelivery),
+      deliveryStatus:    this._convertSmsDeliveryStatus(aDeliveryStatus),
+      sender:            aSender,
+      receiver:          aReceiver,
+      body:              aBody,
+      messageClass:      this._convertSmsMessageClass(aMessageClass),
+      timestamp:         aTimestamp,
+      sentTimestamp:     aSentTimestamp,
+      deliveryTimestamp: aDeliveryTimestamp,
+      read:              aRead
+    });
   }
 };
 
 this.EXPORTED_SYMBOLS = [
   'RILSystemMessenger'
 ];
--- a/dom/system/gonk/RILSystemMessengerHelper.js
+++ b/dom/system/gonk/RILSystemMessengerHelper.js
@@ -44,17 +44,18 @@ function RILSystemMessengerHelper() {
     }
 
     gSystemMessenger.broadcastMessage(aType, aMessage);
   };
 }
 RILSystemMessengerHelper.prototype = {
 
   classID: RILSYSTEMMESSENGERHELPER_CID,
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsITelephonyMessenger]),
+  QueryInterface: XPCOMUtils.generateQI([Ci.nsITelephonyMessenger,
+                                         Ci.nsISmsMessenger]),
 
   /**
    * RILSystemMessenger instance.
    */
   messenger: null,
 
   /**
    * nsITelephonyMessenger API
@@ -62,12 +63,23 @@ RILSystemMessengerHelper.prototype = {
   notifyNewCall: function() {
     this.messenger.notifyNewCall();
   },
 
   notifyCallEnded: function(aServiceId, aNumber, aCdmaWaitingNumber, aEmergency,
                             aDuration, aOutgoing, aHangUpLocal) {
     this.messenger.notifyCallEnded(aServiceId, aNumber, aCdmaWaitingNumber, aEmergency,
                                    aDuration, aOutgoing, aHangUpLocal);
+  },
+
+  /**
+   * nsISmsMessenger API
+   */
+  notifySms: function(aNotificationType, aId, aThreadId, aIccId, aDelivery,
+                      aDeliveryStatus, aSender, aReceiver, aBody, aMessageClass,
+                      aTimestamp, aSentTimestamp, aDeliveryTimestamp, aRead) {
+    this.messenger.notifySms(aNotificationType, aId, aThreadId, aIccId, aDelivery,
+                             aDeliveryStatus, aSender, aReceiver, aBody, aMessageClass,
+                             aTimestamp, aSentTimestamp, aDeliveryTimestamp, aRead);
   }
 };
 
 this.NSGetFactory = XPCOMUtils.generateNSGetFactory([RILSystemMessengerHelper]);
\ No newline at end of file
--- a/dom/system/gonk/RadioInterfaceLayer.js
+++ b/dom/system/gonk/RadioInterfaceLayer.js
@@ -182,16 +182,20 @@ XPCOMUtils.defineLazyServiceGetter(this,
 XPCOMUtils.defineLazyServiceGetter(this, "gMobileConnectionService",
                                    "@mozilla.org/mobileconnection/mobileconnectionservice;1",
                                    "nsIGonkMobileConnectionService");
 
 XPCOMUtils.defineLazyServiceGetter(this, "gCellBroadcastService",
                                    "@mozilla.org/cellbroadcast/gonkservice;1",
                                    "nsIGonkCellBroadcastService");
 
+XPCOMUtils.defineLazyServiceGetter(this, "gSmsMessenger",
+                                   "@mozilla.org/ril/system-messenger-helper;1",
+                                   "nsISmsMessenger");
+
 XPCOMUtils.defineLazyGetter(this, "WAP", function() {
   let wap = {};
   Cu.import("resource://gre/modules/WapPushManager.js", wap);
   return wap;
 });
 
 XPCOMUtils.defineLazyGetter(this, "PhoneNumberUtils", function() {
   let ns = {};
@@ -2166,47 +2170,90 @@ RadioInterface.prototype = {
       destinationAddress: this.rilContext.iccInfo.msisdn,
       destinationPort: message.destinationPort,
       serviceId: this.clientId
     };
     WAP.WapPushManager.receiveWdpPDU(message.fullData, message.fullData.length,
                                      0, options);
   },
 
+  _convertSmsMessageClass: function(aMessageClass) {
+    let index = RIL.GECKO_SMS_MESSAGE_CLASSES.indexOf(aMessageClass);
+
+    if (index < 0) {
+      throw new Error("Invalid MessageClass: " + aMessageClass);
+    }
+
+    return index;
+  },
+
+  _convertSmsDelivery: function(aDelivery) {
+    let index = [DOM_MOBILE_MESSAGE_DELIVERY_RECEIVED,
+                 DOM_MOBILE_MESSAGE_DELIVERY_SENDING,
+                 DOM_MOBILE_MESSAGE_DELIVERY_SENT,
+                 DOM_MOBILE_MESSAGE_DELIVERY_ERROR].indexOf(aDelivery);
+
+    if (index < 0) {
+      throw new Error("Invalid Delivery: " + aDelivery);
+    }
+
+    return index;
+  },
+
+  _convertSmsDeliveryStatus: function(aDeliveryStatus) {
+    let index = [RIL.GECKO_SMS_DELIVERY_STATUS_NOT_APPLICABLE,
+                 RIL.GECKO_SMS_DELIVERY_STATUS_SUCCESS,
+                 RIL.GECKO_SMS_DELIVERY_STATUS_PENDING,
+                 RIL.GECKO_SMS_DELIVERY_STATUS_ERROR].indexOf(aDeliveryStatus);
+
+    if (index < 0) {
+      throw new Error("Invalid DeliveryStatus: " + aDeliveryStatus);
+    }
+
+    return index;
+  },
+
   /**
    * A helper to broadcast the system message to launch registered apps
    * like Costcontrol, Notification and Message app... etc.
    *
    * @param aName
    *        The system message name.
    * @param aDomMessage
    *        The nsIDOMMozSmsMessage object.
    */
-  broadcastSmsSystemMessage: function(aName, aDomMessage) {
-    if (DEBUG) this.debug("Broadcasting the SMS system message: " + aName);
+  broadcastSmsSystemMessage: function(aNotificationType, aDomMessage) {
+    if (DEBUG) this.debug("Broadcasting the SMS system message: " + aNotificationType);
 
     // Sadly we cannot directly broadcast the aDomMessage object
     // because the system message mechamism will rewrap the object
     // based on the content window, which needs to know the properties.
-    gSystemMessenger.broadcastMessage(aName, {
-      iccId:             aDomMessage.iccId,
-      type:              aDomMessage.type,
-      id:                aDomMessage.id,
-      threadId:          aDomMessage.threadId,
-      delivery:          aDomMessage.delivery,
-      deliveryStatus:    aDomMessage.deliveryStatus,
-      sender:            aDomMessage.sender,
-      receiver:          aDomMessage.receiver,
-      body:              aDomMessage.body,
-      messageClass:      aDomMessage.messageClass,
-      timestamp:         aDomMessage.timestamp,
-      sentTimestamp:     aDomMessage.sentTimestamp,
-      deliveryTimestamp: aDomMessage.deliveryTimestamp,
-      read:              aDomMessage.read
-    });
+    try {
+      gSmsMessenger.notifySms(aNotificationType,
+                              aDomMessage.id,
+                              aDomMessage.threadId,
+                              aDomMessage.iccId,
+                              this._convertSmsDelivery(
+                                aDomMessage.delivery),
+                              this._convertSmsDeliveryStatus(
+                                aDomMessage.deliveryStatus),
+                              aDomMessage.sender,
+                              aDomMessage.receiver,
+                              aDomMessage.body,
+                              this._convertSmsMessageClass(
+                                aDomMessage.messageClass),
+                              aDomMessage.timestamp,
+                              aDomMessage.sentTimestamp,
+                              aDomMessage.deliveryTimestamp,
+                              aDomMessage.read);
+    } catch (e) {
+      if (DEBUG) {
+        this.debug("Failed to broadcastSmsSystemMessage: " + e);
+      }
+    }
   },
 
   // The following attributes/functions are used for acquiring/releasing the
   // CPU wake lock when the RIL handles the received SMS. Note that we need
   // a timer to bound the lock's life cycle to avoid exhausting the battery.
   _smsHandledWakeLock: null,
   _smsHandledWakeLockTimer: null,
 
@@ -2541,17 +2588,18 @@ RadioInterface.prototype = {
         // At this point we could send a message to content to notify the user
         // that storing an incoming SMS failed, most likely due to a full disk.
         if (DEBUG) {
           this.debug("Could not store SMS, error code " + rv);
         }
         return;
       }
 
-      this.broadcastSmsSystemMessage(kSmsReceivedObserverTopic, domMessage);
+      this.broadcastSmsSystemMessage(
+        Ci.nsISmsMessenger.NOTIFICATION_TYPE_RECEIVED, domMessage);
       Services.obs.notifyObservers(domMessage, kSmsReceivedObserverTopic, null);
     }.bind(this);
 
     if (message.messageClass != RIL.GECKO_SMS_MESSAGE_CLASSES[RIL.PDU_DCS_MSG_CLASS_0]) {
       gMobileMessageDatabaseService.saveReceivedMessage(message,
                                                         notifyReceived);
     } else {
       message.id = -1;
@@ -3658,17 +3706,18 @@ RadioInterface.prototype = {
 
             let topic = (response.deliveryStatus ==
                          RIL.GECKO_SMS_DELIVERY_STATUS_SUCCESS)
                         ? kSmsDeliverySuccessObserverTopic
                         : kSmsDeliveryErrorObserverTopic;
 
             // Broadcasting a "sms-delivery-success" system message to open apps.
             if (topic == kSmsDeliverySuccessObserverTopic) {
-              this.broadcastSmsSystemMessage(topic, domMessage);
+              this.broadcastSmsSystemMessage(
+                Ci.nsISmsMessenger.NOTIFICATION_TYPE_DELIVERY_SUCCESS, domMessage);
             }
 
             // Notifying observers the delivery status is updated.
             Services.obs.notifyObservers(domMessage, topic, null);
           }).bind(this));
 
           // Send transaction has ended completely.
           return false;
@@ -3706,17 +3755,18 @@ RadioInterface.prototype = {
                                          null,
                                          (function notifyResult(rv, domMessage) {
           // TODO bug 832140 handle !Components.isSuccessCode(rv)
 
           if (context.requestStatusReport) {
             context.sms = domMessage;
           }
 
-          this.broadcastSmsSystemMessage(kSmsSentObserverTopic, domMessage);
+          this.broadcastSmsSystemMessage(
+            Ci.nsISmsMessenger.NOTIFICATION_TYPE_SENT, domMessage);
           context.request.notifyMessageSent(domMessage);
           Services.obs.notifyObservers(domMessage, kSmsSentObserverTopic, null);
         }).bind(this));
 
         // Only keep current context if we have requested for delivery report.
         return context.requestStatusReport;
       }).bind(this, context)); // End of |workerMessenger.send| callback.
     }).bind(this); // End of DB saveSendingMessage callback.
--- a/dom/system/gonk/tests/test_ril_system_messenger.js
+++ b/dom/system/gonk/tests/test_ril_system_messenger.js
@@ -43,17 +43,21 @@ function equal_received_system_message(a
 
 /**
  * Verify that each nsIXxxMessenger could be retrieved.
  */
 function run_test() {
   let telephonyMessenger = Cc["@mozilla.org/ril/system-messenger-helper;1"]
                            .getService(Ci.nsITelephonyMessenger);
 
+  let smsMessenger = Cc["@mozilla.org/ril/system-messenger-helper;1"]
+                     .getService(Ci.nsISmsMessenger);
+
   ok(telephonyMessenger !== null, "Get TelephonyMessenger.");
+  ok(smsMessenger != null, "Get SmsMessenger.");
 
   run_next_test();
 }
 
 /**
  * Verify RILSystemMessenger.notifyNewCall()
  */
 add_test(function test_telephony_messenger_notify_new_call() {
@@ -104,8 +108,138 @@ add_test(function test_telephony_messeng
     duration: 500,
     direction: "outgoing",
     hangUpLocal: false,
     secondNumber: "+1234567890"
   });
 
   run_next_test();
 });
+
+/**
+ * Verify RILSystemMessenger.notifySms()
+ */
+add_test(function test_sms_messenger_notify_sms() {
+  let messenger = newRILSystemMessenger();
+  let timestamp = Date.now();
+  let sentTimestamp = timestamp + 100;
+  let deliveryTimestamp = sentTimestamp + 100;
+
+  // Verify 'sms-received' system message.
+  messenger.notifySms(Ci.nsISmsMessenger.NOTIFICATION_TYPE_RECEIVED,
+                      1,
+                      2,
+                      "99887766554433221100",
+                      Ci.nsISmsService.DELIVERY_TYPE_RECEIVED,
+                      Ci.nsISmsService.DELIVERY_STATUS_TYPE_SUCCESS,
+                      "+0987654321",
+                      null,
+                      "Incoming message",
+                      Ci.nsISmsService.MESSAGE_CLASS_TYPE_CLASS_2,
+                      timestamp,
+                      sentTimestamp,
+                      0,
+                      false);
+
+  equal_received_system_message("sms-received", {
+      iccId:             "99887766554433221100",
+      type:              "sms",
+      id:                1,
+      threadId:          2,
+      delivery:          "received",
+      deliveryStatus:    "success",
+      sender:            "+0987654321",
+      receiver:          null,
+      body:              "Incoming message",
+      messageClass:      "class-2",
+      timestamp:         timestamp,
+      sentTimestamp:     sentTimestamp,
+      deliveryTimestamp: 0,
+      read:              false
+    });
+
+  // Verify 'sms-sent' system message.
+  messenger.notifySms(Ci.nsISmsMessenger.NOTIFICATION_TYPE_SENT,
+                      3,
+                      4,
+                      "99887766554433221100",
+                      Ci.nsISmsService.DELIVERY_TYPE_SENT,
+                      Ci.nsISmsService.DELIVERY_STATUS_TYPE_PENDING,
+                      null,
+                      "+0987654321",
+                      "Outgoing message",
+                      Ci.nsISmsService.MESSAGE_CLASS_TYPE_NORMAL,
+                      timestamp,
+                      0,
+                      0,
+                      true);
+
+  equal_received_system_message("sms-sent", {
+      iccId:             "99887766554433221100",
+      type:              "sms",
+      id:                3,
+      threadId:          4,
+      delivery:          "sent",
+      deliveryStatus:    "pending",
+      sender:            null,
+      receiver:          "+0987654321",
+      body:              "Outgoing message",
+      messageClass:      "normal",
+      timestamp:         timestamp,
+      sentTimestamp:     0,
+      deliveryTimestamp: 0,
+      read:              true
+    });
+
+  // Verify 'sms-delivery-success' system message.
+  messenger.notifySms(Ci.nsISmsMessenger.NOTIFICATION_TYPE_DELIVERY_SUCCESS,
+                      5,
+                      6,
+                      "99887766554433221100",
+                      Ci.nsISmsService.DELIVERY_TYPE_SENT,
+                      Ci.nsISmsService.DELIVERY_STATUS_TYPE_SUCCESS,
+                      null,
+                      "+0987654321",
+                      "Outgoing message",
+                      Ci.nsISmsService.MESSAGE_CLASS_TYPE_NORMAL,
+                      timestamp,
+                      0,
+                      deliveryTimestamp,
+                      true);
+
+  equal_received_system_message("sms-delivery-success", {
+      iccId:             "99887766554433221100",
+      type:              "sms",
+      id:                5,
+      threadId:          6,
+      delivery:          "sent",
+      deliveryStatus:    "success",
+      sender:            null,
+      receiver:          "+0987654321",
+      body:              "Outgoing message",
+      messageClass:      "normal",
+      timestamp:         timestamp,
+      sentTimestamp:     0,
+      deliveryTimestamp: deliveryTimestamp,
+      read:              true
+    });
+
+  // Verify the protection of invalid nsISmsMessenger.NOTIFICATION_TYPEs.
+  try {
+    messenger.notifySms(3,
+                        1,
+                        2,
+                        "99887766554433221100",
+                        Ci.nsISmsService.DELIVERY_TYPE_RECEIVED,
+                        Ci.nsISmsService.DELIVERY_STATUS_TYPE_SUCCESS,
+                        "+0987654321",
+                        null,
+                        "Incoming message",
+                        Ci.nsISmsService.MESSAGE_CLASS_TYPE_NORMAL,
+                        timestamp,
+                        sentTimestamp,
+                        0,
+                        false);
+    ok(false, "Failed to verify the protection of invalid nsISmsMessenger.NOTIFICATION_TYPE!");
+  } catch (e) {}
+
+  run_next_test();
+});