Merge b2g-inbound to m-c.

This commit is contained in:
Ryan VanderMeulen 2013-11-06 14:08:22 -05:00
commit b3add2d839
31 changed files with 890 additions and 263 deletions

View File

@ -1,4 +1,4 @@
{
"revision": "5cc807be4ece02c364c1d7f1cd2becbe1a1b441e",
"revision": "d995823e80fa7f2e67263699bb6e42a6bcde65ea",
"repo_path": "/integration/gaia-central"
}

View File

@ -250,7 +250,9 @@ const kEventConstructors = {
return new MozSmsEvent(aName, aProps);
},
},
MozStkCommandEvent: { create: null, // Cannot create untrusted event from JS.
MozStkCommandEvent: { create: function (aName, aProps) {
return new MozStkCommandEvent(aName, aProps);
},
},
MozVoicemailEvent: { create: function (aName, aProps) {
return new MozVoicemailEvent(aName, aProps);

View File

@ -792,10 +792,6 @@ DOMInterfaces = {
'nativeType': 'mozilla::dom::PowerManager',
},
'MozStkCommandEvent' : {
'nativeType': 'mozilla::dom::StkCommandEvent',
},
'MozTimeManager': {
'nativeType': 'mozilla::dom::time::TimeManager',
},

View File

@ -1249,6 +1249,7 @@ private:
nsRefPtr<RegisterAgentReplyHandler> handler =
new RegisterAgentReplyHandler(aAgentVTable);
MOZ_ASSERT(handler.get());
MOZ_ASSERT(!sAdapterPath.IsEmpty());
bool success = threadConnection->SendWithReply(
RegisterAgentReplyHandler::Callback, handler.get(), -1,
@ -1686,17 +1687,22 @@ BluetoothDBusService::StartInternal()
sPairingReqTable = new nsDataHashtable<nsStringHashKey, DBusMessage* >;
}
// Normally we'll receive the signal 'AdapterAdded' for the default
// adapter from the DBus daemon during start up. If we restart after
// a crash, the default adapter might already be available, so we ask
// the daemon explicitly here.
bool success = mConnection->SendWithReply(OnDefaultAdapterReply, nullptr,
1000, "/",
DBUS_ADAPTER_IFACE,
"DefaultAdapter",
DBUS_TYPE_INVALID);
if (!success) {
BT_WARNING("Failed to query default adapter!");
/**
* Normally we'll receive the signal 'AdapterAdded' with the adapter object
* path from the DBus daemon during start up. So, there's no need to query
* the object path of default adapter here. However, if we restart from a
* crash, the default adapter might already be available, so we ask the daemon
* explicitly here.
*/
if (sAdapterPath.IsEmpty()) {
bool success = mConnection->SendWithReply(OnDefaultAdapterReply, nullptr,
1000, "/",
DBUS_MANAGER_IFACE,
"DefaultAdapter",
DBUS_TYPE_INVALID);
if (!success) {
BT_WARNING("Failed to query default adapter!");
}
}
return NS_OK;
@ -1941,6 +1947,7 @@ BluetoothDBusService::SendDiscoveryMessage(const char* aMessageName,
BluetoothReplyRunnable* aRunnable)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(!sAdapterPath.IsEmpty());
if (!IsReady()) {
NS_NAMED_LITERAL_STRING(errorStr, "Bluetooth service is not ready yet!");
@ -1978,6 +1985,7 @@ BluetoothDBusService::SendInputMessage(const nsAString& aDeviceAddress,
return NS_ERROR_FAILURE;
}
MOZ_ASSERT(!sAdapterPath.IsEmpty());
nsString objectPath = GetObjectPathFromAddress(sAdapterPath, aDeviceAddress);
return SendAsyncDBusMessage(objectPath, DBUS_INPUT_IFACE, aMessage, callback);
}
@ -2030,6 +2038,7 @@ BluetoothDBusService::SendSinkMessage(const nsAString& aDeviceAddress,
return NS_ERROR_FAILURE;
}
MOZ_ASSERT(!sAdapterPath.IsEmpty());
nsString objectPath = GetObjectPathFromAddress(sAdapterPath, aDeviceAddress);
return SendAsyncDBusMessage(objectPath, DBUS_SINK_IFACE, aMessage, callback);
}
@ -2143,6 +2152,7 @@ protected:
bool SendNextGetProperties()
{
MOZ_ASSERT(mProcessedDeviceAddresses < mDeviceAddresses.Length());
MOZ_ASSERT(!sAdapterPath.IsEmpty());
// cache object path for reply
mObjectPath = GetObjectPathFromAddress(sAdapterPath,
@ -2256,6 +2266,7 @@ BluetoothDBusService::SetProperty(BluetoothObjectType aType,
}
MOZ_ASSERT(aType < ArrayLength(sBluetoothDBusIfaces));
MOZ_ASSERT(!sAdapterPath.IsEmpty());
const char* interface = sBluetoothDBusIfaces[aType];
/* Compose the command */
@ -2363,6 +2374,7 @@ BluetoothDBusService::CreatePairedDeviceInternal(
sIsPairing++;
nsRefPtr<BluetoothReplyRunnable> runnable = aRunnable;
MOZ_ASSERT(!sAdapterPath.IsEmpty());
// Then send CreatePairedDevice, it will register a temp device agent then
// unregister it after pairing process is over
@ -2411,6 +2423,7 @@ BluetoothDBusService::RemoveDeviceInternal(const nsAString& aDeviceAddress,
return NS_OK;
}
MOZ_ASSERT(!sAdapterPath.IsEmpty());
nsCString deviceObjectPath =
NS_ConvertUTF16toUTF8(GetObjectPathFromAddress(sAdapterPath,
aDeviceAddress));
@ -2785,6 +2798,7 @@ BluetoothDBusService::GetServiceChannel(const nsAString& aDeviceAddress,
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(!sAdapterPath.IsEmpty());
nsString objectPath(GetObjectPathFromAddress(sAdapterPath, aDeviceAddress));
#ifdef MOZ_WIDGET_GONK
@ -2841,6 +2855,7 @@ BluetoothDBusService::UpdateSdpRecords(const nsAString& aDeviceAddress,
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(!aDeviceAddress.IsEmpty());
MOZ_ASSERT(!sAdapterPath.IsEmpty());
MOZ_ASSERT(aManager);
MOZ_ASSERT(mConnection);
@ -3025,6 +3040,7 @@ BluetoothDBusService::SendMetaData(const nsAString& aTitle,
return;
}
MOZ_ASSERT(!sAdapterPath.IsEmpty());
nsAutoString address;
a2dp->GetAddress(address);
nsString objectPath =
@ -3157,6 +3173,7 @@ BluetoothDBusService::SendPlayStatus(int64_t aDuration,
UpdateNotification(ControlEventId::EVENT_PLAYBACK_POS_CHANGED, aPosition);
}
MOZ_ASSERT(!sAdapterPath.IsEmpty());
nsAutoString address;
a2dp->GetAddress(address);
nsString objectPath =
@ -3204,6 +3221,7 @@ BluetoothDBusService::UpdatePlayStatus(uint32_t aDuration,
NS_ENSURE_TRUE_VOID(a2dp);
MOZ_ASSERT(a2dp->IsConnected());
MOZ_ASSERT(a2dp->IsAvrcpConnected());
MOZ_ASSERT(!sAdapterPath.IsEmpty());
nsAutoString address;
a2dp->GetAddress(address);
@ -3234,6 +3252,7 @@ BluetoothDBusService::UpdateNotification(ControlEventId aEventId,
NS_ENSURE_TRUE_VOID(a2dp);
MOZ_ASSERT(a2dp->IsConnected());
MOZ_ASSERT(a2dp->IsAvrcpConnected());
MOZ_ASSERT(!sAdapterPath.IsEmpty());
nsAutoString address;
a2dp->GetAddress(address);

View File

@ -494,16 +494,6 @@ dictionary MozStkCommand
jsval options;
};
[scriptable, builtinclass, uuid(21cd2f25-ebea-43f8-8255-eaa4e1182858)]
interface nsIDOMMozStkCommandEvent : nsIDOMEvent
{
/**
* See nsIDOMMozStkCommand for the detail of command.
*/
[implicit_jscontext]
readonly attribute jsval command;
};
dictionary MozStkResponse
{
/**

View File

@ -55,16 +55,11 @@ interface nsIDOMMozGsmIccInfo : nsIDOMMozIccInfo
readonly attribute DOMString msisdn;
};
[scriptable, uuid(013e973e-8b56-4525-b634-d23166b86edb)]
[scriptable, uuid(10b89660-2988-443a-a6f0-4ed3618fee41)]
interface nsIDOMMozCdmaIccInfo : nsIDOMMozIccInfo
{
/**
* Mobile Directory Number (MDN) of the subscriber, aka his phone number.
*/
readonly attribute DOMString mdn;
/**
* Mobile Identification Number (MIN) of the subscriber.
*/
readonly attribute DOMString min;
};

View File

@ -5,10 +5,11 @@
#include "mozilla/dom/IccManager.h"
#include "GeneratedEvents.h"
#include "mozilla/dom/StkCommandEvent.h"
#include "mozilla/dom/MozStkCommandEvent.h"
#include "mozilla/Services.h"
#include "nsIDOMClassInfo.h"
#include "nsIDOMIccInfo.h"
#include "nsJSON.h"
#include "SimToolKit.h"
#define NS_RILCONTENTHELPER_CONTRACTID "@mozilla.org/ril/content-helper;1"
@ -264,10 +265,30 @@ NS_IMPL_EVENT_HANDLER(IccManager, iccinfochange)
NS_IMETHODIMP
IccManager::NotifyStkCommand(const nsAString& aMessage)
{
nsRefPtr<StkCommandEvent> event = StkCommandEvent::Create(this, aMessage);
NS_ASSERTION(event, "This should never fail!");
nsresult rv;
nsIScriptContext* sc = GetContextForEventHandlers(&rv);
NS_ENSURE_SUCCESS(rv, rv);
return event->Dispatch(this, NS_LITERAL_STRING("stkcommand"));
AutoPushJSContext cx(sc->GetNativeContext());
JS::Rooted<JS::Value> value(cx);
if (!aMessage.IsEmpty()) {
nsCOMPtr<nsIJSON> json(new nsJSON());
nsresult rv = json->DecodeToJSVal(aMessage, cx, value.address());
NS_ENSURE_SUCCESS(rv, rv);
} else {
value = JSVAL_VOID;
}
MozStkCommandEventInit init;
init.mBubbles = false;
init.mCancelable = false;
init.mCommand = value;
nsRefPtr<MozStkCommandEvent> event =
MozStkCommandEvent::Constructor(this, NS_LITERAL_STRING("stkcommand"), init);
return DispatchTrustedEvent(event);
}
NS_IMETHODIMP

View File

@ -1,47 +0,0 @@
/* 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 "mozilla/dom/StkCommandEvent.h"
#include "jsfriendapi.h"
#include "nsJSON.h"
#include "SimToolKit.h"
namespace mozilla {
namespace dom {
already_AddRefed<StkCommandEvent>
StkCommandEvent::Create(EventTarget* aOwner,
const nsAString& aMessage)
{
nsRefPtr<StkCommandEvent> event = new StkCommandEvent(aOwner);
event->mCommand = aMessage;
return event.forget();
}
NS_IMPL_ADDREF_INHERITED(StkCommandEvent, nsDOMEvent)
NS_IMPL_RELEASE_INHERITED(StkCommandEvent, nsDOMEvent)
NS_INTERFACE_MAP_BEGIN(StkCommandEvent)
NS_INTERFACE_MAP_ENTRY(nsIDOMMozStkCommandEvent)
NS_INTERFACE_MAP_END_INHERITING(nsDOMEvent)
NS_IMETHODIMP
StkCommandEvent::GetCommand(JSContext* aCx, JS::Value* aCommand)
{
nsCOMPtr<nsIJSON> json(new nsJSON());
if (!mCommand.IsEmpty()) {
nsresult rv = json->DecodeToJSVal(mCommand, aCx, aCommand);
NS_ENSURE_SUCCESS(rv, rv);
} else {
*aCommand = JSVAL_VOID;
}
return NS_OK;
}
} // namespace dom
} // namespace mozilla

View File

@ -1,75 +0,0 @@
/* 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/. */
#ifndef mozilla_dom_StkCommandEvent_h
#define mozilla_dom_StkCommandEvent_h
#include "mozilla/dom/MozStkCommandEventBinding.h"
#include "nsDOMEvent.h"
#include "SimToolKit.h"
namespace mozilla {
namespace dom {
class StkCommandEvent : public nsDOMEvent,
public nsIDOMMozStkCommandEvent
{
nsString mCommand;
public:
NS_DECL_ISUPPORTS_INHERITED
NS_FORWARD_TO_NSDOMEVENT
NS_DECL_NSIDOMMOZSTKCOMMANDEVENT
static already_AddRefed<StkCommandEvent>
Create(EventTarget* aOwner, const nsAString& aMessage);
nsresult
Dispatch(EventTarget* aTarget, const nsAString& aEventType)
{
NS_ASSERTION(aTarget, "Null pointer!");
NS_ASSERTION(!aEventType.IsEmpty(), "Empty event type!");
nsresult rv = InitEvent(aEventType, false, false);
NS_ENSURE_SUCCESS(rv, rv);
SetTrusted(true);
nsDOMEvent* thisEvent = this;
bool dummy;
rv = aTarget->DispatchEvent(thisEvent, &dummy);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
virtual JSObject* WrapObject(JSContext* aCx,
JS::Handle<JSObject*> aScope) MOZ_OVERRIDE
{
return MozStkCommandEventBinding::Wrap(aCx, aScope, this);
}
JS::Value GetCommand(JSContext* aCx, ErrorResult& aRv)
{
JS::Rooted<JS::Value> retVal(aCx);
aRv = GetCommand(aCx, retVal.address());
return retVal;
}
private:
StkCommandEvent(EventTarget* aOwner)
: nsDOMEvent(aOwner, nullptr, nullptr)
{
SetIsDOMBinding();
}
~StkCommandEvent()
{ }
};
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_StkCommandEvent_h

View File

@ -6,12 +6,10 @@
EXPORTS.mozilla.dom += [
'IccManager.h',
'StkCommandEvent.h',
]
SOURCES += [
'IccManager.cpp',
'StkCommandEvent.cpp',
]
FAIL_ON_WARNINGS = True

View File

@ -4,12 +4,15 @@
#include "nsISupports.idl"
[scriptable, builtinclass, uuid(5efe7dc5-4f72-4b8e-9bcd-fb0676b554ca)]
[scriptable, builtinclass, uuid(9672c75d-61a2-470e-964b-2396dcff7cf6)]
interface nsIDOMMozMobileMessageThread : nsISupports
{
// Unique identity of the thread.
readonly attribute unsigned long long id;
// Last (MMS) message subject.
readonly attribute DOMString lastMessageSubject;
// Message body of the last message in the thread.
readonly attribute DOMString body;

View File

@ -14,7 +14,7 @@ interface nsIDOMMozSmsSegmentInfo;
#define MOBILE_MESSAGE_SERVICE_CONTRACTID "@mozilla.org/mobilemessage/mobilemessageservice;1"
%}
[scriptable, builtinclass, uuid(7a39eeb4-827e-4c70-9804-288f94174ebe)]
[scriptable, builtinclass, uuid(c9a1aa14-7088-4f22-9d7f-b0c6ce9cf484)]
interface nsIMobileMessageService : nsISupports
{
[implicit_jscontext]
@ -55,6 +55,7 @@ interface nsIMobileMessageService : nsISupports
nsIDOMMozMobileMessageThread createThread(in unsigned long long id,
in jsval participants,
in jsval timestamp,
in DOMString lastMessageSubject,
in DOMString body,
in unsigned long long unreadCount,
in DOMString aLastMessageType);

View File

@ -112,6 +112,7 @@ NS_IMETHODIMP
MobileMessageService::CreateThread(uint64_t aId,
const JS::Value& aParticipants,
const JS::Value& aTimestamp,
const nsAString& aLastMessageSubject,
const nsAString& aBody,
uint64_t aUnreadCount,
const nsAString& aLastMessageType,
@ -121,6 +122,7 @@ MobileMessageService::CreateThread(uint64_t aId,
return MobileMessageThread::Create(aId,
aParticipants,
aTimestamp,
aLastMessageSubject,
aBody,
aUnreadCount,
aLastMessageType,

View File

@ -32,6 +32,7 @@ NS_IMPL_RELEASE(MobileMessageThread)
MobileMessageThread::Create(const uint64_t aId,
const JS::Value& aParticipants,
const JS::Value& aTimestamp,
const nsAString& aLastMessageSubject,
const nsAString& aBody,
const uint64_t aUnreadCount,
const nsAString& aLastMessageType,
@ -44,6 +45,7 @@ MobileMessageThread::Create(const uint64_t aId,
// to them.
ThreadData data;
data.id() = aId;
data.lastMessageSubject().Assign(aLastMessageSubject);
data.body().Assign(aBody);
data.unreadCount() = aUnreadCount;
@ -114,10 +116,12 @@ MobileMessageThread::Create(const uint64_t aId,
MobileMessageThread::MobileMessageThread(const uint64_t aId,
const nsTArray<nsString>& aParticipants,
const uint64_t aTimestamp,
const nsString& aLastMessageSubject,
const nsString& aBody,
const uint64_t aUnreadCount,
MessageType aLastMessageType)
: mData(aId, aParticipants, aTimestamp, aBody, aUnreadCount, aLastMessageType)
: mData(aId, aParticipants, aTimestamp, aLastMessageSubject, aBody,
aUnreadCount, aLastMessageType)
{
MOZ_ASSERT(aParticipants.Length());
}
@ -135,6 +139,13 @@ MobileMessageThread::GetId(uint64_t* aId)
return NS_OK;
}
NS_IMETHODIMP
MobileMessageThread::GetLastMessageSubject(nsAString& aLastMessageSubject)
{
aLastMessageSubject = mData.lastMessageSubject();
return NS_OK;
}
NS_IMETHODIMP
MobileMessageThread::GetBody(nsAString& aBody)
{

View File

@ -26,6 +26,7 @@ public:
MobileMessageThread(const uint64_t aId,
const nsTArray<nsString>& aParticipants,
const uint64_t aTimestamp,
const nsString& aLastMessageSubject,
const nsString& aBody,
const uint64_t aUnreadCount,
mobilemessage::MessageType aLastMessageType);
@ -35,6 +36,7 @@ public:
static nsresult Create(const uint64_t aId,
const JS::Value& aParticipants,
const JS::Value& aTimestamp,
const nsAString& aLastMessageSubject,
const nsAString& aBody,
const uint64_t aUnreadCount,
const nsAString& aLastMessageType,

View File

@ -24,7 +24,7 @@ const DISABLE_MMS_GROUPING_FOR_RECEIVING = true;
const DB_NAME = "sms";
const DB_VERSION = 17;
const DB_VERSION = 18;
const MESSAGE_STORE_NAME = "sms";
const THREAD_STORE_NAME = "thread";
const PARTICIPANT_STORE_NAME = "participant";
@ -241,6 +241,10 @@ MobileMessageDatabaseService.prototype = {
self.upgradeSchema16(event.target.transaction, next);
break;
case 17:
if (DEBUG) debug("Upgrade to version 18. Add last message subject into threadRecord.");
self.upgradeSchema17(event.target.transaction, next);
break;
case 18:
// This will need to be moved for each new version
if (DEBUG) debug("Upgrade finished.");
break;
@ -1102,6 +1106,44 @@ MobileMessageDatabaseService.prototype = {
};
},
upgradeSchema17: function upgradeSchema17(transaction, next) {
let threadStore = transaction.objectStore(THREAD_STORE_NAME);
let messageStore = transaction.objectStore(MESSAGE_STORE_NAME);
// Add 'lastMessageSubject' to each thread record.
threadStore.openCursor().onsuccess = function(event) {
let cursor = event.target.result;
if (!cursor) {
next();
return;
}
let threadRecord = cursor.value;
// We have defined 'threadRecord.subject' in upgradeSchema7(), but it
// actually means 'threadRecord.body'. Swap the two values first.
threadRecord.body = threadRecord.subject;
delete threadRecord.subject;
// Only MMS supports subject so assign null for non-MMS one.
if (threadRecord.lastMessageType != "mms") {
threadRecord.lastMessageSubject = null;
cursor.update(threadRecord);
cursor.continue();
return;
}
messageStore.get(threadRecord.lastMessageId).onsuccess = function(event) {
let messageRecord = event.target.result;
let subject = messageRecord.headers.subject;
threadRecord.lastMessageSubject = subject || null;
cursor.update(threadRecord);
cursor.continue();
};
};
},
matchParsedPhoneNumbers: function matchParsedPhoneNumbers(addr1, parsedAddr1,
addr2, parsedAddr2) {
if ((parsedAddr1.internationalNumber &&
@ -1488,8 +1530,13 @@ MobileMessageDatabaseService.prototype = {
let needsUpdate = false;
if (threadRecord.lastTimestamp <= timestamp) {
let lastMessageSubject;
if (aMessageRecord.type == "mms") {
lastMessageSubject = aMessageRecord.headers.subject;
}
threadRecord.lastMessageSubject = lastMessageSubject || null;
threadRecord.lastTimestamp = timestamp;
threadRecord.subject = aMessageRecord.body;
threadRecord.body = aMessageRecord.body;
threadRecord.lastMessageId = aMessageRecord.id;
threadRecord.lastMessageType = aMessageRecord.type;
needsUpdate = true;
@ -1508,11 +1555,16 @@ MobileMessageDatabaseService.prototype = {
return;
}
let lastMessageSubject;
if (aMessageRecord.type == "mms") {
lastMessageSubject = aMessageRecord.headers.subject;
}
threadStore.add({participantIds: participantIds,
participantAddresses: aAddresses,
lastMessageId: aMessageRecord.id,
lastTimestamp: timestamp,
subject: aMessageRecord.body,
lastMessageSubject: lastMessageSubject || null,
body: aMessageRecord.body,
unreadCount: aMessageRecord.read ? 0 : 1,
lastMessageType: aMessageRecord.type})
.onsuccess = function (event) {
@ -1744,6 +1796,63 @@ MobileMessageDatabaseService.prototype = {
threadParticipants = threadParticipants.concat(slicedReceivers);
},
updateThreadByMessageChange: function updateThreadByMessageChange(messageStore,
threadStore,
threadId,
messageId,
messageRead) {
threadStore.get(threadId).onsuccess = function(event) {
// This must exist.
let threadRecord = event.target.result;
if (DEBUG) debug("Updating thread record " + JSON.stringify(threadRecord));
if (!messageRead) {
threadRecord.unreadCount--;
}
if (threadRecord.lastMessageId == messageId) {
// Check most recent sender/receiver.
let range = IDBKeyRange.bound([threadId, 0], [threadId, ""]);
let request = messageStore.index("threadId")
.openCursor(range, PREV);
request.onsuccess = function(event) {
let cursor = event.target.result;
if (!cursor) {
if (DEBUG) {
debug("Deleting mru entry for thread id " + threadId);
}
threadStore.delete(threadId);
return;
}
let nextMsg = cursor.value;
let lastMessageSubject;
if (nextMsg.type == "mms") {
lastMessageSubject = nextMsg.headers.subject;
}
threadRecord.lastMessageSubject = lastMessageSubject || null;
threadRecord.lastMessageId = nextMsg.id;
threadRecord.lastTimestamp = nextMsg.timestamp;
threadRecord.body = nextMsg.body;
threadRecord.lastMessageType = nextMsg.type;
if (DEBUG) {
debug("Updating mru entry: " +
JSON.stringify(threadRecord));
}
threadStore.put(threadRecord);
};
} else if (!messageRead) {
// Shortcut, just update the unread count.
if (DEBUG) {
debug("Updating unread count for thread id " + threadId + ": " +
(threadRecord.unreadCount + 1) + " -> " +
threadRecord.unreadCount);
}
threadStore.put(threadRecord);
}
};
},
/**
* nsIRilMobileMessageDatabaseService API
*/
@ -1981,58 +2090,6 @@ MobileMessageDatabaseService.prototype = {
this.getMessageRecordById(aMessageId, notifyCallback);
},
updateThreadByMessageChange: function updateThreadByMessageChange(messageStore,
threadStore,
threadId,
messageId,
messageRead) {
threadStore.get(threadId).onsuccess = function(event) {
// This must exist.
let threadRecord = event.target.result;
if (DEBUG) debug("Updating thread record " + JSON.stringify(threadRecord));
if (!messageRead) {
threadRecord.unreadCount--;
}
if (threadRecord.lastMessageId == messageId) {
// Check most recent sender/receiver.
let range = IDBKeyRange.bound([threadId, 0], [threadId, ""]);
let request = messageStore.index("threadId")
.openCursor(range, PREV);
request.onsuccess = function(event) {
let cursor = event.target.result;
if (!cursor) {
if (DEBUG) {
debug("Deleting mru entry for thread id " + threadId);
}
threadStore.delete(threadId);
return;
}
let nextMsg = cursor.value;
threadRecord.lastMessageId = nextMsg.id;
threadRecord.lastTimestamp = nextMsg.timestamp;
threadRecord.subject = nextMsg.body;
threadRecord.lastMessageType = nextMsg.type;
if (DEBUG) {
debug("Updating mru entry: " +
JSON.stringify(threadRecord));
}
threadStore.put(threadRecord);
};
} else if (!messageRead) {
// Shortcut, just update the unread count.
if (DEBUG) {
debug("Updating unread count for thread id " + threadId + ": " +
(threadRecord.unreadCount + 1) + " -> " +
threadRecord.unreadCount);
}
threadStore.put(threadRecord);
}
};
},
deleteMessage: function deleteMessage(messageIds, length, aRequest) {
if (DEBUG) debug("deleteMessage: message ids " + JSON.stringify(messageIds));
let deleted = [];
@ -2837,7 +2894,8 @@ GetThreadsCursor.prototype = {
gMobileMessageService.createThread(threadRecord.id,
threadRecord.participantAddresses,
threadRecord.lastTimestamp,
threadRecord.subject,
threadRecord.lastMessageSubject || "",
threadRecord.body,
threadRecord.unreadCount,
threadRecord.lastMessageType);
self.callback.notifyCursorResult(thread);

View File

@ -92,6 +92,7 @@ struct ThreadData
uint64_t id;
nsString[] participants;
uint64_t timestamp;
nsString lastMessageSubject;
nsString body;
uint64_t unreadCount;
MessageType lastMessageType;

View File

@ -0,0 +1,301 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
const {Cc: Cc, Ci: Ci, Cr: Cr, Cu: Cu} = SpecialPowers;
let Promise = Cu.import("resource://gre/modules/Promise.jsm").Promise;
/* Push required permissions and test if |navigator.mozMobileMessage| exists.
* Resolve if it does, reject otherwise.
*
* Forfill params:
* manager -- an reference to navigator.mozMobileMessage.
*
* Reject params: (none)
*
* @return A deferred promise.
*/
let manager;
function ensureMobileMessage() {
let deferred = Promise.defer();
let permissions = [{
"type": "sms",
"allow": 1,
"context": document,
}];
SpecialPowers.pushPermissions(permissions, function() {
ok(true, "permissions pushed: " + JSON.stringify(permissions));
manager = window.navigator.mozMobileMessage;
if (manager) {
log("navigator.mozMobileMessage is instance of " + manager.constructor);
} else {
log("navigator.mozMobileMessage is undefined.");
}
if (manager instanceof MozMobileMessageManager) {
deferred.resolve(manager);
} else {
deferred.reject();
}
});
return deferred.promise;
}
/* Send a SMS message to a single receiver. Resolve if it succeeds, reject
* otherwise.
*
* Forfill params:
* message -- the sent SmsMessage.
*
* Reject params:
* error -- a DOMError.
*
* @param aReceiver the address of the receiver.
* @param aText the text body of the message.
*
* @return A deferred promise.
*/
function sendSmsWithSuccess(aReceiver, aText) {
let deferred = Promise.defer();
let request = manager.send(aReceiver, aText);
request.onsuccess = function(event) {
deferred.resolve(event.target.result);
};
request.onerror = function(event) {
deferred.reject(event.target.error);
};
return deferred.promise;
}
/* Send a MMS message with specified parameters. Resolve if it fails, reject
* otherwise.
*
* Forfill params:
* message -- the failed MmsMessage
*
* Reject params: (none)
*
* @param aMmsParameters a MmsParameters instance.
*
* @return A deferred promise.
*/
function sendMmsWithFailure(aMmsParameters) {
let deferred = Promise.defer();
manager.onfailed = function(event) {
manager.onfailed = null;
deferred.resolve(event.message);
};
let request = manager.sendMMS(aMmsParameters);
request.onsuccess = function(event) {
deferred.reject();
};
return deferred.promise;
}
/* Retrieve messages from database.
*
* Forfill params:
* messages -- an array of {Sms,Mms}Message instances.
*
* Reject params:
* event -- a DOMEvent
*
* @param aFilter an optional MozSmsFilter instance.
* @param aReverse a boolean value indicating whether the order of the messages
* should be reversed.
*
* @return A deferred promise.
*/
function getMessages(aFilter, aReverse) {
let deferred = Promise.defer();
if (!aFilter) {
aFilter = new MozSmsFilter;
}
let messages = [];
let cursor = manager.getMessages(aFilter, aReverse || false);
cursor.onsuccess = function(aEvent) {
if (cursor.result) {
messages.push(cursor.result);
cursor.continue();
return;
}
deferred.resolve(messages);
};
cursor.onerror = deferred.reject.bind(deferred);
return deferred.promise;
}
/* Retrieve all messages from database.
*
* Forfill params:
* messages -- an array of {Sms,Mms}Message instances.
*
* Reject params:
* event -- a DOMEvent
*
* @return A deferred promise.
*/
function getAllMessages() {
return getMessages(null, false);
}
/* Retrieve all threads from database.
*
* Forfill params:
* threads -- an array of MozMobileMessageThread instances.
*
* Reject params:
* event -- a DOMEvent
*
* @return A deferred promise.
*/
function getAllThreads() {
let deferred = Promise.defer();
let threads = [];
let cursor = manager.getThreads();
cursor.onsuccess = function(aEvent) {
if (cursor.result) {
threads.push(cursor.result);
cursor.continue();
return;
}
deferred.resolve(threads);
};
cursor.onerror = deferred.reject.bind(deferred);
return deferred.promise;
}
/* Retrieve a single specified thread from database.
*
* Forfill params:
* thread -- a MozMobileMessageThread instance.
*
* Reject params:
* event -- a DOMEvent if an error occurs in the retrieving process, or
* undefined if there's no such thread.
*
* @aThreadId a numeric value identifying the target thread.
*
* @return A deferred promise.
*/
function getThreadById(aThreadId) {
return getAllThreads()
.then(function(aThreads) {
for (let thread of aThreads) {
if (thread.id == aThreadId) {
return thread;
}
}
throw undefined;
});
}
/* Delete messages specified from database.
*
* Forfill params:
* result -- an array of boolean values indicating whether delesion was
* actually performed on the message record with corresponding id.
*
* Reject params:
* event -- a DOMEvent.
*
* @aMessageId an array of numeric values identifying the target messages.
*
* @return An empty array if nothing to be deleted; otherwise, a deferred promise.
*/
function deleteMessagesById(aMessageIds) {
if (!aMessageIds.length) {
ok(true, "no message to be deleted");
return [];
}
let deferred = Promise.defer();
let request = manager.delete(aMessageIds);
request.onsuccess = function(event) {
deferred.resolve(event.target.result);
};
request.onerror = deferred.reject.bind(deferred);
return deferred.promise;
}
/* Delete messages specified from database.
*
* Forfill params:
* result -- an array of boolean values indicating whether delesion was
* actually performed on the message record with corresponding id.
*
* Reject params:
* event -- a DOMEvent.
*
* @aMessages an array of {Sms,Mms}Message instances.
*
* @return A deferred promise.
*/
function deleteMessages(aMessages) {
let ids = messagesToIds(aMessages);
return deleteMessagesById(ids);
}
/* Delete all messages from database.
*
* Forfill params:
* ids -- an array of numeric values identifying those deleted
* {Sms,Mms}Messages.
*
* Reject params:
* event -- a DOMEvent.
*
* @return A deferred promise.
*/
function deleteAllMessages() {
return getAllMessages().then(deleteMessages);
}
/* Create a new array of id attribute of input messages.
*
* @param aMessages an array of {Sms,Mms}Message instances.
*
* @return an array of numeric values.
*/
function messagesToIds(aMessages) {
let ids = [];
for (let message of aMessages) {
ids.push(message.id);
}
return ids;
}
/* Flush permission settings and call |finish()|.
*/
function cleanUp() {
SpecialPowers.flushPermissions(function() {
// Use ok here so that we have at least one test run.
ok(true, "permissions flushed");
finish();
});
}
function startTestCommon(aTestCaseMain) {
ensureMobileMessage()
.then(deleteAllMessages)
.then(aTestCaseMain)
.then(deleteAllMessages)
.then(cleanUp, cleanUp);
}

View File

@ -38,3 +38,4 @@ qemu = true
[test_getthreads.js]
[test_smsc_address.js]
[test_dsds_default_service_id.js]
[test_thread_subject.js]

View File

@ -0,0 +1,67 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
MARIONETTE_TIMEOUT = 60000;
MARIONETTE_HEAD_JS = 'head.js';
const PHONE_NUMBER = "+1234567890";
// Have a long long subject causes the send fails, so we don't need
// networking here.
const MMS_MAX_LENGTH_SUBJECT = 40;
function genMmsSubject(sep) {
return "Hello " + (new Array(MMS_MAX_LENGTH_SUBJECT).join(sep)) + " World!";
}
function testSms(aProgressStr, aText) {
log("Testing thread subject: " + aProgressStr);
return sendSmsWithSuccess(PHONE_NUMBER, aText)
.then(function(message) {
log(" SMS sent, retrieving thread of id " + message.threadId);
return getThreadById(message.threadId);
})
.then(function(thread) {
log(" Got thread.lastMessageSubject = '" + thread.lastMessageSubject + "'");
is(thread.lastMessageSubject, "", "thread.lastMessageSubject");
});
}
function testMms(aProgressStr, aSubject) {
log("Testing thread subject: " + aProgressStr);
let mmsParameters = {
receivers: [PHONE_NUMBER],
subject: aSubject,
attachments: [],
};
// We use a long long message subject so it will always fail.
return sendMmsWithFailure(mmsParameters)
.then(function(message) {
log(" MMS sent, retrieving thread of id " + message.threadId);
return getThreadById(message.threadId);
})
.then(function(thread) {
log(" Got thread.lastMessageSubject = '" + thread.lastMessageSubject + "'");
is(thread.lastMessageSubject, aSubject, "thread.lastMessageSubject");
});
}
startTestCommon(function testCaseMain() {
return testSms("SMS", "text")
.then(testMms.bind(null, "SMS..MMS", genMmsSubject(" ")))
.then(testSms.bind(null, "SMS..MMS..SMS", "text"))
.then(deleteAllMessages)
.then(testMms.bind(null, "MMS", genMmsSubject(" ")))
.then(testSms.bind(null, "MMS..SMS", "text"))
.then(testMms.bind(null, "MMS..SMS..MMS", genMmsSubject(" ")))
.then(deleteAllMessages)
.then(testSms.bind(null, "SMS", "1"))
.then(testSms.bind(null, "SMS..SMS", "2"))
.then(testSms.bind(null, "SMS..SMS..SMS", "3"))
.then(deleteAllMessages)
.then(testMms.bind(null, "MMS", genMmsSubject("a")))
.then(testMms.bind(null, "MMS..MMS", genMmsSubject("b")))
.then(testMms.bind(null, "MMS..MMS..MMS", genMmsSubject("c")));
});

View File

@ -189,8 +189,7 @@ CdmaIccInfo.prototype = {
// nsIDOMMozCdmaIccInfo
mdn: null,
min: null
mdn: null
};
function VoicemailInfo() {}

View File

@ -527,8 +527,7 @@ CdmaIccInfo.prototype = {
// nsIDOMMozCdmaIccInfo
mdn: null,
min: null
mdn: null
};
function RadioInterfaceLayer() {

View File

@ -2772,16 +2772,18 @@ this.PDU_CDMA_MSG_CODING_7BITS_GSM = 0x09; // GSM 7-bit default alphabet(7-bi
this.PDU_CDMA_MSG_CODING_GSM_DCS = 0x0A; // GSM Data-Coding-Scheme, Not supported
// SMS Message Type, as defined in 3GPP2 C.S0015-A v2.0, Table 4.5.1-1
this.PDU_CDMA_MSG_TYPE_DELIVER = 0x01; // Receive
this.PDU_CDMA_MSG_TYPE_SUBMIT = 0x02; // Send
this.PDU_CDMA_MSG_TYPE_DELIVER = 0x01; // Deliver
this.PDU_CDMA_MSG_TYPE_SUBMIT = 0x02; // Submit
this.PDU_CDMA_MSG_TYPE_DELIVER_ACK = 0x04; // Delivery Acknowledgment
// SMS User Data Subparameters, as defined in 3GPP2 C.S0015-A v2.0, Table 4.5-1
this.PDU_CDMA_MSG_USERDATA_MSG_ID = 0x00; // Message Identifier
this.PDU_CDMA_MSG_USERDATA_BODY = 0x01; // User Data Body
this.PDU_CDMA_MSG_USERDATA_TIMESTAMP = 0x03; // Message Center Time Stamp
this.PDU_CDMA_REPLY_OPTION = 0x0A; // Reply Option
this.PDU_CDMA_LANGUAGE_INDICATOR = 0x0D; // Language Indicator
this.PDU_CDMA_MSG_USERDATA_MSG_ID = 0x00; // Message Identifier
this.PDU_CDMA_MSG_USERDATA_BODY = 0x01; // User Data Body
this.PDU_CDMA_MSG_USERDATA_TIMESTAMP = 0x03; // Message Center Time Stamp
this.PDU_CDMA_MSG_USERDATA_REPLY_OPTION = 0x0A; // Reply Option
this.PDU_CDMA_LANGUAGE_INDICATOR = 0x0D; // Language Indicator
this.PDU_CDMA_MSG_USERDATA_CALLBACK_NUMBER = 0x0E; // Callback Number
this.PDU_CDMA_MSG_USER_DATA_MSG_STATUS = 0x14; // Message Status
// CDMA Language Indicator: Language groups
// see 3GPP2 C.R1001-F table 9.2-1

View File

@ -4306,6 +4306,46 @@ let RIL = {
return PDU_FCS_OK;
},
/**
* Helper for processing CDMA SMS Delivery Acknowledgment Message
*
* @param message
* decoded SMS Delivery ACK message from CdmaPDUHelper.
*
* @return A failure cause defined in 3GPP 23.040 clause 9.2.3.22.
*/
_processCdmaSmsStatusReport: function _processCdmaSmsStatusReport(message) {
let options = this._pendingSentSmsMap[message.msgId];
if (!options) {
if (DEBUG) debug("no pending SMS-SUBMIT message");
return PDU_FCS_OK;
}
if (message.errorClass === 2) {
if (DEBUG) debug("SMS-STATUS-REPORT: delivery still pending, msgStatus: " + message.msgStatus);
return PDU_FCS_OK;
}
delete this._pendingSentSmsMap[message.msgId];
if (message.errorClass === -1 && message.body) {
// Process as normal incoming SMS, if errorClass is invalid
// but message body is available.
return this._processSmsMultipart(message);
}
let deliveryStatus = (message.errorClass === 0)
? GECKO_SMS_DELIVERY_STATUS_SUCCESS
: GECKO_SMS_DELIVERY_STATUS_ERROR;
this.sendChromeMessage({
rilMessageType: options.rilMessageType,
rilMessageToken: options.rilMessageToken,
deliveryStatus: deliveryStatus
});
return PDU_FCS_OK;
},
/**
* Helper for processing received multipart SMS.
*
@ -5893,7 +5933,7 @@ RIL[REQUEST_CDMA_SUBSCRIPTION] = function REQUEST_CDMA_SUBSCRIPTION(length, opti
this.iccInfo.mdn = result[0];
// The result[1] is Home SID. (Already be handled in readCDMAHome())
// The result[2] is Home NID. (Already be handled in readCDMAHome())
this.iccInfo.min = result[3];
// The result[3] is MIN.
// The result[4] is PRL version.
ICCUtilsHelper.handleICCInfoChange();
@ -6206,7 +6246,11 @@ RIL[UNSOLICITED_RESPONSE_CDMA_NEW_SMS] = function UNSOLICITED_RESPONSE_CDMA_NEW_
let [message, result] = CdmaPDUHelper.processReceivedSms(length);
if (message) {
result = this._processSmsMultipart(message);
if (message.subMsgType === PDU_CDMA_MSG_TYPE_DELIVER_ACK) {
result = this._processCdmaSmsStatusReport(message);
} else {
result = this._processSmsMultipart(message);
}
}
if (result == PDU_FCS_RESERVED || result == MOZ_FCS_WAIT_FOR_EXPLICIT_ACK) {
@ -8667,6 +8711,9 @@ let CdmaPDUHelper = {
// User Data
this.encodeUserDataMsg(options);
// Reply Option
this.encodeUserDataReplyOption(options);
return userDataBuffer;
},
@ -8791,6 +8838,21 @@ let CdmaPDUHelper = {
BitBufferHelper.overwriteWriteBuffer(lengthPosition - 1, [currentPosition - lengthPosition]);
},
/**
* User data subparameter encoder : Reply Option
*
* @see 3GGP2 C.S0015-B 2.0, 4.5.11 Reply Option
*/
encodeUserDataReplyOption: function cdma_encodeUserDataReplyOption(options) {
if (options.requestStatusReport) {
BitBufferHelper.writeBits(PDU_CDMA_MSG_USERDATA_REPLY_OPTION, 8);
BitBufferHelper.writeBits(1, 8);
BitBufferHelper.writeBits(0, 1); // USER_ACK_REQ
BitBufferHelper.writeBits(1, 1); // DAK_REQ
BitBufferHelper.flushWithPadding();
}
},
/**
* Entry point for SMS decoding, the returned object is made compatible
* with existing readMessage() of GsmPDUHelper
@ -8838,39 +8900,56 @@ let CdmaPDUHelper = {
message.sender += String.fromCharCode(addrDigit);
}
// User Data
// Bearer Data
this.decodeUserData(message);
// Bearer Data Sub-Parameter: User Data
let userData = message[PDU_CDMA_MSG_USERDATA_BODY];
[message.header, message.body, message.encoding] =
(userData)? [userData.header, userData.body, userData.encoding]
: [null, null, null];
// Bearer Data Sub-Parameter: Message Status
// Success Delivery (0) if both Message Status and User Data are absent.
// Message Status absent (-1) if only User Data is available.
let msgStatus = message[PDU_CDMA_MSG_USER_DATA_MSG_STATUS];
[message.errorClass, message.msgStatus] =
(msgStatus)? [msgStatus.errorClass, msgStatus.msgStatus]
: ((message.body)? [-1, -1]: [0, 0]);
// Transform message to GSM msg
let msg = {
SMSC: "",
mti: 0,
udhi: 0,
sender: message.sender,
recipient: null,
pid: PDU_PID_DEFAULT,
epid: PDU_PID_DEFAULT,
dcs: 0,
mwi: null, //message[PDU_CDMA_MSG_USERDATA_BODY].header ? message[PDU_CDMA_MSG_USERDATA_BODY].header.mwi : null,
replace: false,
header: message[PDU_CDMA_MSG_USERDATA_BODY].header,
body: message[PDU_CDMA_MSG_USERDATA_BODY].body,
data: null,
timestamp: message[PDU_CDMA_MSG_USERDATA_TIMESTAMP],
language: message[PDU_CDMA_LANGUAGE_INDICATOR],
status: null,
scts: null,
dt: null,
encoding: message[PDU_CDMA_MSG_USERDATA_BODY].encoding,
messageClass: GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL],
messageType: message.messageType,
serviceCategory: message.service
SMSC: "",
mti: 0,
udhi: 0,
sender: message.sender,
recipient: null,
pid: PDU_PID_DEFAULT,
epid: PDU_PID_DEFAULT,
dcs: 0,
mwi: null,
replace: false,
header: message.header,
body: message.body,
data: null,
timestamp: message[PDU_CDMA_MSG_USERDATA_TIMESTAMP],
language: message[PDU_CDMA_LANGUAGE_INDICATOR],
status: null,
scts: null,
dt: null,
encoding: message.encoding,
messageClass: GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL],
messageType: message.messageType,
serviceCategory: message.service,
subMsgType: message[PDU_CDMA_MSG_USERDATA_MSG_ID].msgType,
msgId: message[PDU_CDMA_MSG_USERDATA_MSG_ID].msgId,
errorClass: message.errorClass,
msgStatus: message.msgStatus
};
return msg;
},
/**
* Helper for processing received SMS parcel data.
*
@ -8963,8 +9042,8 @@ let CdmaPDUHelper = {
case PDU_CDMA_MSG_USERDATA_TIMESTAMP:
message[id] = this.decodeUserDataTimestamp();
break;
case PDU_CDMA_REPLY_OPTION:
message[id] = this.decodeUserDataReplyAction();
case PDU_CDMA_MSG_USERDATA_REPLY_OPTION:
message[id] = this.decodeUserDataReplyOption();
break;
case PDU_CDMA_LANGUAGE_INDICATOR:
message[id] = this.decodeLanguageIndicator();
@ -8972,6 +9051,9 @@ let CdmaPDUHelper = {
case PDU_CDMA_MSG_USERDATA_CALLBACK_NUMBER:
message[id] = this.decodeUserDataCallbackNumber();
break;
case PDU_CDMA_MSG_USER_DATA_MSG_STATUS:
message[id] = this.decodeUserDataMsgStatus();
break;
}
userDataLength -= (length + 2);
@ -9338,7 +9420,7 @@ let CdmaPDUHelper = {
*
* @see 3GGP2 C.S0015-B 2.0, 4.5.11 Reply Option
*/
decodeUserDataReplyAction: function cdma_decodeUserDataReplyAction() {
decodeUserDataReplyOption: function cdma_decodeUserDataReplyOption() {
let replyAction = BitBufferHelper.readBits(4),
result = { userAck: (replyAction & 0x8) ? true : false,
deliverAck: (replyAction & 0x4) ? true : false,
@ -9386,6 +9468,20 @@ let CdmaPDUHelper = {
return result;
},
/**
* User data subparameter decoder : Message Status
*
* @see 3GGP2 C.S0015-B 2.0, 4.5.21 Message Status
*/
decodeUserDataMsgStatus: function cdma_decodeUserDataMsgStatus() {
let result = {
errorClass: BitBufferHelper.readBits(2),
msgStatus: BitBufferHelper.readBits(6)
};
return result;
},
/**
* Decode information record parcel.
*/

View File

@ -0,0 +1,100 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
subscriptLoader.loadSubScript("resource://gre/modules/ril_consts.js", this);
function run_test() {
run_next_test();
}
function _getWorker() {
let _postedMessage;
let _worker = newWorker({
postRILMessage: function fakePostRILMessage(data) {
},
postMessage: function fakePostMessage(message) {
_postedMessage = message;
}
});
return {
get postedMessage() {
return _postedMessage;
},
get worker() {
return _worker;
}
};
}
/**
* Verify CDMA SMS Delivery ACK Message.
*/
add_test(function test_processCdmaSmsStatusReport() {
let workerHelper = _getWorker();
let worker = workerHelper.worker;
function test_StatusReport(errorClass, msgStatus) {
let msgId = 0;
let sentSmsMap = worker.RIL._pendingSentSmsMap;
sentSmsMap[msgId] = {};
let message = {
SMSC: "",
mti: 0,
udhi: 0,
sender: "0987654321",
recipient: null,
pid: PDU_PID_DEFAULT,
epid: PDU_PID_DEFAULT,
dcs: 0,
mwi: null,
replace: false,
header: null,
body: "Status: Sent, Dest: 0987654321",
data: null,
timestamp: new Date().valueOf(),
language: null,
status: null,
scts: null,
dt: null,
encoding: PDU_CDMA_MSG_CODING_7BITS_ASCII,
messageClass: GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL],
messageType: PDU_CDMA_MSG_TYPE_P2P,
serviceCategory: 0,
subMsgType: PDU_CDMA_MSG_TYPE_DELIVER_ACK,
msgId: msgId,
errorClass: errorClass,
msgStatus: msgStatus
};
worker.RIL._processCdmaSmsStatusReport(message);
let postedMessage = workerHelper.postedMessage;
// Check if pending token is removed.
do_check_true((errorClass === 2)? !!sentSmsMap[msgId]: !sentSmsMap[msgId]);
// Check the response message accordingly.
if (errorClass === -1) {
// Check if the report is treated as normal incoming SMS
do_check_eq("sms-received", postedMessage.rilMessageType);
} else if (errorClass === 2) {
// Do nothing.
} else {
// Check Delivery Status
if (errorClass === 0) {
do_check_eq(postedMessage.deliveryStatus, GECKO_SMS_DELIVERY_STATUS_SUCCESS);
} else {
do_check_eq(postedMessage.deliveryStatus, GECKO_SMS_DELIVERY_STATUS_ERROR);
}
}
}
test_StatusReport(-1, -1); // Message Status Sub-parameter is absent.
test_StatusReport(0, 0); // 00|000000: no error|Message accepted
test_StatusReport(2, 4); // 10|000100: temporary condition|Network congestion
test_StatusReport(3, 5); // 11|000101: permanent condition|Network error
run_next_test();
});

View File

@ -0,0 +1,73 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
subscriptLoader.loadSubScript("resource://gre/modules/ril_consts.js", this);
function run_test() {
run_next_test();
}
/**
* Verify CdmaPDUHelper#encodeUserDataReplyOption.
*/
add_test(function test_CdmaPDUHelper_encodeUserDataReplyOption() {
let worker = newWorker({
postRILMessage: function fakePostRILMessage(data) {
// Do nothing
},
postMessage: function fakePostMessage(message) {
// Do nothing
}
});
let testDataBuffer = [];
worker.BitBufferHelper.startWrite(testDataBuffer);
let helper = worker.CdmaPDUHelper;
helper.encodeUserDataReplyOption({requestStatusReport: true});
let expectedDataBuffer = [PDU_CDMA_MSG_USERDATA_REPLY_OPTION, 0x01, 0x40];
do_check_eq(testDataBuffer.length, expectedDataBuffer.length);
for (let i = 0; i < expectedDataBuffer.length; i++) {
do_check_eq(testDataBuffer[i], expectedDataBuffer[i]);
}
run_next_test();
});
/**
* Verify CdmaPDUHelper#cdma_decodeUserDataMsgStatus.
*/
add_test(function test_CdmaPDUHelper_decodeUserDataMsgStatus() {
let worker = newWorker({
postRILMessage: function fakePostRILMessage(data) {
// Do nothing
},
postMessage: function fakePostMessage(message) {
// Do nothing
}
});
let helper = worker.CdmaPDUHelper;
function test_MsgStatus(octet) {
let testDataBuffer = [octet];
worker.BitBufferHelper.startRead(testDataBuffer);
let result = helper.decodeUserDataMsgStatus();
do_check_eq(result.errorClass, octet >>> 6);
do_check_eq(result.msgStatus, octet & 0x3F);
}
// 00|000000: no error|Message accepted
test_MsgStatus(0x00);
// 10|000100: temporary condition|Network congestion
test_MsgStatus(0x84);
// 11|000101: permanent condition|Network error
test_MsgStatus(0xC5);
run_next_test();
});

View File

@ -7,6 +7,8 @@ tail =
[test_ril_worker_sms.js]
# Bug 916067 - B2G RIL: test_ril_worker_sms.js takes too long to finish
skip-if = true
[test_ril_worker_sms_cdma.js]
[test_ril_worker_sms_cdmapduhelper.js]
[test_ril_worker_sms_nl_tables.js]
[test_ril_worker_sms_gsmpduhelper.js]
[test_ril_worker_sms_segment_info.js]

View File

@ -4,8 +4,14 @@
* You can obtain one at http://mozilla.org/MPL/2.0/.
*/
[Pref="dom.icc.enabled",
Constructor(DOMString type, optional MozStkCommandEventInit eventInitDict)]
interface MozStkCommandEvent : Event
{
[Throws]
readonly attribute any command;
};
dictionary MozStkCommandEventInit : EventInit
{
any command = null;
};

View File

@ -515,7 +515,6 @@ if CONFIG['MOZ_B2G_RIL']:
'MozCellBroadcastEvent.webidl',
'MozEmergencyCbModeEvent.webidl',
'MozOtaStatusEvent.webidl',
'MozStkCommandEvent.webidl',
'MozVoicemail.webidl',
'MozVoicemailEvent.webidl',
'USSDReceivedEvent.webidl',
@ -560,6 +559,7 @@ GENERATED_EVENTS_WEBIDL_FILES = [
'MediaStreamEvent.webidl',
'MozContactChangeEvent.webidl',
'MozInterAppMessageEvent.webidl',
'MozStkCommandEvent.webidl',
'RTCDataChannelEvent.webidl',
'RTCPeerConnectionIceEvent.webidl',
'TrackEvent.webidl',
@ -572,4 +572,3 @@ if CONFIG['MOZ_GAMEPAD']:
'GamepadButtonEvent.webidl',
'GamepadEvent.webidl',
]

View File

@ -269,6 +269,9 @@ public:
SetCompositor(nullptr);
mAttached = false;
mKeepAttached = false;
if (mBackendData) {
mBackendData->ClearData();
}
}
}
bool IsAttached() { return mAttached; }

View File

@ -524,7 +524,9 @@ EHTable::EHTable(const void *aELF, size_t aSize, const std::string &aName)
file.e_ident[EI_DATA] != hostEndian ||
file.e_ident[EI_VERSION] != EV_CURRENT ||
file.e_ident[EI_OSABI] != ELFOSABI_SYSV ||
#ifdef EI_ABIVERSION
file.e_ident[EI_ABIVERSION] != 0 ||
#endif
file.e_machine != EM_ARM ||
file.e_version != EV_CURRENT)
// e_flags?