Bug 850140 - B2G MMS: implement MmsService.handleDeliveryIndication() to handle delivery report (part 1, provide and correct DB functions). r=vicamo a=koi+

This commit is contained in:
Gene Lian 2013-07-31 15:23:37 +08:00
parent 868bc9fa1d
commit e620d61236
4 changed files with 292 additions and 158 deletions

View File

@ -25,7 +25,7 @@ interface nsIRilMobileMessageDatabaseRecordCallback : nsISupports
void notify(in nsresult aRv, in jsval aMessageRecord, in nsISupports aDomMessage);
};
[scriptable, uuid(0ead3154-542d-4e2c-a624-9e3cec504758)]
[scriptable, uuid(f6cd671e-f9af-11e2-b64b-1fb87e9c217c)]
interface nsIRilMobileMessageDatabaseService : nsIMobileMessageDatabaseService
{
/**
@ -43,7 +43,7 @@ interface nsIRilMobileMessageDatabaseService : nsIMobileMessageDatabaseService
* - |deliveryStatus| DOMString Array: the delivery status of received message
* - |receivers| DOMString Array: the phone numbers of receivers
* - |msisdn| DOMString: [optional] my own phone number.
* - |transactionId| DOMString: the transaction ID from MMS pdu header.
* - |transactionId| DOMString: the transaction ID from MMS PDU header.
*
* Note: |deliveryStatus| should only contain single string to specify
* the delivery status of MMS message for the phone owner self.
@ -72,26 +72,41 @@ interface nsIRilMobileMessageDatabaseService : nsIMobileMessageDatabaseService
* |aReceiver| DOMString: the phone number of receiver (for MMS; can be null).
* |aDelivery| DOMString: the new delivery value to update (can be null).
* |aDeliveryStatus| DOMString: the new delivery status to update (can be null).
* |aEnvelopeId| DOMString: the "message-id" specified in the MMS PDU headers.
* |aCallback| nsIRilMobileMessageDatabaseCallback: an optional callback.
*/
void setMessageDelivery(in long aMessageId,
in DOMString aReceiver,
in DOMString aDelivery,
in DOMString aDeliveryStatus,
[optional] in nsIRilMobileMessageDatabaseCallback aCallback);
void setMessageDeliveryByMessageId(in long aMessageId,
in DOMString aReceiver,
in DOMString aDelivery,
in DOMString aDeliveryStatus,
in DOMString aEnvelopeId,
[optional] in nsIRilMobileMessageDatabaseCallback aCallback);
/**
* |aEnvelopeId| DOMString: the "message-id" specified in the MMS PDU headers.
* |aReceiver| DOMString: the phone number of receiver (for MMS; can be null).
* |aDelivery| DOMString: the new delivery value to update (can be null).
* |aDeliveryStatus| DOMString: the new delivery status to update (can be null).
* |aCallback| nsIRilMobileMessageDatabaseCallback: an optional callback.
*/
void setMessageDeliveryByEnvelopeId(in DOMString aEnvelopeId,
in DOMString aReceiver,
in DOMString aDelivery,
in DOMString aDeliveryStatus,
[optional] in nsIRilMobileMessageDatabaseCallback aCallback);
/**
* |aMessageId| Number: the message's DB record ID.
* |aCallback| nsIRilMobileMessageDatabaseCallback: a callback which takes
* result flag, message record and domMessage as parameters.
* |aCallback| nsIRilMobileMessageDatabaseRecordCallback: a callback which
* takes result flag, message record and domMessage as parameters.
*/
void getMessageRecordById(in long aMessageId,
in nsIRilMobileMessageDatabaseRecordCallback aCallback);
/**
* |aTransactionId| DOMString: the transaction ID of MMS pdu.
* |aCallback| nsIRilMobileMessageDatabaseCallback: a callback which takes
* result flag and message record as parameters.
* |aTransactionId| DOMString: the transaction ID of MMS PDU.
* |aCallback| nsIRilMobileMessageDatabaseRecordCallback: a callback which
* takes result flag and message record as parameters.
*/
void getMessageRecordByTransactionId(in DOMString aTransactionId,
in nsIRilMobileMessageDatabaseRecordCallback aCallback);

View File

@ -1396,11 +1396,13 @@ MmsService.prototype = {
transaction.run();
// Retrieved fail after retry, so we update the delivery status in DB and
// notify this domMessage that error happen.
gMobileMessageDatabaseService.setMessageDelivery(id,
null,
null,
DELIVERY_STATUS_ERROR,
(function (rv, domMessage) {
gMobileMessageDatabaseService
.setMessageDeliveryByMessageId(id,
null,
null,
DELIVERY_STATUS_ERROR,
null,
(function (rv, domMessage) {
this.broadcastReceivedMessageEvent(domMessage);
}).bind(this));
return;
@ -1728,11 +1730,12 @@ MmsService.prototype = {
let isSentSuccess = (aErrorCode == Ci.nsIMobileMessageCallback.SUCCESS_NO_ERROR);
gMobileMessageDatabaseService
.setMessageDelivery(aDomMessage.id,
null,
isSentSuccess ? DELIVERY_SENT : DELIVERY_ERROR,
isSentSuccess ? null : DELIVERY_STATUS_ERROR,
function notifySetDeliveryResult(aRv, aDomMessage) {
.setMessageDeliveryByMessageId(aDomMessage.id,
null,
isSentSuccess ? DELIVERY_SENT : DELIVERY_ERROR,
isSentSuccess ? null : DELIVERY_STATUS_ERROR,
null,
function notifySetDeliveryResult(aRv, aDomMessage) {
if (DEBUG) debug("Marking the delivery state/staus is done. Notify sent or failed.");
// TODO bug 832140 handle !Components.isSuccessCode(aRv)
if (!isSentSuccess) {
@ -1874,11 +1877,13 @@ MmsService.prototype = {
// status to 'error'.
if (MMS.MMS_PDU_STATUS_RETRIEVED !== mmsStatus) {
if (DEBUG) debug("RetrieveMessage fail after retry.");
gMobileMessageDatabaseService.setMessageDelivery(aMessageId,
null,
null,
DELIVERY_STATUS_ERROR,
function () {
gMobileMessageDatabaseService
.setMessageDeliveryByMessageId(aMessageId,
null,
null,
DELIVERY_STATUS_ERROR,
null,
function () {
aRequest.notifyGetMessageFailed(Ci.nsIMobileMessageCallback.INTERNAL_ERROR);
});
return;
@ -1932,13 +1937,14 @@ MmsService.prototype = {
};
// Update the delivery status to pending in DB.
gMobileMessageDatabaseService
.setMessageDelivery(aMessageId,
null,
null,
DELIVERY_STATUS_PENDING,
this.retrieveMessage(url,
responseNotify.bind(this),
aDomMessage));
.setMessageDeliveryByMessageId(aMessageId,
null,
null,
DELIVERY_STATUS_PENDING,
null,
this.retrieveMessage(url,
responseNotify.bind(this),
aDomMessage));
}).bind(this));
},

View File

@ -24,7 +24,7 @@ const DISABLE_MMS_GROUPING_FOR_RECEIVING = true;
const DB_NAME = "sms";
const DB_VERSION = 11;
const DB_VERSION = 12;
const MESSAGE_STORE_NAME = "sms";
const THREAD_STORE_NAME = "thread";
const PARTICIPANT_STORE_NAME = "participant";
@ -221,10 +221,14 @@ MobileMessageDatabaseService.prototype = {
if (DEBUG) debug("Upgrade to version 11. Add last message type into threadRecord.");
self.upgradeSchema10(event.target.transaction, next);
break;
case 11:
// This will need to be moved for each new version
if (DEBUG) debug("Upgrade finished.");
break;
case 11:
if (DEBUG) debug("Upgrade to version 12. Add envelopeId index for outgoing MMS.");
self.upgradeSchema11(event.target.transaction, next);
break;
case 12:
// This will need to be moved for each new version
if (DEBUG) debug("Upgrade finished.");
break;
default:
event.target.transaction.abort();
callback("Old database version: " + event.oldVersion, null);
@ -765,6 +769,38 @@ MobileMessageDatabaseService.prototype = {
};
},
/**
* Add envelopeId index for MMS.
*/
upgradeSchema11: function upgradeSchema11(transaction, next) {
let messageStore = transaction.objectStore(MESSAGE_STORE_NAME);
// Delete "envelopeId" index.
if (messageStore.indexNames.contains("envelopeId")) {
messageStore.deleteIndex("envelopeId");
}
// Create new "envelopeId" indexes.
messageStore.createIndex("envelopeId", "envelopeIdIndex", { unique: true });
// Populate new "envelopeIdIndex" attributes.
messageStore.openCursor().onsuccess = function(event) {
let cursor = event.target.result;
if (!cursor) {
next();
return;
}
let messageRecord = cursor.value;
if (messageRecord.type == "mms" &&
messageRecord.delivery == DELIVERY_SENT) {
messageRecord.envelopeIdIndex = messageRecord.headers["message-id"];
cursor.update(messageRecord);
}
cursor.continue();
};
},
createDomMessageFromRecord: function createDomMessageFromRecord(aMessageRecord) {
if (DEBUG) {
debug("createDomMessageFromRecord: " + JSON.stringify(aMessageRecord));
@ -1152,6 +1188,162 @@ MobileMessageDatabaseService.prototype = {
return aMessageRecord.id;
},
updateMessageDeliveryById: function updateMessageDeliveryById(
id, type, receiver, delivery, deliveryStatus, envelopeId, callback) {
if (DEBUG) {
debug("Setting message's delivery by " + type + " = "+ id
+ " receiver: " + receiver
+ " delivery: " + delivery
+ " deliveryStatus: " + deliveryStatus
+ " envelopeId: " + envelopeId);
}
let self = this;
let messageRecord;
function notifyResult(rv) {
if (!callback) {
return;
}
let domMessage = self.createDomMessageFromRecord(messageRecord);
callback.notify(rv, domMessage);
}
this.newTxn(READ_WRITE, function (error, txn, messageStore) {
if (error) {
// TODO bug 832140 check event.target.errorCode
notifyResult(Cr.NS_ERROR_FAILURE);
return;
}
txn.oncomplete = function oncomplete(event) {
notifyResult(Cr.NS_OK);
};
txn.onabort = function onabort(event) {
// TODO bug 832140 check event.target.errorCode
notifyResult(Cr.NS_ERROR_FAILURE);
};
let getRequest;
if (type === "messageId") {
getRequest = messageStore.get(id);
} else if (type === "envelopeId") {
getRequest = messageStore.index("envelopeId").get(id);
}
getRequest.onsuccess = function onsuccess(event) {
messageRecord = event.target.result;
if (!messageRecord) {
if (DEBUG) debug("type = " + id + " is not found");
return;
}
let isRecordUpdated = false;
// Update |messageRecord.delivery| if needed.
if (delivery && messageRecord.delivery != delivery) {
messageRecord.delivery = delivery;
messageRecord.deliveryIndex = [delivery, messageRecord.timestamp];
isRecordUpdated = true;
}
// Update |messageRecord.deliveryStatus| if needed.
if (deliveryStatus) {
if (messageRecord.type == "sms") {
if (messageRecord.deliveryStatus != deliveryStatus) {
messageRecord.deliveryStatus = deliveryStatus;
isRecordUpdated = true;
}
} else if (messageRecord.type == "mms") {
if (!receiver) {
for (let i = 0; i < messageRecord.deliveryStatus.length; i++) {
if (messageRecord.deliveryStatus[i] != deliveryStatus) {
messageRecord.deliveryStatus[i] = deliveryStatus;
isRecordUpdated = true;
}
}
} else {
let normReceiver = PhoneNumberUtils.normalize(receiver, false);
if (!normReceiver) {
if (DEBUG) {
debug("Normalized receiver is not valid. Fail to update.");
}
return;
}
let parsedReveiver = PhoneNumberUtils.parseWithMCC(normReceiver, null);
let found = false;
for (let i = 0; i < messageRecord.receivers.length; i++) {
let storedReceiver = messageRecord.receivers[i];
let normStoreReceiver =
PhoneNumberUtils.normalize(storedReceiver, false);
if (!normStoreReceiver) {
if (DEBUG) {
debug("Normalized stored receiver is not valid. Skipping.");
}
continue;
}
let match = (normReceiver === normStoreReceiver);
if (!match) {
if (parsedReveiver) {
if (normStoreReceiver.endsWith(parsedReveiver.nationalNumber)) {
match = true;
}
} else {
let parsedStoreReceiver =
PhoneNumberUtils.parseWithMCC(normStoreReceiver, null);
if (parsedStoreReceiver &&
normReceiver.endsWith(parsedStoreReceiver.nationalNumber)) {
match = true;
}
}
}
if (!match) {
if (DEBUG) debug("Stored receiver is not matched. Skipping.");
continue;
}
found = true;
if (messageRecord.deliveryStatus[i] != deliveryStatus) {
messageRecord.deliveryStatus[i] = deliveryStatus;
isRecordUpdated = true;
}
}
if (!found) {
if (DEBUG) {
debug("Cannot find the receiver. Fail to set delivery status.");
}
return;
}
}
}
}
// Update |messageRecord.envelopeIdIndex| if needed.
if (envelopeId) {
if (messageRecord.envelopeIdIndex != envelopeId) {
messageRecord.envelopeIdIndex = envelopeId;
isRecordUpdated = true;
}
}
if (!isRecordUpdated) {
if (DEBUG) {
debug("The values of delivery, deliveryStatus and envelopeId " +
"don't need to be updated.");
}
return;
}
if (DEBUG) {
debug("The delivery, deliveryStatus or envelopeId are updated.");
}
messageStore.put(messageRecord);
};
});
},
/**
* nsIRilMobileMessageDatabaseService API
*/
@ -1283,107 +1475,20 @@ MobileMessageDatabaseService.prototype = {
return this.saveRecord(aMessage, addresses, aCallback);
},
setMessageDelivery: function setMessageDelivery(
messageId, receiver, delivery, deliveryStatus, callback) {
if (DEBUG) {
debug("Setting message " + messageId + " delivery to " + delivery
+ ", and deliveryStatus to " + deliveryStatus);
}
setMessageDeliveryByMessageId: function setMessageDeliveryByMessageId(
messageId, receiver, delivery, deliveryStatus, envelopeId, callback) {
this.updateMessageDeliveryById(messageId, "messageId",
receiver, delivery, deliveryStatus,
envelopeId, callback);
let self = this;
let messageRecord;
function notifyResult(rv) {
if (!callback) {
return;
}
let domMessage = self.createDomMessageFromRecord(messageRecord);
callback.notify(rv, domMessage);
}
},
this.newTxn(READ_WRITE, function (error, txn, messageStore) {
if (error) {
// TODO bug 832140 check event.target.errorCode
notifyResult(Cr.NS_ERROR_FAILURE);
return;
}
txn.oncomplete = function oncomplete(event) {
notifyResult(Cr.NS_OK);
};
txn.onabort = function onabort(event) {
// TODO bug 832140 check event.target.errorCode
notifyResult(Cr.NS_ERROR_FAILURE);
};
setMessageDeliveryByEnvelopeId: function setMessageDeliveryByEnvelopeId(
envelopeId, receiver, delivery, deliveryStatus, callback) {
this.updateMessageDeliveryById(envelopeId, "envelopeId",
receiver, delivery, deliveryStatus,
null, callback);
let getRequest = messageStore.get(messageId);
getRequest.onsuccess = function onsuccess(event) {
messageRecord = event.target.result;
if (!messageRecord) {
if (DEBUG) debug("Message ID " + messageId + " not found");
return;
}
if (messageRecord.id != messageId) {
if (DEBUG) {
debug("Retrieve message ID (" + messageId + ") is " +
"different from the one we got");
}
return;
}
let isRecordUpdated = false;
// Update |messageRecord.delivery| if needed.
if (delivery && messageRecord.delivery != delivery) {
messageRecord.delivery = delivery;
messageRecord.deliveryIndex = [delivery, messageRecord.timestamp];
isRecordUpdated = true;
}
// Update |messageRecord.deliveryStatus| if needed.
if (deliveryStatus) {
if (messageRecord.type == "sms") {
if (messageRecord.deliveryStatus != deliveryStatus) {
messageRecord.deliveryStatus = deliveryStatus;
isRecordUpdated = true;
}
} else if (messageRecord.type == "mms") {
if (!receiver) {
for (let i = 0; i < messageRecord.deliveryStatus.length; i++) {
if (messageRecord.deliveryStatus[i] != deliveryStatus) {
messageRecord.deliveryStatus[i] = deliveryStatus;
isRecordUpdated = true;
}
}
} else {
let index = messageRecord.receivers.indexOf(receiver);
if (index == -1) {
if (DEBUG) {
debug("Cannot find the receiver. Fail to set delivery status.");
}
return;
}
if (messageRecord.deliveryStatus[index] != deliveryStatus) {
messageRecord.deliveryStatus[index] = deliveryStatus;
isRecordUpdated = true;
}
}
}
}
// Only updates messages that have different delivery or deliveryStatus.
if (!isRecordUpdated) {
if (DEBUG) {
debug("The values of attribute delivery and deliveryStatus are the"
+ " the same with given parameters.");
}
return;
}
if (DEBUG) {
debug("The record's delivery and/or deliveryStatus are updated.");
}
messageStore.put(messageRecord);
};
});
},
getMessageRecordByTransactionId: function getMessageRecordByTransactionId(aTransactionId, aCallback) {
@ -1413,8 +1518,9 @@ MobileMessageDatabaseService.prototype = {
txn.onerror = function onerror(event) {
if (DEBUG) {
if (event.target)
if (event.target) {
debug("Caught error on transaction", event.target.errorCode);
}
}
aCallback.notify(Ci.nsIMobileMessageCallback.INTERNAL_ERROR, null, null);
};

View File

@ -2032,11 +2032,13 @@ RadioInterface.prototype = {
return;
}
gMobileMessageDatabaseService.setMessageDelivery(options.sms.id,
null,
DOM_MOBILE_MESSAGE_DELIVERY_SENT,
options.sms.deliveryStatus,
function notifyResult(rv, domMessage) {
gMobileMessageDatabaseService
.setMessageDeliveryByMessageId(options.sms.id,
null,
DOM_MOBILE_MESSAGE_DELIVERY_SENT,
options.sms.deliveryStatus,
null,
function notifyResult(rv, domMessage) {
// TODO bug 832140 handle !Components.isSuccessCode(rv)
this.broadcastSmsSystemMessage("sms-sent", domMessage);
@ -2065,11 +2067,13 @@ RadioInterface.prototype = {
return;
}
gMobileMessageDatabaseService.setMessageDelivery(options.sms.id,
null,
options.sms.delivery,
message.deliveryStatus,
function notifyResult(rv, domMessage) {
gMobileMessageDatabaseService
.setMessageDeliveryByMessageId(options.sms.id,
null,
options.sms.delivery,
message.deliveryStatus,
null,
function notifyResult(rv, domMessage) {
// TODO bug 832140 handle !Components.isSuccessCode(rv)
let topic = (message.deliveryStatus == RIL.GECKO_SMS_DELIVERY_STATUS_SUCCESS)
? kSmsDeliverySuccessObserverTopic
@ -2099,11 +2103,13 @@ RadioInterface.prototype = {
return;
}
gMobileMessageDatabaseService.setMessageDelivery(options.sms.id,
null,
DOM_MOBILE_MESSAGE_DELIVERY_ERROR,
RIL.GECKO_SMS_DELIVERY_STATUS_ERROR,
function notifyResult(rv, domMessage) {
gMobileMessageDatabaseService
.setMessageDeliveryByMessageId(options.sms.id,
null,
DOM_MOBILE_MESSAGE_DELIVERY_ERROR,
RIL.GECKO_SMS_DELIVERY_STATUS_ERROR,
null,
function notifyResult(rv, domMessage) {
// TODO bug 832140 handle !Components.isSuccessCode(rv)
options.request.notifySendMessageFailed(error);
Services.obs.notifyObservers(domMessage, kSmsFailedObserverTopic, null);
@ -3275,11 +3281,12 @@ RadioInterface.prototype = {
}
gMobileMessageDatabaseService
.setMessageDelivery(domMessage.id,
null,
DOM_MOBILE_MESSAGE_DELIVERY_ERROR,
RIL.GECKO_SMS_DELIVERY_STATUS_ERROR,
function notifyResult(rv, domMessage) {
.setMessageDeliveryByMessageId(domMessage.id,
null,
DOM_MOBILE_MESSAGE_DELIVERY_ERROR,
RIL.GECKO_SMS_DELIVERY_STATUS_ERROR,
null,
function notifyResult(rv, domMessage) {
// TODO bug 832140 handle !Components.isSuccessCode(rv)
request.notifySendMessageFailed(errorCode);
Services.obs.notifyObservers(domMessage, kSmsFailedObserverTopic, null);