Bug 1072808 - Part 2: Add SmsMessenger as a Wrapper for Sms-Related System Messages. r=echen
authorBevis Tseng <btseng@mozilla.com>
Fri, 24 Oct 2014 11:33:01 +0800
changeset 233590 f69c551148903c638888a890452df7d464a97971
parent 233589 10ef609563a76c56a0f7e59d5eb47da7148d3485
child 233591 a9546493e532f7037de5de08b571b3107cb43489
push id7326
push userbhearsum@mozilla.com
push dateFri, 28 Nov 2014 15:58:42 +0000
treeherdermozilla-aurora@d3a3b2a0f2f8 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersechen
bugs1072808
milestone36.0a1
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();
+});