From 5ea13833739a035bda3bed421124804d3822ff59 Mon Sep 17 00:00:00 2001 From: Bevis Tseng Date: Fri, 24 Oct 2014 11:33:01 +0800 Subject: [PATCH] Bug 1072808 - Part 2: Add SmsMessenger as a Wrapper for Sms-Related System Messages. r=echen --- dom/mobilemessage/interfaces/moz.build | 1 + .../interfaces/nsISmsMessenger.idl | 69 +++++++++ .../interfaces/nsISmsService.idl | 28 +++- dom/system/gonk/RILSystemMessenger.jsm | 58 ++++++++ dom/system/gonk/RILSystemMessengerHelper.js | 14 +- dom/system/gonk/RadioInterfaceLayer.js | 92 +++++++++--- .../gonk/tests/test_ril_system_messenger.js | 134 ++++++++++++++++++ 7 files changed, 373 insertions(+), 23 deletions(-) create mode 100644 dom/mobilemessage/interfaces/nsISmsMessenger.idl diff --git a/dom/mobilemessage/interfaces/moz.build b/dom/mobilemessage/interfaces/moz.build index e35f078b6df0..dc35b6db0357 100644 --- a/dom/mobilemessage/interfaces/moz.build +++ b/dom/mobilemessage/interfaces/moz.build @@ -21,6 +21,7 @@ XPIDL_SOURCES += [ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk' and CONFIG['MOZ_B2G_RIL']: XPIDL_SOURCES += [ 'nsIRilMobileMessageDatabaseService.idl', + 'nsISmsMessenger.idl', ] XPIDL_MODULE = 'dom_mobilemessage' diff --git a/dom/mobilemessage/interfaces/nsISmsMessenger.idl b/dom/mobilemessage/interfaces/nsISmsMessenger.idl new file mode 100644 index 000000000000..ace020b24957 --- /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); +}; diff --git a/dom/mobilemessage/interfaces/nsISmsService.idl b/dom/mobilemessage/interfaces/nsISmsService.idl index 9bf7f2bfbee3..27615018d581 100644 --- a/dom/mobilemessage/interfaces/nsISmsService.idl +++ b/dom/mobilemessage/interfaces/nsISmsService.idl @@ -12,9 +12,35 @@ interface nsIMobileMessageCallback; #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, diff --git a/dom/system/gonk/RILSystemMessenger.jsm b/dom/system/gonk/RILSystemMessenger.jsm index a74e67e990c1..0725ffebbefc 100644 --- a/dom/system/gonk/RILSystemMessenger.jsm +++ b/dom/system/gonk/RILSystemMessenger.jsm @@ -4,6 +4,16 @@ "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 */ @@ -48,6 +58,54 @@ RILSystemMessenger.prototype = { } 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 + }); } }; diff --git a/dom/system/gonk/RILSystemMessengerHelper.js b/dom/system/gonk/RILSystemMessengerHelper.js index 678ace9cde73..65dfe7b4d19d 100644 --- a/dom/system/gonk/RILSystemMessengerHelper.js +++ b/dom/system/gonk/RILSystemMessengerHelper.js @@ -49,7 +49,8 @@ function RILSystemMessengerHelper() { RILSystemMessengerHelper.prototype = { classID: RILSYSTEMMESSENGERHELPER_CID, - QueryInterface: XPCOMUtils.generateQI([Ci.nsITelephonyMessenger]), + QueryInterface: XPCOMUtils.generateQI([Ci.nsITelephonyMessenger, + Ci.nsISmsMessenger]), /** * RILSystemMessenger instance. @@ -67,6 +68,17 @@ RILSystemMessengerHelper.prototype = { 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); } }; diff --git a/dom/system/gonk/RadioInterfaceLayer.js b/dom/system/gonk/RadioInterfaceLayer.js index b806da1799ec..2044b1ab3275 100644 --- a/dom/system/gonk/RadioInterfaceLayer.js +++ b/dom/system/gonk/RadioInterfaceLayer.js @@ -187,6 +187,10 @@ 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); @@ -2171,6 +2175,42 @@ RadioInterface.prototype = { 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. @@ -2180,28 +2220,35 @@ RadioInterface.prototype = { * @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 @@ -2546,7 +2593,8 @@ RadioInterface.prototype = { return; } - this.broadcastSmsSystemMessage(kSmsReceivedObserverTopic, domMessage); + this.broadcastSmsSystemMessage( + Ci.nsISmsMessenger.NOTIFICATION_TYPE_RECEIVED, domMessage); Services.obs.notifyObservers(domMessage, kSmsReceivedObserverTopic, null); }.bind(this); @@ -3663,7 +3711,8 @@ RadioInterface.prototype = { // 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. @@ -3711,7 +3760,8 @@ RadioInterface.prototype = { 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)); diff --git a/dom/system/gonk/tests/test_ril_system_messenger.js b/dom/system/gonk/tests/test_ril_system_messenger.js index 6f71c1bd1a7a..7995a10e38d1 100644 --- a/dom/system/gonk/tests/test_ril_system_messenger.js +++ b/dom/system/gonk/tests/test_ril_system_messenger.js @@ -48,7 +48,11 @@ 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(); } @@ -109,3 +113,133 @@ add_test(function test_telephony_messenger_notify_call_ended() { 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(); +});