Bug 873351 - Part 3: Refactor SMS Notifications from RadioInterfaceLayer to SmsService. r=echen

This commit is contained in:
Bevis Tseng 2014-11-27 18:59:06 +08:00
parent 75a73fbbfd
commit 4a672075ae
7 changed files with 618 additions and 627 deletions

View File

@ -50,14 +50,6 @@ SmsService::Send(uint32_t aServiceId,
return NS_OK;
}
NS_IMETHODIMP
SmsService::IsSilentNumber(const nsAString& aNumber,
bool* aIsSilent)
{
NS_NOTYETIMPLEMENTED("Implement me!");
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
SmsService::AddSilentNumber(const nsAString& aNumber)
{

View File

@ -2968,11 +2968,11 @@ MobileMessageDB.prototype = {
// save it into the segmentRecord.
if (aSmsSegment.teleservice === RIL.PDU_CDMA_MSG_TELESERIVCIE_ID_WAP
&& seq === 1) {
if (aSmsSegment.originatorPort) {
if (aSmsSegment.originatorPort === Ci.nsIGonkSmsService.SMS_APPLICATION_PORT_INVALID) {
segmentRecord.originatorPort = aSmsSegment.originatorPort;
}
if (aSmsSegment.destinationPort) {
if (aSmsSegment.destinationPort === Ci.nsIGonkSmsService.SMS_APPLICATION_PORT_INVALID) {
segmentRecord.destinationPort = aSmsSegment.destinationPort;
}
}

View File

@ -35,6 +35,8 @@ const DOM_MOBILE_MESSAGE_DELIVERY_SENDING = "sending";
const DOM_MOBILE_MESSAGE_DELIVERY_SENT = "sent";
const DOM_MOBILE_MESSAGE_DELIVERY_ERROR = "error";
const SMS_HANDLED_WAKELOCK_TIMEOUT = 5000;
XPCOMUtils.defineLazyGetter(this, "gRadioInterfaces", function() {
let ril = Cc["@mozilla.org/ril;1"].getService(Ci.nsIRadioInterfaceLayer);
@ -57,6 +59,16 @@ XPCOMUtils.defineLazyGetter(this, "gPhoneNumberUtils", function() {
return ns.PhoneNumberUtils;
});
XPCOMUtils.defineLazyGetter(this, "gWAP", function() {
let ns = {};
Cu.import("resource://gre/modules/WapPushManager.js", ns);
return ns;
});
XPCOMUtils.defineLazyServiceGetter(this, "gCellBroadcastService",
"@mozilla.org/cellbroadcast/gonkservice;1",
"nsIGonkCellBroadcastService");
XPCOMUtils.defineLazyServiceGetter(this, "gMobileConnectionService",
"@mozilla.org/mobileconnection/mobileconnectionservice;1",
"nsIMobileConnectionService");
@ -69,6 +81,10 @@ XPCOMUtils.defineLazyServiceGetter(this, "gMobileMessageService",
"@mozilla.org/mobilemessage/mobilemessageservice;1",
"nsIMobileMessageService");
XPCOMUtils.defineLazyServiceGetter(this, "gPowerManagerService",
"@mozilla.org/power/powermanagerservice;1",
"nsIPowerManagerService");
XPCOMUtils.defineLazyServiceGetter(this, "gSmsMessenger",
"@mozilla.org/ril/system-messenger-helper;1",
"nsISmsMessenger");
@ -82,6 +98,11 @@ function SmsService() {
this._silentNumbers = [];
this.smsDefaultServiceId = this._getDefaultServiceId();
this._portAddressedSmsApps = {};
this._portAddressedSmsApps[gWAP.WDP_PORT_PUSH] = this._handleSmsWdpPortPush.bind(this);
this._receivedSmsSegmentsMap = {};
Services.prefs.addObserver(kPrefRilDebuggingEnabled, this, false);
Services.prefs.addObserver(kPrefDefaultServiceId, this, false);
Services.obs.addObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false);
@ -151,6 +172,43 @@ SmsService.prototype = {
return iccInfo.iccid;
},
// 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,
_acquireSmsHandledWakeLock: function() {
if (!this._smsHandledWakeLock) {
if (DEBUG) debug("Acquiring a CPU wake lock for handling SMS.");
this._smsHandledWakeLock = gPowerManagerService.newWakeLock("cpu");
}
if (!this._smsHandledWakeLockTimer) {
if (DEBUG) debug("Creating a timer for releasing the CPU wake lock.");
this._smsHandledWakeLockTimer =
Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
}
if (DEBUG) debug("Setting the timer for releasing the CPU wake lock.");
this._smsHandledWakeLockTimer
.initWithCallback(this._releaseSmsHandledWakeLock.bind(this),
SMS_HANDLED_WAKELOCK_TIMEOUT,
Ci.nsITimer.TYPE_ONE_SHOT);
},
_releaseSmsHandledWakeLock: function() {
if (DEBUG) debug("Releasing the CPU wake lock for handling SMS.");
if (this._smsHandledWakeLockTimer) {
this._smsHandledWakeLockTimer.cancel();
}
if (this._smsHandledWakeLock) {
this._smsHandledWakeLock.unlock();
this._smsHandledWakeLock = null;
}
},
_convertSmsMessageClassToString: function(aMessageClass) {
return RIL.GECKO_SMS_MESSAGE_CLASSES[aMessageClass] || null;
},
_convertSmsMessageClass: function(aMessageClass) {
let index = RIL.GECKO_SMS_MESSAGE_CLASSES.indexOf(aMessageClass);
@ -362,6 +420,347 @@ SmsService.prototype = {
}
},
/**
* Helper for processing received multipart SMS.
*
* @return null for handled segments, and an object containing full message
* body/data once all segments are received.
*
* |_receivedSmsSegmentsMap|:
* Hash map for received multipart sms fragments. Messages are hashed with
* its sender address and concatenation reference number. Three additional
* attributes `segmentMaxSeq`, `receivedSegments`, `segments` are inserted.
*/
_receivedSmsSegmentsMap: null,
_processReceivedSmsSegment: function(aSegment) {
// Directly replace full message body for single SMS.
if (!(aSegment.segmentMaxSeq && (aSegment.segmentMaxSeq > 1))) {
if (aSegment.encoding == Ci.nsIGonkSmsService.SMS_MESSAGE_ENCODING_8BITS_ALPHABET) {
aSegment.fullData = aSegment.data;
} else {
aSegment.fullBody = aSegment.body;
}
return aSegment;
}
// Handle Concatenation for Class 0 SMS
let hash = aSegment.sender + ":" +
aSegment.segmentRef + ":" +
aSegment.segmentMaxSeq;
let seq = aSegment.segmentSeq;
let options = this._receivedSmsSegmentsMap[hash];
if (!options) {
options = aSegment;
this._receivedSmsSegmentsMap[hash] = options;
options.receivedSegments = 0;
options.segments = [];
} else if (options.segments[seq]) {
// Duplicated segment?
if (DEBUG) {
debug("Got duplicated segment no." + seq +
" of a multipart SMS: " + JSON.stringify(aSegment));
}
return null;
}
if (options.receivedSegments > 0) {
// Update received timestamp.
options.timestamp = aSegment.timestamp;
}
if (options.encoding == Ci.nsIGonkSmsService.SMS_MESSAGE_ENCODING_8BITS_ALPHABET) {
options.segments[seq] = aSegment.data;
} else {
options.segments[seq] = aSegment.body;
}
options.receivedSegments++;
// The port information is only available in 1st segment for CDMA WAP Push.
// If the segments of a WAP Push are not received in sequence
// (e.g., SMS with seq == 1 is not the 1st segment received by the device),
// we have to retrieve the port information from 1st segment and
// save it into the cached options.
if (aSegment.teleservice === RIL.PDU_CDMA_MSG_TELESERIVCIE_ID_WAP
&& seq === 1) {
if (options.originatorPort === Ci.nsIGonkSmsService.SMS_APPLICATION_PORT_INVALID
&& aSegment.originatorPort !== Ci.nsIGonkSmsService.SMS_APPLICATION_PORT_INVALID) {
options.originatorPort = aSegment.originatorPort;
}
if (options.destinationPort === Ci.nsIGonkSmsService.SMS_APPLICATION_PORT_INVALID
&& aSegment.destinationPort !== Ci.nsIGonkSmsService.SMS_APPLICATION_PORT_INVALID) {
options.destinationPort = aSegment.destinationPort;
}
}
if (options.receivedSegments < options.segmentMaxSeq) {
if (DEBUG) {
debug("Got segment no." + seq + " of a multipart SMS: " +
JSON.stringify(options));
}
return null;
}
// Remove from map
delete this._receivedSmsSegmentsMap[hash];
// Rebuild full body
if (options.encoding == Ci.nsIGonkSmsService.SMS_MESSAGE_ENCODING_8BITS_ALPHABET) {
// Uint8Array doesn't have `concat`, so we have to merge all segements
// by hand.
let fullDataLen = 0;
for (let i = 1; i <= options.segmentMaxSeq; i++) {
fullDataLen += options.segments[i].length;
}
options.fullData = new Uint8Array(fullDataLen);
for (let d= 0, i = 1; i <= options.segmentMaxSeq; i++) {
let data = options.segments[i];
for (let j = 0; j < data.length; j++) {
options.fullData[d++] = data[j];
}
}
} else {
options.fullBody = options.segments.join("");
}
// Remove handy fields after completing the concatenation.
delete options.receivedSegments;
delete options.segments;
if (DEBUG) {
debug("Got full multipart SMS: " + JSON.stringify(options));
}
return options;
},
/**
* Helper to purge complete message.
*
* We remove unnessary fields after completing the concatenation.
*/
_purgeCompleteSmsMessage: function(aMessage) {
// Purge concatenation info
delete aMessage.segmentRef;
delete aMessage.segmentSeq;
delete aMessage.segmentMaxSeq;
// Purge partial message body
delete aMessage.data;
delete aMessage.body;
},
/**
* Handle WDP port push PDU. Constructor WDP bearer information and deliver
* to WapPushManager.
*
* @param aMessage
* A SMS message.
*/
_handleSmsWdpPortPush: function(aMessage, aServiceId) {
if (aMessage.encoding != Ci.nsIGonkSmsService.SMS_MESSAGE_ENCODING_8BITS_ALPHABET) {
if (DEBUG) {
debug("Got port addressed SMS but not encoded in 8-bit alphabet." +
" Drop!");
}
return;
}
let options = {
bearer: gWAP.WDP_BEARER_GSM_SMS_GSM_MSISDN,
sourceAddress: aMessage.sender,
sourcePort: aMessage.originatorPort,
destinationAddress: this._getPhoneNumber(aServiceId),
destinationPort: aMessage.destinationPort,
serviceId: aServiceId
};
gWAP.WapPushManager.receiveWdpPDU(aMessage.fullData, aMessage.fullData.length,
0, options);
},
_handleCellbroadcastMessageReceived: function(aMessage, aServiceId) {
gCellBroadcastService
.notifyMessageReceived(aServiceId,
Ci.nsICellBroadcastService.GSM_GEOGRAPHICAL_SCOPE_INVALID,
aMessage.messageCode,
aMessage.messageId,
aMessage.language,
aMessage.fullBody,
Ci.nsICellBroadcastService.GSM_MESSAGE_CLASS_NORMAL,
Date.now(),
aMessage.serviceCategory,
false,
Ci.nsICellBroadcastService.GSM_ETWS_WARNING_INVALID,
false,
false);
},
_handleMwis: function(aMwi, aServiceId) {
let service = Cc["@mozilla.org/voicemail/voicemailservice;1"]
.getService(Ci.nsIGonkVoicemailService);
service.notifyStatusChanged(aServiceId, aMwi.active, aMwi.msgCount,
aMwi.returnNumber, aMwi.returnMessage);
gRadioInterfaces[aServiceId].sendWorkerMessage("updateMwis", { mwi: aMwi });
},
_portAddressedSmsApps: null,
_handleSmsReceived: function(aMessage, aServiceId) {
if (DEBUG) debug("_handleSmsReceived: " + JSON.stringify(aMessage));
if (aMessage.messageType == RIL.PDU_CDMA_MSG_TYPE_BROADCAST) {
this._handleCellbroadcastMessageReceived(aMessage, aServiceId);
return true;
}
// Dispatch to registered handler if application port addressing is
// available. Note that the destination port can possibly be zero when
// representing a UDP/TCP port.
if (aMessage.destinationPort !== Ci.nsIGonkSmsService.SMS_APPLICATION_PORT_INVALID) {
let handler = this._portAddressedSmsApps[aMessage.destinationPort];
if (handler) {
handler(aMessage, aServiceId);
}
return true;
}
if (aMessage.encoding == Ci.nsIGonkSmsService.SMS_MESSAGE_ENCODING_8BITS_ALPHABET) {
// Don't know how to handle binary data yet.
return true;
}
aMessage.type = "sms";
aMessage.sender = aMessage.sender || null;
aMessage.receiver = this._getPhoneNumber(aServiceId);
aMessage.body = aMessage.fullBody = aMessage.fullBody || null;
if (this._isSilentNumber(aMessage.sender)) {
aMessage.id = -1;
aMessage.threadId = 0;
aMessage.delivery = DOM_MOBILE_MESSAGE_DELIVERY_RECEIVED;
aMessage.deliveryStatus = RIL.GECKO_SMS_DELIVERY_STATUS_SUCCESS;
aMessage.read = false;
let domMessage =
gMobileMessageService.createSmsMessage(aMessage.id,
aMessage.threadId,
aMessage.iccId,
aMessage.delivery,
aMessage.deliveryStatus,
aMessage.sender,
aMessage.receiver,
aMessage.body,
aMessage.messageClass,
aMessage.timestamp,
aMessage.sentTimestamp,
0,
aMessage.read);
Services.obs.notifyObservers(domMessage,
kSilentSmsReceivedObserverTopic,
null);
return true;
}
if (aMessage.mwiPresent) {
let mwi = {
discard: aMessage.mwiDiscard,
msgCount: aMessage.mwiMsgCount,
active: aMessage.mwiActive,
returnNumber: aMessage.sender || null,
returnMessage: aMessage.fullBody || null
};
this._handleMwis(mwi, aServiceId);
// Dicarded MWI comes without text body.
// Hence, we discard it here after notifying the MWI status.
if (aMessage.mwiDiscard) {
return true;
}
}
let notifyReceived = (aRv, aDomMessage) => {
let success = Components.isSuccessCode(aRv);
this._sendAckSms(aRv, aMessage, aServiceId);
if (!success) {
// 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) {
debug("Could not store SMS, error code " + aRv);
}
return;
}
this._broadcastSmsSystemMessage(
Ci.nsISmsMessenger.NOTIFICATION_TYPE_RECEIVED, aDomMessage);
Services.obs.notifyObservers(aDomMessage, kSmsReceivedObserverTopic, null);
};
if (aMessage.messageClass != RIL.GECKO_SMS_MESSAGE_CLASSES[RIL.PDU_DCS_MSG_CLASS_0]) {
gMobileMessageDatabaseService.saveReceivedMessage(aMessage,
notifyReceived);
} else {
aMessage.id = -1;
aMessage.threadId = 0;
aMessage.delivery = DOM_MOBILE_MESSAGE_DELIVERY_RECEIVED;
aMessage.deliveryStatus = RIL.GECKO_SMS_DELIVERY_STATUS_SUCCESS;
aMessage.read = false;
let domMessage =
gMobileMessageService.createSmsMessage(aMessage.id,
aMessage.threadId,
aMessage.iccId,
aMessage.delivery,
aMessage.deliveryStatus,
aMessage.sender,
aMessage.receiver,
aMessage.body,
aMessage.messageClass,
aMessage.timestamp,
aMessage.sentTimestamp,
0,
aMessage.read);
notifyReceived(Cr.NS_OK, domMessage);
}
// SMS ACK will be sent in notifyReceived. Return false here.
return false;
},
/**
* Handle ACK response of received SMS.
*/
_sendAckSms: function(aRv, aMessage, aServiceId) {
if (aMessage.messageClass === RIL.GECKO_SMS_MESSAGE_CLASSES[RIL.PDU_DCS_MSG_CLASS_2]) {
return;
}
let result = RIL.PDU_FCS_OK;
if (!Components.isSuccessCode(aRv)) {
if (DEBUG) debug("Failed to handle received sms: " + aRv);
result = (aRv === Cr.NS_ERROR_FILE_NO_DEVICE_SPACE)
? RIL.PDU_FCS_MEMORY_CAPACITY_EXCEEDED
: RIL.PDU_FCS_UNSPECIFIED;
}
gRadioInterfaces[aServiceId]
.sendWorkerMessage("ackSMS", { result: result });
},
// An array of slient numbers.
_silentNumbers: null,
_isSilentNumber: function(aNumber) {
return this._silentNumbers.indexOf(aNumber) >= 0;
},
/**
* nsISmsService interface
*/
@ -507,14 +906,8 @@ SmsService.prototype = {
sendingMessage, saveSendingMessageCallback);
},
// An array of slient numbers.
_silentNumbers: null,
isSilentNumber: function(aNumber) {
return this._silentNumbers.indexOf(aNumber) >= 0;
},
addSilentNumber: function(aNumber) {
if (this.isSilentNumber(aNumber)) {
if (this._isSilentNumber(aNumber)) {
throw Cr.NS_ERROR_UNEXPECTED;
}
@ -548,8 +941,80 @@ SmsService.prototype = {
},
/**
* TODO: nsIGonkSmsService interface
* nsIGonkSmsService interface
*/
notifyMessageReceived: function(aServiceId, aSMSC, aSentTimestamp,
aSender, aPid, aEncoding, aMessageClass,
aLanguage, aSegmentRef, aSegmentSeq,
aSegmentMaxSeq, aOriginatorPort,
aDestinationPort, aMwiPresent, aMwiDiscard,
aMwiMsgCount, aMwiActive, aCdmaMessageType,
aCdmaTeleservice, aCdmaServiceCategory,
aBody, aData, aDataLength) {
this._acquireSmsHandledWakeLock();
let segment = {};
segment.iccId = this._getIccId(aServiceId);
segment.SMSC = aSMSC;
segment.sentTimestamp = aSentTimestamp;
segment.timestamp = Date.now();
segment.sender = aSender;
segment.pid = aPid;
segment.encoding = aEncoding;
segment.messageClass = this._convertSmsMessageClassToString(aMessageClass);
segment.language = aLanguage;
segment.segmentRef = aSegmentRef;
segment.segmentSeq = aSegmentSeq;
segment.segmentMaxSeq = aSegmentMaxSeq;
segment.originatorPort = aOriginatorPort;
segment.destinationPort = aDestinationPort;
segment.mwiPresent = aMwiPresent;
segment.mwiDiscard = aMwiDiscard;
segment.mwiMsgCount = aMwiMsgCount;
segment.mwiActive = aMwiActive;
segment.messageType = aCdmaMessageType;
segment.teleservice = aCdmaTeleservice;
segment.serviceCategory = aCdmaServiceCategory;
segment.body = aBody;
segment.data = (aData && aDataLength > 0) ? aData : null;
let isMultipart = (segment.segmentMaxSeq && (segment.segmentMaxSeq > 1));
let messageClass = segment.messageClass;
let handleReceivedAndAck = (aRvOfIncompleteMsg, aCompleteMessage) => {
if (aCompleteMessage) {
this._purgeCompleteSmsMessage(aCompleteMessage);
if (this._handleSmsReceived(aCompleteMessage, aServiceId)) {
this._sendAckSms(Cr.NS_OK, aCompleteMessage, aServiceId);
}
// else Ack will be sent after further process in _handleSmsReceived.
} else {
this._sendAckSms(aRvOfIncompleteMsg, segment, aServiceId);
}
};
// No need to access SmsSegmentStore for Class 0 SMS and Single SMS.
if (!isMultipart ||
(messageClass == RIL.GECKO_SMS_MESSAGE_CLASSES[RIL.PDU_DCS_MSG_CLASS_0])) {
// `When a mobile terminated message is class 0 and the MS has the
// capability of displaying short messages, the MS shall display the
// message immediately and send an acknowledgement to the SC when the
// message has successfully reached the MS irrespective of whether
// there is memory available in the (U)SIM or ME. The message shall
// not be automatically stored in the (U)SIM or ME.`
// ~ 3GPP 23.038 clause 4
handleReceivedAndAck(Cr.NS_OK, // ACK OK For Incomplete Class 0
this._processReceivedSmsSegment(segment));
} else {
gMobileMessageDatabaseService
.saveSmsSegment(segment, function notifyResult(aRv, aCompleteMessage) {
handleReceivedAndAck(aRv, // Ack according to the result after saving
aCompleteMessage);
});
}
},
/**
* nsIObserver interface.
@ -565,6 +1030,8 @@ SmsService.prototype = {
}
break;
case NS_XPCOM_SHUTDOWN_OBSERVER_ID:
// Release the CPU wake lock for handling the received SMS.
this._releaseSmsHandledWakeLock();
Services.prefs.removeObserver(kPrefRilDebuggingEnabled, this);
Services.prefs.removeObserver(kPrefDefaultServiceId, this);
Services.obs.removeObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID);

View File

@ -2,6 +2,7 @@
* 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 "nsISmsService.idl"
%{C++
@ -9,10 +10,86 @@
"@mozilla.org/sms/gonksmsservice;1"
%}
[scriptable, uuid(63fab75e-73b4-11e4-a10d-dbfa9d05a4f4)]
[scriptable, uuid(4dda515e-05ec-47b1-b750-e42c74576c43)]
interface nsIGonkSmsService : nsISmsService
{
const unsigned short SMS_MESSAGE_ENCODING_7BITS_ALPHABET = 0x00;
const unsigned short SMS_MESSAGE_ENCODING_8BITS_ALPHABET = 0x04;
const unsigned short SMS_MESSAGE_ENCODING_16BITS_ALPHABET = 0x08;
const unsigned long SMS_APPLICATION_PORT_INVALID = 0xFFFFFFFF;
/**
* TODO: define callback to receive message from the network.
* Called when a short message has been received by the network.
*
* @param aServiceId
* The ID of the service where this message is received from.
* @param aSMSC
* SMS Center address.
* @param aSentTimestamp
* The time stamp when message is arrived to SMSC.
* @param aSender
* The sender's address of this message.
* @param aPid
* Protocol Identifier, See TS 23.040, subcluase 9.2.3.9.
* Set to 0 if invalid.
* @param aEncoding
* The encoding of message body.
* SMS_MESSAGE_ENCODING_*.
* @param aMessageClass
* A predefined constant of nsISmsService.MESSAGE_CLASS_TYPE_*.
* @param aLanguage
* ISO-639-1 language code for this message. Null if unspecified.
* @param aSegmentRef, aSegmentSeq, aSegmentMaxSeq
* Concatenation info. See TS 23.040, subclause 9.2.3.24.1.
* All set to 1 if no need for concatenatenation.
* @param aOriginatorPort, aDestinationPort
* Application Port Addressing. See TS 23.040 subclause 9.2.3.24.3~4.
* All set to 1 if no need for concatenatenation.
* @param aMwiPresent
* True if MWI is presented in this message.
* @param aMwiDiscard
* True if MWI has to be discarded after received.
* @param aMwiMsgCount
* The number of messages waiting in the voicemail server.
* -1 if number is unknown from the decoded MWI.
* @param aMwiActive
* True if there are messages waiting in the voicemail server.
* @param aCdmaMessageType
* CDMA SMS Message Type, as defined in 3GPP2 C.S0015-A v2.0, Table 3.4-1
* Set to 0 if invalid.
* @param aCdmaTeleservice
* SMS Teleservice Identitifier, as defined in 3GPP2 N.S0005, Table 175.
* Set to 0 if invalid.
* @param aCdmaServiceCategory
* CDMA Service Category, 3GPP2 C.R1001-D v2.0, 9.3 Service Category.
* Set to 0 if invalid.
* @param aBody
* Text message body.
* @param aData
* Binary message body.
*/
};
void notifyMessageReceived(in unsigned long aServiceId,
in DOMString aSMSC,
in DOMTimeStamp aSentTimestamp,
in DOMString aSender,
in unsigned short aPid,
in unsigned short aEncoding,
in unsigned long aMessageClass,
in DOMString aLanguage,
in unsigned short aSegmentRef,
in unsigned short aSegmentSeq,
in unsigned short aSegmentMaxSeq,
in unsigned long aOriginatorPort,
in unsigned long aDestinationPort,
in boolean aMwiPresent,
in boolean aMwiDiscard,
in short aMwiMsgCount,
in boolean aMwiActive,
in unsigned short aCdmaMessageType,
in unsigned long aCdmaTeleservice,
in unsigned long aCdmaServiceCategory,
in DOMString aBody,
[array, size_is(aDataLength)] in octet aData,
in uint32_t aDataLength);
};

View File

@ -12,7 +12,7 @@ interface nsIMobileMessageCallback;
#define SMS_SERVICE_CONTRACTID "@mozilla.org/sms/smsservice;1"
%}
[scriptable, uuid(31626940-73b4-11e4-8b03-1724e1d8a6a1)]
[scriptable, uuid(ae688bca-00c9-4d08-945d-e8a5272ad5b1)]
interface nsISmsService : nsISupports
{
/**
@ -52,7 +52,6 @@ interface nsISmsService : nsISupports
in boolean silent,
in nsIMobileMessageCallback request);
boolean isSilentNumber(in DOMString number);
void addSilentNumber(in DOMString number);
void removeSilentNumber(in DOMString number);

View File

@ -193,14 +193,6 @@ SmsIPCService::Send(uint32_t aServiceId,
aRequest);
}
NS_IMETHODIMP
SmsIPCService::IsSilentNumber(const nsAString& aNumber,
bool* aIsSilent)
{
NS_ERROR("We should not be here!");
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP
SmsIPCService::AddSilentNumber(const nsAString& aNumber)
{

View File

@ -56,13 +56,6 @@ const RILNETWORKINTERFACE_CID =
const NS_XPCOM_SHUTDOWN_OBSERVER_ID = "xpcom-shutdown";
const kNetworkConnStateChangedTopic = "network-connection-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";
@ -78,13 +71,7 @@ const NS_PREFBRANCH_PREFCHANGE_TOPIC_ID = "nsPref:changed";
const kPrefRilNumRadioInterfaces = "ril.numRadioInterfaces";
const kPrefRilDebuggingEnabled = "ril.debugging.enabled";
const DOM_MOBILE_MESSAGE_DELIVERY_RECEIVED = "received";
const DOM_MOBILE_MESSAGE_DELIVERY_SENDING = "sending";
const DOM_MOBILE_MESSAGE_DELIVERY_SENT = "sent";
const DOM_MOBILE_MESSAGE_DELIVERY_ERROR = "error";
const RADIO_POWER_OFF_TIMEOUT = 30000;
const SMS_HANDLED_WAKELOCK_TIMEOUT = 5000;
const HW_DEFAULT_CLIENT_ID = 0;
const INT32_MAX = 2147483647;
@ -136,10 +123,6 @@ function debug(s) {
dump("-*- RadioInterfaceLayer: " + s + "\n");
}
XPCOMUtils.defineLazyServiceGetter(this, "gPowerManagerService",
"@mozilla.org/power/powermanagerservice;1",
"nsIPowerManagerService");
XPCOMUtils.defineLazyServiceGetter(this, "gMobileMessageService",
"@mozilla.org/mobilemessage/mobilemessageservice;1",
"nsIMobileMessageService");
@ -148,10 +131,6 @@ XPCOMUtils.defineLazyServiceGetter(this, "gSmsService",
"@mozilla.org/sms/gonksmsservice;1",
"nsIGonkSmsService");
XPCOMUtils.defineLazyServiceGetter(this, "gMobileMessageDatabaseService",
"@mozilla.org/mobilemessage/rilmobilemessagedatabaseservice;1",
"nsIRilMobileMessageDatabaseService");
XPCOMUtils.defineLazyServiceGetter(this, "ppmm",
"@mozilla.org/parentprocessmessagemanager;1",
"nsIMessageBroadcaster");
@ -160,10 +139,6 @@ XPCOMUtils.defineLazyServiceGetter(this, "gSettingsService",
"@mozilla.org/settingsService;1",
"nsISettingsService");
XPCOMUtils.defineLazyServiceGetter(this, "gSystemMessenger",
"@mozilla.org/system-message-internal;1",
"nsISystemMessagesInternal");
XPCOMUtils.defineLazyServiceGetter(this, "gNetworkManager",
"@mozilla.org/network/manager;1",
"nsINetworkManager");
@ -188,10 +163,6 @@ XPCOMUtils.defineLazyServiceGetter(this, "gCellBroadcastService",
"@mozilla.org/cellbroadcast/gonkservice;1",
"nsIGonkCellBroadcastService");
XPCOMUtils.defineLazyServiceGetter(this, "gSmsMessenger",
"@mozilla.org/ril/system-messenger-helper;1",
"nsISmsMessenger");
XPCOMUtils.defineLazyServiceGetter(this, "gIccMessenger",
"@mozilla.org/ril/system-messenger-helper;1",
"nsIIccMessenger");
@ -202,12 +173,6 @@ XPCOMUtils.defineLazyGetter(this, "gStkCmdFactory", function() {
return stk.StkProactiveCmdFactory;
});
XPCOMUtils.defineLazyGetter(this, "WAP", function() {
let wap = {};
Cu.import("resource://gre/modules/WapPushManager.js", wap);
return wap;
});
XPCOMUtils.defineLazyGetter(this, "gMessageManager", function() {
return {
QueryInterface: XPCOMUtils.generateQI([Ci.nsIMessageListener,
@ -1740,11 +1705,6 @@ function RadioInterface(aClientId, aWorkerMessenger) {
Services.obs.addObserver(this, kNetworkConnStateChangedTopic, false);
this.portAddressedSmsApps = {};
this.portAddressedSmsApps[WAP.WDP_PORT_PUSH] = this.handleSmsWdpPortPush.bind(this);
this._receivedSmsSegmentsMap = {};
this._sntp = new Sntp(this.setClockBySntp.bind(this),
Services.prefs.getIntPref("network.sntp.maxRetryCount"),
Services.prefs.getIntPref("network.sntp.refreshPeriod"),
@ -1772,9 +1732,6 @@ RadioInterface.prototype = {
},
shutdown: function() {
// Release the CPU wake lock for handling the received SMS.
this._releaseSmsHandledWakeLock();
Services.obs.removeObserver(this, kMozSettingsChangedObserverTopic);
Services.obs.removeObserver(this, kSysClockChangeObserverTopic);
Services.obs.removeObserver(this, kScreenStateChangedTopic);
@ -1977,7 +1934,7 @@ RadioInterface.prototype = {
this.clientId, message);
break;
case "sms-received":
this.handleSmsMultipart(message);
this.handleSmsReceived(message);
break;
case "cellbroadcast-received":
this.handleCellbroadcastMessageReceived(message);
@ -2012,58 +1969,6 @@ RadioInterface.prototype = {
}
},
/**
* Get phone number from iccInfo.
*
* If the icc card is gsm card, the phone number is in msisdn.
* @see nsIGsmIccInfo
*
* Otherwise, the phone number is in mdn.
* @see nsICdmaIccInfo
*/
getPhoneNumber: function() {
let iccInfo = this.rilContext.iccInfo;
if (!iccInfo) {
return null;
}
// After moving SMS code out of RadioInterfaceLayer, we could use
// |iccInfo instanceof Ci.nsIGsmIccInfo| here.
// TODO: Bug 873351 - B2G SMS: move SMS code out of RadioInterfaceLayer to
// SmsService
let number = (iccInfo instanceof GsmIccInfo) ? iccInfo.msisdn : iccInfo.mdn;
// Workaround an xpconnect issue with undefined string objects.
// See bug 808220
if (number === undefined || number === "undefined") {
return null;
}
return number;
},
/**
* A utility function to get the ICC ID of the SIM card (if installed).
*/
getIccId: function() {
let iccInfo = this.rilContext.iccInfo;
if (!iccInfo) {
return null;
}
let iccId = iccInfo.iccid;
// Workaround an xpconnect issue with undefined string objects.
// See bug 808220
if (iccId === undefined || iccId === "undefined") {
return null;
}
return iccId;
},
// Matches the mvnoData pattern with imsi. Characters 'x' and 'X' are skipped
// and not compared. E.g., if the mvnoData passed is '310260x10xxxxxx',
// then the function returns true only if imsi has the same first 6 digits,
@ -2163,506 +2068,64 @@ RadioInterface.prototype = {
},
/**
* Handle WDP port push PDU. Constructor WDP bearer information and deliver
* to WapPushManager.
*
* @param message
* A SMS message.
* handle received SMS.
*/
handleSmsWdpPortPush: function(message) {
if (message.encoding != RIL.PDU_DCS_MSG_CODING_8BITS_ALPHABET) {
if (DEBUG) {
this.debug("Got port addressed SMS but not encoded in 8-bit alphabet." +
" Drop!");
}
return;
}
let options = {
bearer: WAP.WDP_BEARER_GSM_SMS_GSM_MSISDN,
sourceAddress: message.sender,
sourcePort: message.originatorPort,
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(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.
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,
_acquireSmsHandledWakeLock: function() {
if (!this._smsHandledWakeLock) {
if (DEBUG) this.debug("Acquiring a CPU wake lock for handling SMS.");
this._smsHandledWakeLock = gPowerManagerService.newWakeLock("cpu");
}
if (!this._smsHandledWakeLockTimer) {
if (DEBUG) this.debug("Creating a timer for releasing the CPU wake lock.");
this._smsHandledWakeLockTimer =
Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
}
if (DEBUG) this.debug("Setting the timer for releasing the CPU wake lock.");
this._smsHandledWakeLockTimer
.initWithCallback(this._releaseSmsHandledWakeLock.bind(this),
SMS_HANDLED_WAKELOCK_TIMEOUT,
Ci.nsITimer.TYPE_ONE_SHOT);
},
_releaseSmsHandledWakeLock: function() {
if (DEBUG) this.debug("Releasing the CPU wake lock for handling SMS.");
if (this._smsHandledWakeLockTimer) {
this._smsHandledWakeLockTimer.cancel();
}
if (this._smsHandledWakeLock) {
this._smsHandledWakeLock.unlock();
this._smsHandledWakeLock = null;
}
},
/**
* Hash map for received multipart sms fragments. Messages are hashed with
* its sender address and concatenation reference number. Three additional
* attributes `segmentMaxSeq`, `receivedSegments`, `segments` are inserted.
*/
_receivedSmsSegmentsMap: null,
/**
* Helper for processing received multipart SMS.
*
* @return null for handled segments, and an object containing full message
* body/data once all segments are received.
*/
_processReceivedSmsSegment: function(aSegment) {
// Directly replace full message body for single SMS.
if (!(aSegment.segmentMaxSeq && (aSegment.segmentMaxSeq > 1))) {
if (aSegment.encoding == RIL.PDU_DCS_MSG_CODING_8BITS_ALPHABET) {
aSegment.fullData = aSegment.data;
} else {
aSegment.fullBody = aSegment.body;
}
return aSegment;
}
// Handle Concatenation for Class 0 SMS
let hash = aSegment.sender + ":" +
aSegment.segmentRef + ":" +
aSegment.segmentMaxSeq;
let seq = aSegment.segmentSeq;
let options = this._receivedSmsSegmentsMap[hash];
if (!options) {
options = aSegment;
this._receivedSmsSegmentsMap[hash] = options;
options.receivedSegments = 0;
options.segments = [];
} else if (options.segments[seq]) {
// Duplicated segment?
if (DEBUG) {
this.debug("Got duplicated segment no." + seq +
" of a multipart SMS: " + JSON.stringify(aSegment));
}
return null;
}
if (options.receivedSegments > 0) {
// Update received timestamp.
options.timestamp = aSegment.timestamp;
}
if (options.encoding == RIL.PDU_DCS_MSG_CODING_8BITS_ALPHABET) {
options.segments[seq] = aSegment.data;
} else {
options.segments[seq] = aSegment.body;
}
options.receivedSegments++;
// The port information is only available in 1st segment for CDMA WAP Push.
// If the segments of a WAP Push are not received in sequence
// (e.g., SMS with seq == 1 is not the 1st segment received by the device),
// we have to retrieve the port information from 1st segment and
// save it into the cached options.
if (aSegment.teleservice === RIL.PDU_CDMA_MSG_TELESERIVCIE_ID_WAP
&& seq === 1) {
if (!options.originatorPort && aSegment.originatorPort) {
options.originatorPort = aSegment.originatorPort;
}
if (!options.destinationPort && aSegment.destinationPort) {
options.destinationPort = aSegment.destinationPort;
}
}
if (options.receivedSegments < options.segmentMaxSeq) {
if (DEBUG) {
this.debug("Got segment no." + seq + " of a multipart SMS: " +
JSON.stringify(options));
}
return null;
}
// Remove from map
delete this._receivedSmsSegmentsMap[hash];
// Rebuild full body
if (options.encoding == RIL.PDU_DCS_MSG_CODING_8BITS_ALPHABET) {
// Uint8Array doesn't have `concat`, so we have to merge all segements
// by hand.
let fullDataLen = 0;
for (let i = 1; i <= options.segmentMaxSeq; i++) {
fullDataLen += options.segments[i].length;
}
options.fullData = new Uint8Array(fullDataLen);
for (let d= 0, i = 1; i <= options.segmentMaxSeq; i++) {
let data = options.segments[i];
for (let j = 0; j < data.length; j++) {
options.fullData[d++] = data[j];
}
}
} else {
options.fullBody = options.segments.join("");
}
// Remove handy fields after completing the concatenation.
delete options.receivedSegments;
delete options.segments;
if (DEBUG) {
this.debug("Got full multipart SMS: " + JSON.stringify(options));
}
return options;
},
/**
* Helper to create Savable SmsSegment.
*/
_createSavableSmsSegment: function(aMessage) {
// We precisely define what data fields to be stored into
// DB here for better data migration.
let segment = {};
segment.messageType = aMessage.messageType;
segment.teleservice = aMessage.teleservice;
segment.SMSC = aMessage.SMSC;
segment.sentTimestamp = aMessage.sentTimestamp;
segment.timestamp = Date.now();
segment.sender = aMessage.sender;
segment.pid = aMessage.pid;
segment.encoding = aMessage.encoding;
segment.messageClass = aMessage.messageClass;
segment.iccId = this.getIccId();
if (aMessage.header) {
segment.segmentRef = aMessage.header.segmentRef;
segment.segmentSeq = aMessage.header.segmentSeq;
segment.segmentMaxSeq = aMessage.header.segmentMaxSeq;
segment.originatorPort = aMessage.header.originatorPort;
segment.destinationPort = aMessage.header.destinationPort;
}
segment.mwiPresent = (aMessage.mwi)? true: false;
segment.mwiDiscard = (segment.mwiPresent)? aMessage.mwi.discard: false;
segment.mwiMsgCount = (segment.mwiPresent)? aMessage.mwi.msgCount: 0;
segment.mwiActive = (segment.mwiPresent)? aMessage.mwi.active: false;
segment.serviceCategory = aMessage.serviceCategory;
segment.language = aMessage.language;
segment.data = aMessage.data;
segment.body = aMessage.body;
return segment;
},
/**
* Helper to purge complete message.
*
* We remove unnessary fields defined in _createSavableSmsSegment() after
* completing the concatenation.
*/
_purgeCompleteSmsMessage: function(aMessage) {
// Purge concatenation info
delete aMessage.segmentRef;
delete aMessage.segmentSeq;
delete aMessage.segmentMaxSeq;
// Purge partial message body
delete aMessage.data;
delete aMessage.body;
},
/**
* handle concatenation of received SMS.
*/
handleSmsMultipart: function(aMessage) {
if (DEBUG) this.debug("handleSmsMultipart: " + JSON.stringify(aMessage));
this._acquireSmsHandledWakeLock();
let segment = this._createSavableSmsSegment(aMessage);
let isMultipart = (segment.segmentMaxSeq && (segment.segmentMaxSeq > 1));
let messageClass = segment.messageClass;
let handleReceivedAndAck = function(aRvOfIncompleteMsg, aCompleteMessage) {
if (aCompleteMessage) {
this._purgeCompleteSmsMessage(aCompleteMessage);
if (this.handleSmsReceived(aCompleteMessage)) {
this.sendAckSms(Cr.NS_OK, aCompleteMessage);
}
// else Ack will be sent after further process in handleSmsReceived.
} else {
this.sendAckSms(aRvOfIncompleteMsg, segment);
}
}.bind(this);
// No need to access SmsSegmentStore for Class 0 SMS and Single SMS.
if (!isMultipart ||
(messageClass == RIL.GECKO_SMS_MESSAGE_CLASSES[RIL.PDU_DCS_MSG_CLASS_0])) {
// `When a mobile terminated message is class 0 and the MS has the
// capability of displaying short messages, the MS shall display the
// message immediately and send an acknowledgement to the SC when the
// message has successfully reached the MS irrespective of whether
// there is memory available in the (U)SIM or ME. The message shall
// not be automatically stored in the (U)SIM or ME.`
// ~ 3GPP 23.038 clause 4
handleReceivedAndAck(Cr.NS_OK, // ACK OK For Incomplete Class 0
this._processReceivedSmsSegment(segment));
} else {
gMobileMessageDatabaseService
.saveSmsSegment(segment, function notifyResult(aRv, aCompleteMessage) {
handleReceivedAndAck(aRv, // Ack according to the result after saving
aCompleteMessage);
});
}
},
portAddressedSmsApps: null,
handleSmsReceived: function(message) {
if (DEBUG) this.debug("handleSmsReceived: " + JSON.stringify(message));
if (message.messageType == RIL.PDU_CDMA_MSG_TYPE_BROADCAST) {
this.handleCellbroadcastMessageReceived(message);
return true;
}
// Dispatch to registered handler if application port addressing is
// available. Note that the destination port can possibly be zero when
// representing a UDP/TCP port.
if (message.destinationPort != null) {
let handler = this.portAddressedSmsApps[message.destinationPort];
if (handler) {
handler(message);
}
return true;
}
if (message.encoding == RIL.PDU_DCS_MSG_CODING_8BITS_ALPHABET) {
// Don't know how to handle binary data yet.
return true;
}
message.type = "sms";
message.sender = message.sender || null;
message.receiver = this.getPhoneNumber();
message.body = message.fullBody = message.fullBody || null;
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.iccId,
message.delivery,
message.deliveryStatus,
message.sender,
message.receiver,
message.body,
message.messageClass,
message.timestamp,
message.sentTimestamp,
0,
message.read);
Services.obs.notifyObservers(domMessage,
kSilentSmsReceivedObserverTopic,
null);
return true;
}
if (message.mwiPresent) {
let mwi = {
discard: message.mwiDiscard,
msgCount: message.mwiMsgCount,
active: message.mwiActive
};
this.workerMessenger.send("updateMwis", { mwi: mwi });
mwi.returnNumber = message.sender;
mwi.returnMessage = message.fullBody;
this.handleIccMwis(mwi);
// Dicarded MWI comes without text body.
// Hence, we discard it here after notifying the MWI status.
if (message.mwiDiscard) {
return true;
}
}
let notifyReceived = function notifyReceived(rv, domMessage) {
let success = Components.isSuccessCode(rv);
this.sendAckSms(rv, message);
if (!success) {
// 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(
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;
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.iccId,
message.delivery,
message.deliveryStatus,
message.sender,
message.receiver,
message.body,
message.messageClass,
message.timestamp,
message.sentTimestamp,
0,
message.read);
notifyReceived(Cr.NS_OK, domMessage);
}
// SMS ACK will be sent in notifyReceived. Return false here.
return false;
},
/**
* Handle ACK response of received SMS.
*/
sendAckSms: function(aRv, aMessage) {
if (aMessage.messageClass === RIL.GECKO_SMS_MESSAGE_CLASSES[RIL.PDU_DCS_MSG_CLASS_2]) {
return;
}
let result = RIL.PDU_FCS_OK;
if (!Components.isSuccessCode(aRv)) {
if (DEBUG) this.debug("Failed to handle received sms: " + aRv);
result = (aRv === Cr.NS_ERROR_FILE_NO_DEVICE_SPACE)
? RIL.PDU_FCS_MEMORY_CAPACITY_EXCEEDED
: RIL.PDU_FCS_UNSPECIFIED;
}
this.workerMessenger.send("ackSMS", { result: result });
handleSmsReceived: function(aMessage) {
let header = aMessage.header;
// Concatenation Info:
// - segmentRef: a modulo 256 counter indicating the reference number for a
// particular concatenated short message. '0' is a valid number.
// - The concatenation info will not be available in |header| if
// segmentSeq or segmentMaxSeq is 0.
// See 3GPP TS 23.040, 9.2.3.24.1 Concatenated Short Messages.
let segmentRef = (header && header.segmentRef !== undefined)
? header.segmentRef : 1;
let segmentSeq = header && header.segmentSeq || 1;
let segmentMaxSeq = header && header.segmentMaxSeq || 1;
// Application Ports:
// The port number ranges from 0 to 49151.
// see 3GPP TS 23.040, 9.2.3.24.3/4 Application Port Addressing.
let originatorPort = (header && header.originatorPort !== undefined)
? header.originatorPort
: Ci.nsIGonkSmsService.SMS_APPLICATION_PORT_INVALID;
let destinationPort = (header && header.destinationPort !== undefined)
? header.destinationPort
: Ci.nsIGonkSmsService.SMS_APPLICATION_PORT_INVALID;
// MWI info:
let mwiPresent = (aMessage.mwi)? true : false;
let mwiDiscard = (mwiPresent)? aMessage.mwi.discard: false;
let mwiMsgCount = (mwiPresent)? aMessage.mwi.msgCount: 0;
let mwiActive = (mwiPresent)? aMessage.mwi.active: false;
// CDMA related attributes:
let cdmaMessageType = aMessage.messageType || 0;
let cdmaTeleservice = aMessage.teleservice || 0;
let cdmaServiceCategory = aMessage.serviceCategory || 0;
gSmsService
.notifyMessageReceived(this.clientId,
aMessage.SMSC || null,
aMessage.sentTimestamp,
aMessage.sender,
aMessage.pid,
aMessage.encoding,
RIL.GECKO_SMS_MESSAGE_CLASSES
.indexOf(aMessage.messageClass),
aMessage.language || null,
segmentRef,
segmentSeq,
segmentMaxSeq,
originatorPort,
destinationPort,
mwiPresent,
mwiDiscard,
mwiMsgCount,
mwiActive,
cdmaMessageType,
cdmaTeleservice,
cdmaServiceCategory,
aMessage.body || null,
aMessage.data || [],
(aMessage.data) ? aMessage.data.length : 0);
},
/**
@ -2756,8 +2219,9 @@ RadioInterface.prototype = {
handleIccMwis: function(mwi) {
let service = Cc["@mozilla.org/voicemail/voicemailservice;1"]
.getService(Ci.nsIGonkVoicemailService);
// Note: returnNumber and returnMessage is not available from UICC.
service.notifyStatusChanged(this.clientId, mwi.active, mwi.msgCount,
mwi.returnNumber, mwi.returnMessage);
null, null);
},
handleIccInfoChange: function(message) {