diff --git a/b2g/config/gaia.json b/b2g/config/gaia.json index 594015c4e457..1feadebd1e8e 100644 --- a/b2g/config/gaia.json +++ b/b2g/config/gaia.json @@ -1,4 +1,4 @@ { - "revision": "bdac3547cbc0423bcdcf3b1650be326bfd1c601f", + "revision": "a96d83d7e0bbd6b3fb8ecb78712c924ba8094659", "repo_path": "/integration/gaia-central" } diff --git a/dom/alarm/nsIAlarmHalService.idl b/dom/alarm/nsIAlarmHalService.idl index 744e144f7281..70d31ce3796f 100644 --- a/dom/alarm/nsIAlarmHalService.idl +++ b/dom/alarm/nsIAlarmHalService.idl @@ -21,7 +21,7 @@ interface nsITimezoneChangedCb : nsISupports #define ALARMHALSERVICE_CONTRACTID "@mozilla.org/alarmHalService;1" %} -[scriptable, builtinclass, uuid(057b1ee4-f696-486d-bd55-205e21e88fab)] +[scriptable, uuid(057b1ee4-f696-486d-bd55-205e21e88fab)] interface nsIAlarmHalService : nsISupports { bool setAlarm(in int32_t aSeconds, in int32_t aNanoseconds); diff --git a/dom/base/IndexedDBHelper.jsm b/dom/base/IndexedDBHelper.jsm index 197b897f8c57..a158da91ea9a 100644 --- a/dom/base/IndexedDBHelper.jsm +++ b/dom/base/IndexedDBHelper.jsm @@ -68,7 +68,7 @@ IndexedDBHelper.prototype = { self.upgradeSchema(req.transaction, _db, aEvent.oldVersion, aEvent.newVersion); }; req.onerror = function (aEvent) { - if (DEBUG) debug("Failed to open database:" + self.dbName); + if (DEBUG) debug("Failed to open database: " + self.dbName); aFailureCb(aEvent.target.error.name); }; req.onblocked = function (aEvent) { diff --git a/dom/bluetooth/linux/BluetoothDBusService.cpp b/dom/bluetooth/linux/BluetoothDBusService.cpp index 06cfcea12546..7ed88c2cb5b5 100644 --- a/dom/bluetooth/linux/BluetoothDBusService.cpp +++ b/dom/bluetooth/linux/BluetoothDBusService.cpp @@ -812,34 +812,17 @@ GetPropertiesInternal(const nsAString& aPath, return true; } -class GetPropertiesReplyHandler : public DBusReplyHandler -{ -public: - GetPropertiesReplyHandler(const nsCString& aIface) - : mIface(aIface) - { - MOZ_ASSERT(!mIface.IsEmpty()); - } - - const nsCString& GetInterface() const - { - return mIface; - } - -private: - nsCString mIface; -}; - -class AppendDeviceNameReplyHandler: public GetPropertiesReplyHandler +class AppendDeviceNameReplyHandler: public DBusReplyHandler { public: AppendDeviceNameReplyHandler(const nsCString& aIface, const nsString& aDevicePath, const BluetoothSignal& aSignal) - : GetPropertiesReplyHandler(aIface) + : mIface(aIface) , mDevicePath(aDevicePath) , mSignal(aSignal) { + MOZ_ASSERT(!mIface.IsEmpty()); MOZ_ASSERT(!mDevicePath.IsEmpty()); } @@ -859,7 +842,7 @@ public: BluetoothValue deviceProperties; bool success = UnpackPropertiesMessage(aReply, &err, deviceProperties, - GetInterface().get()); + mIface.get()); if (!success) { BT_WARNING("Failed to get device properties"); return; @@ -894,6 +877,7 @@ public: } private: + nsCString mIface; nsString mDevicePath; BluetoothSignal mSignal; }; @@ -1805,46 +1789,119 @@ BluetoothDBusService::IsEnabledInternal() return mEnabled; } -class DefaultAdapterPropertiesRunnable : public nsRunnable +class DefaultAdapterPathReplyHandler : public DBusReplyHandler { public: - DefaultAdapterPropertiesRunnable(BluetoothReplyRunnable* aRunnable) - : mRunnable(dont_AddRef(aRunnable)) + DefaultAdapterPathReplyHandler(BluetoothReplyRunnable* aRunnable) + : mRunnable(aRunnable) { + MOZ_ASSERT(mRunnable); } - nsresult Run() + void Handle(DBusMessage* aReply) MOZ_OVERRIDE { - MOZ_ASSERT(!NS_IsMainThread()); + MOZ_ASSERT(!NS_IsMainThread()); // DBus thread - BluetoothValue v; - nsAutoString replyError; - if (!GetDefaultAdapterPath(v, replyError)) { - DispatchBluetoothReply(mRunnable, v, replyError); - return NS_ERROR_FAILURE; + if (!aReply || (dbus_message_get_type(aReply) == DBUS_MESSAGE_TYPE_ERROR)) { + const char* errStr = "Timeout in DefaultAdapterPathReplyHandler"; + if (aReply) { + errStr = dbus_message_get_error_name(aReply); + if (!errStr) { + errStr = "Bluetooth DBus Error"; + } + } + DispatchBluetoothReply(mRunnable, BluetoothValue(), + NS_ConvertUTF8toUTF16(errStr)); + return; } - DBusError err; - dbus_error_init(&err); + bool success; + nsAutoString replyError; - nsString objectPath = v.get_nsString(); - v = InfallibleTArray(); - if (!GetPropertiesInternal(objectPath, DBUS_ADAPTER_IFACE, v)) { - NS_WARNING("Getting properties failed!"); - return NS_ERROR_FAILURE; + if (mAdapterPath.IsEmpty()) { + success = HandleDefaultAdapterPathReply(aReply, replyError); + } else { + success = HandleGetPropertiesReply(aReply, replyError); + } + + if (!success) { + DispatchBluetoothReply(mRunnable, BluetoothValue(), replyError); + } + } + +protected: + bool HandleDefaultAdapterPathReply(DBusMessage* aReply, + nsAString& aReplyError) + { + BluetoothValue value; + DBusError error; + dbus_error_init(&error); + + MOZ_ASSERT(!NS_IsMainThread()); // DBus thread + + UnpackObjectPathMessage(aReply, &error, value, aReplyError); + + if (!aReplyError.IsEmpty()) { + return false; + } + + mAdapterPath = value.get_nsString(); + + // Acquire another reference to this reply handler + nsRefPtr handler = this; + + nsRefPtr threadConnection = gThreadConnection; + + if (!threadConnection.get()) { + aReplyError = NS_LITERAL_STRING("DBus connection has been closed."); + return false; + } + + bool success = dbus_func_args_async(threadConnection->GetConnection(), 1000, + DefaultAdapterPathReplyHandler::Callback, + handler.get(), + NS_ConvertUTF16toUTF8(mAdapterPath).get(), + DBUS_ADAPTER_IFACE, "GetProperties", + DBUS_TYPE_INVALID); + if (!success) { + aReplyError = NS_LITERAL_STRING("dbus_func_args_async failed"); + return false; + } + + handler.forget(); + + return true; + } + + bool HandleGetPropertiesReply(DBusMessage* aReply, + nsAutoString& aReplyError) + { + BluetoothValue value; + DBusError error; + dbus_error_init(&error); + + MOZ_ASSERT(!NS_IsMainThread()); // DBus thread + + bool success = UnpackPropertiesMessage(aReply, &error, value, + DBUS_ADAPTER_IFACE); + if (!success) { + aReplyError = NS_ConvertUTF8toUTF16(error.message); + return false; } // We have to manually attach the path to the rest of the elements - v.get_ArrayOfBluetoothNamedValue().AppendElement( - BluetoothNamedValue(NS_LITERAL_STRING("Path"), objectPath)); + value.get_ArrayOfBluetoothNamedValue().AppendElement( + BluetoothNamedValue(NS_LITERAL_STRING("Path"), mAdapterPath)); - DispatchBluetoothReply(mRunnable, v, replyError); + // Dispatch result + DispatchBluetoothReply(mRunnable, value, aReplyError); - return NS_OK; + return true; } private: nsRefPtr mRunnable; + nsString mAdapterPath; }; nsresult @@ -1859,14 +1916,18 @@ BluetoothDBusService::GetDefaultAdapterPathInternal( return NS_OK; } - nsRefPtr runnable = aRunnable; - nsRefPtr func(new DefaultAdapterPropertiesRunnable(runnable)); - if (NS_FAILED(mBluetoothCommandThread->Dispatch(func, NS_DISPATCH_NORMAL))) { - NS_WARNING("Cannot dispatch firmware loading task!"); - return NS_ERROR_FAILURE; - } + nsRefPtr handler = + new DefaultAdapterPathReplyHandler(aRunnable); + bool success = dbus_func_args_async(mConnection, 1000, + DefaultAdapterPathReplyHandler::Callback, + handler.get(), + "/", + DBUS_MANAGER_IFACE, "DefaultAdapter", + DBUS_TYPE_INVALID); + NS_ENSURE_TRUE(success, NS_ERROR_FAILURE); + + handler.forget(); - runnable.forget(); return NS_OK; } diff --git a/dom/contacts/ContactManager.js b/dom/contacts/ContactManager.js index b32cd5fd35ea..64a6816ef29e 100644 --- a/dom/contacts/ContactManager.js +++ b/dom/contacts/ContactManager.js @@ -658,6 +658,12 @@ ContactManager.prototype = { Services.DOMRequest.fireError(req, msg.errorMsg); } break; + case "Contacts:GetAll:Return:KO": + req = this.getRequest(msg.requestID); + if (req) { + Services.DOMRequest.fireError(req.cursor, msg.errorMsg); + } + break; case "PermissionPromptHelper:AskPermission:OK": if (DEBUG) debug("id: " + msg.requestID); req = this.getRequest(msg.requestID); @@ -686,14 +692,14 @@ ContactManager.prototype = { if (DEBUG) debug("new revision: " + msg.revision); req = this.getRequest(msg.requestID); if (req) { - Services.DOMRequest.fireSuccess(req, msg.revision); + Services.DOMRequest.fireSuccess(req.request, msg.revision); } break; case "Contacts:Count": if (DEBUG) debug("count: " + msg.count); req = this.getRequest(msg.requestID); if (req) { - Services.DOMRequest.fireSuccess(req, msg.count); + Services.DOMRequest.fireSuccess(req.request, msg.count); } break; default: @@ -871,8 +877,12 @@ ContactManager.prototype = { }, remove: function removeContact(aRecord) { - let request; - request = this.createRequest(); + let request = this.createRequest(); + if (!aRecord || !aRecord.id) { + Services.DOMRequest.fireErrorAsync(request, true); + return request; + } + let options = { id: aRecord.id }; let allowCallback = function() { cpmm.sendAsyncMessage("Contact:Remove", {requestID: this.getRequestId({request: request, reason: "remove"}), options: options}); @@ -898,7 +908,7 @@ ContactManager.prototype = { let allowCallback = function() { cpmm.sendAsyncMessage("Contacts:GetRevision", { - requestID: this.getRequestId(request) + requestID: this.getRequestId({ request: request }) }); }.bind(this); @@ -915,7 +925,7 @@ ContactManager.prototype = { let allowCallback = function() { cpmm.sendAsyncMessage("Contacts:GetCount", { - requestID: this.getRequestId(request) + requestID: this.getRequestId({ request: request }) }); }.bind(this); @@ -934,7 +944,8 @@ ContactManager.prototype = { "Contact:Remove:Return:OK", "Contact:Remove:Return:KO", "Contact:Changed", "PermissionPromptHelper:AskPermission:OK", - "Contacts:GetAll:Next", "Contacts:Count", + "Contacts:GetAll:Next", "Contacts:GetAll:Return:KO", + "Contacts:Count", "Contacts:Revision", "Contacts:GetRevision:Return:KO",]); }, diff --git a/dom/contacts/fallback/ContactService.jsm b/dom/contacts/fallback/ContactService.jsm index c836a7d3fb3c..17676967a2e6 100644 --- a/dom/contacts/fallback/ContactService.jsm +++ b/dom/contacts/fallback/ContactService.jsm @@ -143,7 +143,7 @@ let ContactService = { throw e; } }.bind(this), - function(aErrorMsg) { mm.sendAsyncMessage("Contacts:Find:Return:KO", { requestID: msg.cursorId, errorMsg: aErrorMsg }); }, + function(aErrorMsg) { mm.sendAsyncMessage("Contacts:GetAll:Return:KO", { requestID: msg.cursorId, errorMsg: aErrorMsg }); }, msg.findOptions, msg.cursorId); break; case "Contacts:GetAll:SendNow": @@ -192,7 +192,9 @@ let ContactService = { mm.sendAsyncMessage("Contacts:Clear:Return:OK", { requestID: msg.requestID }); this.broadcastMessage("Contact:Changed", { reason: "remove" }); }.bind(this), - function(aErrorMsg) { mm.sendAsyncMessage("Contacts:Clear:Return:KO", { requestID: msg.requestID, errorMsg: aErrorMsg }); }.bind(this) + function(aErrorMsg) { + mm.sendAsyncMessage("Contacts:Clear:Return:KO", { requestID: msg.requestID, errorMsg: aErrorMsg }); + }.bind(this) ); break; case "Contacts:GetRevision": @@ -206,7 +208,9 @@ let ContactService = { revision: revision }); }, - function(aErrorMsg) { mm.sendAsyncMessage("Contacts:GetRevision:Return:KO", { requestID: msg.requestID, errorMsg: aErrorMsg }); }.bind(this) + function(aErrorMsg) { + mm.sendAsyncMessage("Contacts:GetRevision:Return:KO", { requestID: msg.requestID, errorMsg: aErrorMsg }); + }.bind(this) ); break; case "Contacts:GetCount": @@ -220,7 +224,9 @@ let ContactService = { count: count }); }, - function(aErrorMsg) { mm.sendAsyncMessage("Contacts:Count:Return:KO", { requestID: msg.requestID, errorMsg: aErrorMsg }); }.bind(this) + function(aErrorMsg) { + mm.sendAsyncMessage("Contacts:Count:Return:KO", { requestID: msg.requestID, errorMsg: aErrorMsg }); + }.bind(this) ); break; case "Contacts:RegisterForMessages": diff --git a/dom/contacts/tests/test_contacts_basics.html b/dom/contacts/tests/test_contacts_basics.html index f2504469620f..662e87424c89 100644 --- a/dom/contacts/tests/test_contacts_basics.html +++ b/dom/contacts/tests/test_contacts_basics.html @@ -158,6 +158,7 @@ function onUnwantedSuccess() { function onFailure() { ok(false, "in on Failure!"); + next(); } function checkStr(str1, str2, msg) { @@ -801,21 +802,25 @@ var steps = [ }, function () { ok(true, "Modifying contact1"); - findResult1.impp = properties1.impp = [{value:"phil impp"}]; - req = navigator.mozContacts.save(findResult1); - req.onsuccess = function () { - var req2 = mozContacts.find({}); - req2.onsuccess = function() { - is(req2.result.length, 1, "Found exactly 1 contact."); - findResult2 = req2.result[0]; - ok(findResult2.id == sample_id1, "Same ID"); - checkContacts(findResult2, properties1); - is(findResult2.impp.length, 1, "Found exactly 1 IMS info."); - next(); + if (!findResult1) { + SpecialPowers.executeSoon(next); + } else { + findResult1.impp = properties1.impp = [{value:"phil impp"}]; + req = navigator.mozContacts.save(findResult1); + req.onsuccess = function () { + var req2 = mozContacts.find({}); + req2.onsuccess = function() { + is(req2.result.length, 1, "Found exactly 1 contact."); + findResult2 = req2.result[0]; + ok(findResult2.id == sample_id1, "Same ID"); + checkContacts(findResult2, properties1); + is(findResult2.impp.length, 1, "Found exactly 1 IMS info."); + next(); + }; + req2.onerror = onFailure; }; - req2.onerror = onFailure; - }; - req.onerror = onFailure; + req.onerror = onFailure; + } }, function() { // Android does not support published/updated fields. Skip this. @@ -861,21 +866,25 @@ var steps = [ }, function () { ok(true, "Modifying contact2"); - findResult1.impp = properties1.impp = [{value: "phil impp"}]; - req = mozContacts.save(findResult1); - req.onsuccess = function () { - var req2 = mozContacts.find({}); - req2.onsuccess = function () { - is(req2.result.length, 1, "Found exactly 1 contact."); - findResult1 = req2.result[0]; - ok(findResult1.id == sample_id1, "Same ID"); - checkContacts(findResult1, properties1); - is(findResult1.impp.length, 1, "Found exactly 1 IMS info."); - next(); - } - req2.onerror = onFailure; - }; - req.onerror = onFailure; + if (!findResult1) { + SpecialPowers.executeSoon(next); + } else { + findResult1.impp = properties1.impp = [{value: "phil impp"}]; + req = mozContacts.save(findResult1); + req.onsuccess = function () { + var req2 = mozContacts.find({}); + req2.onsuccess = function () { + is(req2.result.length, 1, "Found exactly 1 contact."); + findResult1 = req2.result[0]; + ok(findResult1.id == sample_id1, "Same ID"); + checkContacts(findResult1, properties1); + is(findResult1.impp.length, 1, "Found exactly 1 IMS info."); + next(); + } + req2.onerror = onFailure; + }; + req.onerror = onFailure; + } }, function () { ok(true, "Searching contacts by query"); @@ -924,28 +933,32 @@ var steps = [ }, function () { ok(true, "Modifying contact3"); - findResult1.email = [{value: properties1.nickname}]; - findResult1.nickname = "TEST"; - var newContact = new mozContact(); - newContact.init(findResult1); - req = mozContacts.save(newContact); - req.onsuccess = function () { - var options = {filterBy: ["email", "givenName"], - filterOp: "startsWith", - filterValue: properties1.givenName[0]}; - // One contact has it in nickname and the other in email - var req2 = mozContacts.find(options); - req2.onsuccess = function () { - is(req2.result.length, 2, "Found exactly 2 contacts."); - ok(req2.result[0].id != req2.result[1].id, "Different ID"); - next(); - } - req2.onerror = onFailure; - }; - req.onerror = onFailure; + if (!findResult1) { + SpecialPowers.executeSoon(next); + } else { + findResult1.email = [{value: properties1.nickname}]; + findResult1.nickname = "TEST"; + var newContact = new mozContact(); + newContact.init(findResult1); + req = mozContacts.save(newContact); + req.onsuccess = function () { + var options = {filterBy: ["email", "givenName"], + filterOp: "startsWith", + filterValue: properties1.givenName[0]}; + // One contact has it in nickname and the other in email + var req2 = mozContacts.find(options); + req2.onsuccess = function () { + is(req2.result.length, 2, "Found exactly 2 contacts."); + ok(req2.result[0].id != req2.result[1].id, "Different ID"); + next(); + } + req2.onerror = onFailure; + }; + req.onerror = onFailure; + } }, function () { - ok(true, "Deleting contact" + findResult1.id); + ok(true, "Deleting contact" + findResult1); req = mozContacts.remove(findResult1); req.onsuccess = function () { var req2 = mozContacts.find({}); diff --git a/dom/contacts/tests/test_contacts_blobs.html b/dom/contacts/tests/test_contacts_blobs.html index e32e51e595d4..494218edcc70 100644 --- a/dom/contacts/tests/test_contacts_blobs.html +++ b/dom/contacts/tests/test_contacts_blobs.html @@ -111,6 +111,7 @@ function onUnwantedSuccess() { function onFailure() { ok(false, "in on Failure!"); + next(); } function verifyBlob(blob1, blob2, isLast) diff --git a/dom/contacts/tests/test_contacts_getall.html b/dom/contacts/tests/test_contacts_getall.html index 60d31264238a..acc0d62a4778 100644 --- a/dom/contacts/tests/test_contacts_getall.html +++ b/dom/contacts/tests/test_contacts_getall.html @@ -56,6 +56,7 @@ let properties1 = { function onFailure() { ok(false, "in on Failure!"); + next(); } function checkStr(str1, str2, msg) { diff --git a/dom/contacts/tests/test_contacts_international.html b/dom/contacts/tests/test_contacts_international.html index 10370650fd98..358aa52126d5 100644 --- a/dom/contacts/tests/test_contacts_international.html +++ b/dom/contacts/tests/test_contacts_international.html @@ -37,6 +37,7 @@ var androidVersion = SpecialPowers.Cc['@mozilla.org/system-info;1'] function onFailure() { ok(false, "in on Failure!"); + next(); } var number1 = { @@ -167,11 +168,15 @@ var steps = [ }, function() { ok(true, "Modifying number"); - findResult1.tel[0].value = number2.local; - req = mozContacts.save(findResult1); - req.onsuccess = function () { - next(); - }; + if (!findResult1) { + SpecialPowers.executeSoon(next); + } else { + findResult1.tel[0].value = number2.local; + req = mozContacts.save(findResult1); + req.onsuccess = function () { + next(); + }; + } }, function () { ok(true, "Searching for local number"); @@ -225,7 +230,7 @@ var steps = [ }, function () { ok(true, "Deleting database"); - req = mozContacts.clear() + req = mozContacts.clear(); req.onsuccess = function () { ok(true, "Deleted the database"); next(); diff --git a/dom/contacts/tests/test_contacts_substringmatching.html b/dom/contacts/tests/test_contacts_substringmatching.html index 5eba147310f9..41b25af07d05 100644 --- a/dom/contacts/tests/test_contacts_substringmatching.html +++ b/dom/contacts/tests/test_contacts_substringmatching.html @@ -44,6 +44,7 @@ var findResult1; function onFailure() { ok(false, "in on Failure!"); + next(); } var prop = { diff --git a/dom/devicestorage/DeviceStorage.h b/dom/devicestorage/DeviceStorage.h index d8f73f9f2935..83059aa60a7d 100644 --- a/dom/devicestorage/DeviceStorage.h +++ b/dom/devicestorage/DeviceStorage.h @@ -300,6 +300,7 @@ private: static mozilla::StaticRefPtr sVolumeNameCache; #ifdef MOZ_WIDGET_GONK + nsString mLastStatus; void DispatchMountChangeEvent(nsAString& aVolumeStatus); #endif diff --git a/dom/devicestorage/nsDeviceStorage.cpp b/dom/devicestorage/nsDeviceStorage.cpp index 676069ff6595..304c40737c25 100644 --- a/dom/devicestorage/nsDeviceStorage.cpp +++ b/dom/devicestorage/nsDeviceStorage.cpp @@ -1261,14 +1261,27 @@ DeviceStorageFile::GetStatus(nsAString& aStatus) nsCOMPtr vol; nsresult rv = vs->GetVolumeByName(mStorageName, getter_AddRefs(vol)); NS_ENSURE_SUCCESS_VOID(rv); + if (!vol) { + return; + } + bool isMediaPresent; + rv = vol->GetIsMediaPresent(&isMediaPresent); + NS_ENSURE_SUCCESS_VOID(rv); + if (!isMediaPresent) { + return; + } + bool isSharing; + rv = vol->GetIsSharing(&isSharing); + NS_ENSURE_SUCCESS_VOID(rv); + if (isSharing) { + aStatus.AssignLiteral("shared"); + return; + } int32_t volState; rv = vol->GetState(&volState); NS_ENSURE_SUCCESS_VOID(rv); if (volState == nsIVolume::STATE_MOUNTED) { aStatus.AssignLiteral("available"); - } else if (volState == nsIVolume::STATE_SHARED || - volState == nsIVolume::STATE_SHAREDMNT) { - aStatus.AssignLiteral("shared"); } #endif } @@ -3159,6 +3172,12 @@ nsDOMDeviceStorage::EnumerateInternal(const nsAString& aPath, void nsDOMDeviceStorage::DispatchMountChangeEvent(nsAString& aVolumeStatus) { + if (aVolumeStatus == mLastStatus) { + // We've already sent this status, don't bother sending it again. + return; + } + mLastStatus = aVolumeStatus; + nsCOMPtr event; NS_NewDOMDeviceStorageChangeEvent(getter_AddRefs(event), this, nullptr, nullptr); diff --git a/dom/ipc/ContentChild.cpp b/dom/ipc/ContentChild.cpp index 511357c68b6e..1660278db723 100644 --- a/dom/ipc/ContentChild.cpp +++ b/dom/ipc/ContentChild.cpp @@ -1248,11 +1248,14 @@ bool ContentChild::RecvFileSystemUpdate(const nsString& aFsName, const nsString& aVolumeName, const int32_t& aState, - const int32_t& aMountGeneration) + const int32_t& aMountGeneration, + const bool& aIsMediaPresent, + const bool& aIsSharing) { #ifdef MOZ_WIDGET_GONK nsRefPtr volume = new nsVolume(aFsName, aVolumeName, aState, - aMountGeneration); + aMountGeneration, aIsMediaPresent, + aIsSharing); nsRefPtr vs = nsVolumeService::GetSingleton(); if (vs) { @@ -1264,6 +1267,8 @@ ContentChild::RecvFileSystemUpdate(const nsString& aFsName, unused << aVolumeName; unused << aState; unused << aMountGeneration; + unused << aIsMediaPresent; + unused << aIsSharing; #endif return true; } diff --git a/dom/ipc/ContentChild.h b/dom/ipc/ContentChild.h index 127fad3de4f0..4db71103ffad 100644 --- a/dom/ipc/ContentChild.h +++ b/dom/ipc/ContentChild.h @@ -208,7 +208,9 @@ public: virtual bool RecvFileSystemUpdate(const nsString& aFsName, const nsString& aVolumeName, const int32_t& aState, - const int32_t& aMountGeneration); + const int32_t& aMountGeneration, + const bool& aIsMediaPresent, + const bool& aIsSharing); virtual bool RecvNotifyProcessPriorityChanged(const hal::ProcessPriority& aPriority); virtual bool RecvMinimizeMemoryUsage(); diff --git a/dom/ipc/ContentParent.cpp b/dom/ipc/ContentParent.cpp index 6e4571ce0792..8d828b506814 100644 --- a/dom/ipc/ContentParent.cpp +++ b/dom/ipc/ContentParent.cpp @@ -1676,14 +1676,19 @@ ContentParent::Observe(nsISupports* aSubject, nsString mountPoint; int32_t state; int32_t mountGeneration; + bool isMediaPresent; + bool isSharing; vol->GetName(volName); vol->GetMountPoint(mountPoint); vol->GetState(&state); vol->GetMountGeneration(&mountGeneration); + vol->GetIsMediaPresent(&isMediaPresent); + vol->GetIsSharing(&isSharing); unused << SendFileSystemUpdate(volName, mountPoint, state, - mountGeneration); + mountGeneration, isMediaPresent, + isSharing); } #endif #ifdef ACCESSIBILITY diff --git a/dom/ipc/PContent.ipdl b/dom/ipc/PContent.ipdl index d856baa55d1c..89763a664a8b 100644 --- a/dom/ipc/PContent.ipdl +++ b/dom/ipc/PContent.ipdl @@ -269,7 +269,8 @@ child: nsCString reasons); FileSystemUpdate(nsString fsName, nsString mountPoint, int32_t fsState, - int32_t mountGeneration); + int32_t mountGeneration, bool isMediaPresent, + bool isSharing); NotifyProcessPriorityChanged(ProcessPriority priority); MinimizeMemoryUsage(); diff --git a/dom/mobilemessage/src/gonk/MmsPduHelper.jsm b/dom/mobilemessage/src/gonk/MmsPduHelper.jsm index d9b5c33ca20c..bf9b8edd8a78 100644 --- a/dom/mobilemessage/src/gonk/MmsPduHelper.jsm +++ b/dom/mobilemessage/src/gonk/MmsPduHelper.jsm @@ -13,6 +13,16 @@ Cu.import("resource://gre/modules/mms_consts.js"); let DEBUG; // set to true to see debug messages +this.MMS_VERSION = (function () { + Cu.import("resource://gre/modules/Services.jsm"); + + try { + return Services.prefs.getIntPref("dom.mms.version"); + } catch(ex) {} + + return MMS_VERSION_1_3; +})(); + this.translatePduErrorToStatus = function translatePduErrorToStatus(error) { if (error == MMS_PDU_ERROR_OK) { return MMS_PDU_STATUS_RETRIEVED; @@ -1699,6 +1709,9 @@ if (DEBUG) { } this.EXPORTED_SYMBOLS = ALL_CONST_SYMBOLS.concat([ + // Constant values + "MMS_VERSION", + // Utility functions "translatePduErrorToStatus", diff --git a/dom/mobilemessage/src/gonk/MmsService.js b/dom/mobilemessage/src/gonk/MmsService.js index a07693801805..284a107f20c1 100644 --- a/dom/mobilemessage/src/gonk/MmsService.js +++ b/dom/mobilemessage/src/gonk/MmsService.js @@ -1161,6 +1161,12 @@ AcknowledgeTransaction.prototype = { * MmsService */ function MmsService() { + if (DEBUG) { + let macro = (MMS.MMS_VERSION >> 4) & 0x0f; + let minor = MMS.MMS_VERSION & 0x0f; + debug("Running protocol version: " + macro + "." + minor); + } + // TODO: bug 810084 - support application identifier } MmsService.prototype = { diff --git a/dom/mobilemessage/src/gonk/mms_consts.js b/dom/mobilemessage/src/gonk/mms_consts.js index 9db577a99011..7969949b379e 100644 --- a/dom/mobilemessage/src/gonk/mms_consts.js +++ b/dom/mobilemessage/src/gonk/mms_consts.js @@ -29,9 +29,10 @@ this.MMS_PDU_TYPE_DELETE_CONF = 149; this.MMS_PDU_TYPE_CANCEL_REQ = 150; this.MMS_PDU_TYPE_CANCEL_CONF = 151; -// MMS version 1.3 +// MMS version // @see OMA-TS-MMS_ENC-V1_3-20110913-A clause 7.3.34 -this.MMS_VERSION = (0x01 << 4) | 0x03; +this.MMS_VERSION_1_1 = (0x01 << 4) | 0x01; +this.MMS_VERSION_1_3 = (0x01 << 4) | 0x03; // Common Status Values this.MMS_PDU_ERROR_OK = 128; diff --git a/dom/mobilemessage/tests/marionette/manifest.ini b/dom/mobilemessage/tests/marionette/manifest.ini index 367d4ba998c3..17457a849406 100644 --- a/dom/mobilemessage/tests/marionette/manifest.ini +++ b/dom/mobilemessage/tests/marionette/manifest.ini @@ -16,8 +16,7 @@ qemu = true [test_getmessages.js] [test_filter_date.js] [test_filter_date_notfound.js] -[test_filter_number_single.js] -[test_filter_number_multiple.js] +[test_filter_number.js] [test_filter_received.js] [test_filter_sent.js] [test_filter_read.js] diff --git a/dom/mobilemessage/tests/marionette/test_filter_number.js b/dom/mobilemessage/tests/marionette/test_filter_number.js new file mode 100644 index 000000000000..3ff3d1bc8948 --- /dev/null +++ b/dom/mobilemessage/tests/marionette/test_filter_number.js @@ -0,0 +1,201 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +MARIONETTE_TIMEOUT = 60000; + +const NUM_THREADS = 10; +const REMOTE_NATIONAL_NUMBER = "555531555"; +const REMOTE_INTERNATIONAL_NUMBER = "+1" + REMOTE_NATIONAL_NUMBER; + +SpecialPowers.addPermission("sms", true, document); +SpecialPowers.setBoolPref("dom.sms.enabled", true); + +let pendingEmulatorCmdCount = 0; +function sendSmsToEmulator(from, text) { + ++pendingEmulatorCmdCount; + + let cmd = "sms send " + from + " " + text; + runEmulatorCmd(cmd, function (result) { + --pendingEmulatorCmdCount; + + is(result[0], "OK", "Emulator response"); + }); +} + +let tasks = { + // List of test fuctions. Each of them should call |tasks.next()| when + // completed or |tasks.finish()| to jump to the last one. + _tasks: [], + _nextTaskIndex: 0, + + push: function push(func) { + this._tasks.push(func); + }, + + next: function next() { + let index = this._nextTaskIndex++; + let task = this._tasks[index]; + try { + task(); + } catch (ex) { + ok(false, "test task[" + index + "] throws: " + ex); + // Run last task as clean up if possible. + if (index != this._tasks.length - 1) { + this.finish(); + } + } + }, + + finish: function finish() { + this._tasks[this._tasks.length - 1](); + }, + + run: function run() { + this.next(); + } +}; + +let manager; +function getAllMessages(callback, filter, reverse) { + if (!filter) { + filter = new MozSmsFilter; + } + let messages = []; + let request = manager.getMessages(filter, reverse || false); + request.onsuccess = function(event) { + if (request.result) { + messages.push(request.result); + request.continue(); + return; + } + + window.setTimeout(callback.bind(null, messages), 0); + } +} + +function deleteAllMessages() { + log("Deleting all messages."); + getAllMessages(function deleteAll(messages) { + let message = messages.shift(); + if (!message) { + ok(true, "all messages deleted"); + tasks.next(); + return; + } + + let request = manager.delete(message.id); + request.onsuccess = deleteAll.bind(null, messages); + request.onerror = function (event) { + ok(false, "failed to delete all messages"); + tasks.finish(); + } + }); +} + +function checkMessage(needle, secondary) { + log(" Verifying " + needle); + + let filter = new MozSmsFilter(); + filter.numbers = [needle]; + getAllMessages(function (messages) { + is(messages.length, 2, "should have exactly 2 messages"); + + // Check the messages are sent to/received from either 'needle' or + // 'secondary' number. + let validNumbers = [needle, secondary]; + for (let message of messages) { + let number = (message.delivery === "received") ? message.sender + : message.receiver; + let index = validNumbers.indexOf(number); + ok(index >= 0, "message.number"); + validNumbers.splice(index, 1); // Remove from validNumbers. + } + + tasks.next(); + }, filter); +} + +tasks.push(function verifyInitialState() { + log("Verifying initial state."); + manager = window.navigator.mozMobileMessage; + ok(manager instanceof MozMobileMessageManager, + "manager is instance of " + manager.constructor); + tasks.next(); +}); + +tasks.push(deleteAllMessages); + +/** + * Populate database with messages to being tests. We'll have NUM_THREADS + * sent and received messages. + * + * send to "+15555315550" + * receive from "5555315550", count = 1 + * + * send to "+15555315551" + * receive from "5555315551", count = 2 + * ... + * send to "+15555315559" + * receive from "5555315559", count = 10 + */ +tasks.push(function populateMessages() { + log("Populating messages."); + let count = 0; + + function sendMessage(iter) { + let request = manager.send(REMOTE_INTERNATIONAL_NUMBER + iter, + "Nice to meet you"); + request.onsuccess = function onRequestSuccess(event) { + sendSmsToEmulator(REMOTE_NATIONAL_NUMBER + iter, + "Nice to meet you, too"); + } + request.onerror = function onRequestError(event) { + tasks.finish(); + } + } + + manager.addEventListener("received", function onReceived(event) { + ++count; + if (count < NUM_THREADS) { + sendMessage(count); + } else { + manager.removeEventListener("received", onReceived); + tasks.next(); + } + }); + + sendMessage(count); +}); + +tasks.push(function () { + log("Verifying number of messages in database"); + getAllMessages(function (messages) { + is(messages.length, NUM_THREADS * 2, + "should have exactly " + (NUM_THREADS * 2) + " messages"); + + tasks.next(); + }); +}); + +for (let iter = 0; iter < NUM_THREADS; iter++) { + let national = REMOTE_NATIONAL_NUMBER + iter; + let international = REMOTE_INTERNATIONAL_NUMBER + iter; + tasks.push(checkMessage.bind(null, national, international)); + tasks.push(checkMessage.bind(null, international, national)); +} + +tasks.push(deleteAllMessages); + +// WARNING: All tasks should be pushed before this!!! +tasks.push(function cleanUp() { + if (pendingEmulatorCmdCount) { + window.setTimeout(cleanUp, 100); + return; + } + + SpecialPowers.removePermission("sms", document); + SpecialPowers.clearUserPref("dom.sms.enabled"); + finish(); +}); + +tasks.run(); diff --git a/dom/mobilemessage/tests/marionette/test_filter_number_multiple.js b/dom/mobilemessage/tests/marionette/test_filter_number_multiple.js deleted file mode 100644 index 60dd9ef117d7..000000000000 --- a/dom/mobilemessage/tests/marionette/test_filter_number_multiple.js +++ /dev/null @@ -1,249 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/publicdomain/zero/1.0/ */ - -MARIONETTE_TIMEOUT = 60000; - -SpecialPowers.addPermission("sms", true, document); -SpecialPowers.setBoolPref("dom.sms.enabled", true); - -let manager = window.navigator.mozMobileMessage; -let numberMsgs = 10; -let smsList = new Array(); -let defaultRemoteNumber = "+15552227777"; - -function verifyInitialState() { - log("Verifying initial state."); - ok(manager instanceof MozMobileMessageManager, - "manager is instance of " + manager.constructor); - // Ensure test is starting clean with no existing sms messages - deleteAllMsgs(sendSms); -} - -function deleteAllMsgs(nextFunction) { - // Check for any existing SMS messages, if any are found delete them - let msgList = new Array(); - let filter = new MozSmsFilter; - - let cursor = manager.getMessages(filter, false); - ok(cursor instanceof DOMCursor, - "cursor is instanceof " + cursor.constructor); - - cursor.onsuccess = function(event) { - // Check if message was found - if (cursor.result) { - msgList.push(cursor.result.id); - // Now get next message in the list - cursor.continue(); - } else { - // No (more) messages found - if (msgList.length) { - log("Found " + msgList.length + " SMS messages to delete."); - deleteMsgs(msgList, nextFunction); - } else { - log("No SMS messages found."); - nextFunction(); - } - } - }; - - cursor.onerror = function(event) { - log("Received 'onerror' event."); - ok(event.target.error, "domerror obj"); - log("manager.getMessages error: " + event.target.error.name); - ok(false,"Could not get SMS messages"); - cleanUp(); - }; -} - -function deleteMsgs(msgList, nextFunction) { - // Delete the SMS messages specified in the given list - let smsId = msgList.shift(); - - log("Deleting SMS (id: " + smsId + ")."); - let request = manager.delete(smsId); - ok(request instanceof DOMRequest, - "request is instanceof " + request.constructor); - - request.onsuccess = function(event) { - log("Received 'onsuccess' smsrequest event."); - if (event.target.result) { - // Message deleted, continue until none are left - if (msgList.length) { - deleteMsgs(msgList, nextFunction); - } else { - log("Finished deleting SMS messages."); - nextFunction(); - } - } else { - log("SMS delete failed."); - ok(false,"manager.delete request returned false"); - cleanUp(); - } - }; - - request.onerror = function(event) { - log("Received 'onerror' smsrequest event."); - ok(event.target.error, "domerror obj"); - ok(false, "manager.delete request returned unexpected error: " - + event.target.error.name ); - cleanUp(); - }; -} - -function sendSms() { - // Send an SMS to a unique number that will fall outside of the filter - let gotSmsSent = false; - let gotRequestSuccess = false; - let remoteNumber = "+15558120649"; - let text = "Outgoing SMS brought to you by Firefox OS!"; - - log("Sending an SMS."); - - manager.onsent = function(event) { - log("Received 'onsent' event."); - gotSmsSent = true; - log("Sent SMS (id: " + event.message.id + ")."); - if (gotSmsSent && gotRequestSuccess) { - simulateIncomingSms(); - } - }; - - let request = manager.send(remoteNumber, text); - ok(request instanceof DOMRequest, - "request is instanceof " + request.constructor); - - request.onsuccess = function(event) { - log("Received 'onsuccess' smsrequest event."); - if (event.target.result) { - gotRequestSuccess = true; - if (gotSmsSent && gotRequestSuccess) { - simulateIncomingSms(); - } - } else { - log("smsrequest returned false for manager.send"); - ok(false,"SMS send failed"); - cleanUp(); - } - }; - - request.onerror = function(event) { - log("Received 'onerror' smsrequest event."); - ok(event.target.error, "domerror obj"); - ok(false, "manager.send request returned unexpected error: " - + event.target.error.name ); - cleanUp(); - }; -} - -function simulateIncomingSms(remoteNumber) { - // Simulate incoming SMS messages from specified (or default) remote number - let text = "Incoming SMS number " + (smsList.length + 1); - remoteNumber = typeof remoteNumber !== 'undefined' - ? remoteNumber : defaultRemoteNumber; - - log("Simulating incoming SMS number " + (smsList.length + 1) + " of " - + (numberMsgs - 1) + "."); - - // Simulate incoming SMS sent from remoteNumber to our emulator - rcvdEmulatorCallback = false; - runEmulatorCmd("sms send " + remoteNumber + " " + text, function(result) { - is(result[0], "OK", "emulator callback"); - rcvdEmulatorCallback = true; - }); -} - -manager.onreceived = function onreceived(event) { - // Callback for incoming SMS - log("Received 'onreceived' sms event."); - let incomingSms = event.message; - log("Received SMS (id: " + incomingSms.id + ")."); - - smsList.push(incomingSms); - - // Wait for emulator to catch up before continuing - waitFor(nextRep,function() { - return(rcvdEmulatorCallback); - }); -}; - -function nextRep() { - // Keep simulating incoming messages until have received specified number - let secondNumber = "+15559990000"; - if (smsList.length < (numberMsgs - 1)) { - // Have every other SMS be from different number, so filter won't find all - if (smsList.length % 2) { - simulateIncomingSms(secondNumber); - } else { - simulateIncomingSms(); - } - } else { - getMsgs(secondNumber); - } -} - -function getMsgs(secondNumber) { - // Set the filter and test it via getMessages - var filter = new MozSmsFilter(); - let foundSmsList = new Array(); - - // Set filter for default and second number - filter.numbers = new Array(defaultRemoteNumber, secondNumber); - - log("Getting the SMS messages with numbers " + defaultRemoteNumber + " and " - + secondNumber + "."); - let cursor = manager.getMessages(filter, false); - ok(cursor instanceof DOMCursor, - "cursor is instanceof " + cursor.constructor); - - cursor.onsuccess = function(event) { - log("Received 'onsuccess' event."); - - if (cursor.result) { - // Another message found - log("Got SMS (id: " + cursor.result.id + ")."); - // Store found message - foundSmsList.push(cursor.result); - // Now get next message in the list - cursor.continue(); - } else { - // No more messages; ensure correct number of SMS messages were found - if (foundSmsList.length == smsList.length) { - log("SMS getMessages returned " + foundSmsList.length + - " messages as expected."); - verifyFoundMsgs(foundSmsList); - } else { - log("SMS getMessages returned " + foundSmsList.length + - " messages, but expected " + smsList.length + "."); - ok(false, "Incorrect number of messages returned by manager.getMessages"); - deleteAllMsgs(cleanUp); - } - } - }; - - cursor.onerror = function(event) { - log("Received 'onerror' event."); - ok(event.target.error, "domerror obj"); - log("manager.getMessages error: " + event.target.error.name); - ok(false,"Could not get SMS messages"); - cleanUp(); - }; -} - -function verifyFoundMsgs(foundSmsList) { - // Verify the SMS messages returned by getMessages are the correct ones - for (var x = 0; x < foundSmsList.length; x++) { - is(foundSmsList[x].id, smsList[x].id, "id"); - is(foundSmsList[x].sender, smsList[x].sender, "number"); - } - deleteAllMsgs(cleanUp); -} - -function cleanUp() { - manager.onreceived = null; - SpecialPowers.removePermission("sms", document); - SpecialPowers.clearUserPref("dom.sms.enabled"); - finish(); -} - -// Start the test -verifyInitialState(); diff --git a/dom/mobilemessage/tests/marionette/test_filter_number_single.js b/dom/mobilemessage/tests/marionette/test_filter_number_single.js deleted file mode 100644 index 382abb184c50..000000000000 --- a/dom/mobilemessage/tests/marionette/test_filter_number_single.js +++ /dev/null @@ -1,207 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/publicdomain/zero/1.0/ */ - -MARIONETTE_TIMEOUT = 60000; - -SpecialPowers.addPermission("sms", true, document); -SpecialPowers.setBoolPref("dom.sms.enabled", true); - -let manager = window.navigator.mozMobileMessage; -let numberMsgs = 10; -let smsList = new Array(); -let defaultRemoteNumber = "+15552227777"; - -function verifyInitialState() { - log("Verifying initial state."); - ok(manager instanceof MozMobileMessageManager, - "manager is instance of " + manager.constructor); - // Ensure test is starting clean with no existing sms messages - deleteAllMsgs(simulateIncomingSms); -} - -function deleteAllMsgs(nextFunction) { - // Check for any existing SMS messages, if any are found delete them - let msgList = new Array(); - let filter = new MozSmsFilter; - - let cursor = manager.getMessages(filter, false); - ok(cursor instanceof DOMCursor, - "cursor is instanceof " + cursor.constructor); - - cursor.onsuccess = function(event) { - // Check if message was found - if (cursor.result) { - msgList.push(cursor.result.id); - // Now get next message in the list - cursor.continue(); - } else { - // No (more) messages found - if (msgList.length) { - log("Found " + msgList.length + " SMS messages to delete."); - deleteMsgs(msgList, nextFunction); - } else { - log("No SMS messages found."); - nextFunction(); - } - } - }; - - cursor.onerror = function(event) { - log("Received 'onerror' event."); - ok(event.target.error, "domerror obj"); - log("manager.getMessages error: " + event.target.error.name); - ok(false,"Could not get SMS messages"); - cleanUp(); - }; -} - -function deleteMsgs(msgList, nextFunction) { - // Delete the SMS messages specified in the given list - let smsId = msgList.shift(); - - log("Deleting SMS (id: " + smsId + ")."); - let request = manager.delete(smsId); - ok(request instanceof DOMRequest, - "request is instanceof " + request.constructor); - - request.onsuccess = function(event) { - log("Received 'onsuccess' smsrequest event."); - if (event.target.result) { - // Message deleted, continue until none are left - if (msgList.length) { - deleteMsgs(msgList, nextFunction); - } else { - log("Finished deleting SMS messages."); - nextFunction(); - } - } else { - log("SMS delete failed."); - ok(false,"manager.delete request returned false"); - cleanUp(); - } - }; - - request.onerror = function(event) { - log("Received 'onerror' smsrequest event."); - ok(event.target.error, "domerror obj"); - ok(false, "manager.delete request returned unexpected error: " - + event.target.error.name ); - cleanUp(); - }; -} - -function simulateIncomingSms(remoteNumber) { - // Simulate incoming SMS messages from specified (or default) remote number - let text = "Incoming SMS number " + (smsList.length + 1); - remoteNumber = typeof remoteNumber !== 'undefined' - ? remoteNumber : defaultRemoteNumber; - - log("Simulating incoming SMS number " + (smsList.length + 1) + " of " - + numberMsgs + "."); - - // Simulate incoming sms sent from remoteNumber to our emulator - rcvdEmulatorCallback = false; - runEmulatorCmd("sms send " + remoteNumber + " " + text, function(result) { - is(result[0], "OK", "emulator callback"); - rcvdEmulatorCallback = true; - }); -} - -manager.onreceived = function onreceived(event) { - // Callback for incoming SMS - log("Received 'onreceived' sms event."); - let incomingSms = event.message; - log("Received SMS (id: " + incomingSms.id + ")."); - - smsList.push(incomingSms); - - // Wait for emulator to catch up before continuing - waitFor(nextRep,function() { - return(rcvdEmulatorCallback); - }); -}; - -function nextRep() { - // Keep simulating incoming messages until have received specified number - if (smsList.length < numberMsgs) { - // Have every other sms be from different number, so filter won't find all - if (smsList.length % 2) { - simulateIncomingSms("+15559990000"); - } else { - simulateIncomingSms(); - } - } else { - getMsgs(); - } -} - -function getMsgs() { - // Set the filter and test it via getMessages - var filter = new MozSmsFilter(); - let foundSmsList = new Array(); - - // Going to filter for one number only, so set our expected SMS array - smsList = smsList.filter(function(i) { - return i.sender != defaultRemoteNumber ? false: true; - }); - - // Set filter for default remote number - filter.numbers = new Array(defaultRemoteNumber); - - log("Getting the SMS messages from sender " + defaultRemoteNumber + "."); - let cursor = manager.getMessages(filter, false); - ok(cursor instanceof DOMCursor, - "cursor is instanceof " + cursor.constructor); - - cursor.onsuccess = function(event) { - log("Received 'onsuccess' event."); - - if (cursor.result) { - // Another message found - log("Got SMS (id: " + cursor.result.id + ")."); - // Store found message - foundSmsList.push(cursor.result); - // Now get next message in the list - cursor.continue(); - } else { - // No more messages; ensure correct number of SMS messages were found - if (foundSmsList.length == smsList.length) { - log("SMS getMessages returned " + foundSmsList.length + - " messages as expected."); - verifyFoundMsgs(foundSmsList); - } else { - log("SMS getMessages returned " + foundSmsList.length + - " messages, but expected " + smsList.length + "."); - ok(false, "Incorrect number of messages returned by manager.getMessages"); - deleteAllMsgs(cleanUp); - } - } - }; - - cursor.onerror = function(event) { - log("Received 'onerror' event."); - ok(event.target.error, "domerror obj"); - log("manager.getMessages error: " + event.target.error.name); - ok(false,"Could not get SMS messages"); - cleanUp(); - }; -} - -function verifyFoundMsgs(foundSmsList) { - // Verify the SMS messages returned by getMessages are the correct ones - for (var x = 0; x < foundSmsList.length; x++) { - is(foundSmsList[x].id, smsList[x].id, "id"); - is(foundSmsList[x].sender, smsList[x].sender, "number"); - } - deleteAllMsgs(cleanUp); -} - -function cleanUp() { - manager.onreceived = null; - SpecialPowers.removePermission("sms", document); - SpecialPowers.clearUserPref("dom.sms.enabled"); - finish(); -} - -// Start the test -verifyInitialState(); diff --git a/dom/system/gonk/AutoMounter.cpp b/dom/system/gonk/AutoMounter.cpp index 09006519debc..190ced792d40 100644 --- a/dom/system/gonk/AutoMounter.cpp +++ b/dom/system/gonk/AutoMounter.cpp @@ -443,6 +443,7 @@ AutoMounter::UpdateState() // Volume is mounted, we need to unmount before // we can share. LOG("UpdateState: Unmounting %s", vol->NameStr()); + vol->SetIsSharing(true); vol->StartUnmount(mResponseCallback); return; // UpdateState will be called again when the Unmount command completes } diff --git a/dom/system/gonk/Volume.cpp b/dom/system/gonk/Volume.cpp index e2b00a307aee..532be04c078d 100644 --- a/dom/system/gonk/Volume.cpp +++ b/dom/system/gonk/Volume.cpp @@ -59,11 +59,18 @@ Volume::Volume(const nsCSubstring& aName) mMountGeneration(-1), mMountLocked(true), // Needs to agree with nsVolume::nsVolume mSharingEnabled(false), - mCanBeShared(true) + mCanBeShared(true), + mIsSharing(false) { DBG("Volume %s: created", NameStr()); } +void +Volume::SetIsSharing(bool aIsSharing) +{ + mIsSharing = aIsSharing; +} + void Volume::SetMediaPresent(bool aMediaPresent) { @@ -133,9 +140,29 @@ Volume::SetState(Volume::STATE aNewState) StateStr(aNewState), mEventObserverList.Length()); } - if (aNewState == nsIVolume::STATE_NOMEDIA) { - // Cover the startup case where we don't get insertion/removal events - mMediaPresent = false; + switch (aNewState) { + case nsIVolume::STATE_NOMEDIA: + // Cover the startup case where we don't get insertion/removal events + mMediaPresent = false; + mIsSharing = false; + break; + + case nsIVolume::STATE_MOUNTED: + case nsIVolume::STATE_FORMATTING: + mIsSharing = false; + break; + + case nsIVolume::STATE_SHARED: + case nsIVolume::STATE_SHAREDMNT: + // Covers startup cases. Normally, mIsSharing would be set to true + // when we issue the command to initiate the sharing process, but + // it's conceivable that a volume could already be in a shared state + // when b2g starts. + mIsSharing = true; + break; + + default: + break; } mState = aNewState; mEventObserverList.Broadcast(this); diff --git a/dom/system/gonk/Volume.h b/dom/system/gonk/Volume.h index 68a35f7989d5..02b3b4d8e134 100644 --- a/dom/system/gonk/Volume.h +++ b/dom/system/gonk/Volume.h @@ -47,6 +47,7 @@ public: bool MediaPresent() const { return mMediaPresent; } bool CanBeShared() const { return mCanBeShared; } bool IsSharingEnabled() const { return mCanBeShared && mSharingEnabled; } + bool IsSharing() const { return mIsSharing; } void SetSharingEnabled(bool aSharingEnabled); @@ -71,6 +72,7 @@ private: void StartShare(VolumeResponseCallback* aCallback); void StartUnshare(VolumeResponseCallback* aCallback); + void SetIsSharing(bool aIsSharing); void SetState(STATE aNewState); void SetMediaPresent(bool aMediaPresent); void SetMountPoint(const nsCSubstring& aMountPoint); @@ -90,6 +92,7 @@ private: bool mMountLocked; bool mSharingEnabled; bool mCanBeShared; + bool mIsSharing; static EventObserverList mEventObserverList; }; diff --git a/dom/system/gonk/nsIVolume.idl b/dom/system/gonk/nsIVolume.idl index c7170fbb04ba..f8b21c5e4fcb 100644 --- a/dom/system/gonk/nsIVolume.idl +++ b/dom/system/gonk/nsIVolume.idl @@ -5,7 +5,7 @@ #include "nsISupports.idl" #include "nsIVolumeStat.idl" -[scriptable, uuid(4b5bd562-bd05-4658-ab0f-f668a9e25fb5)] +[scriptable, uuid(e476e7ea-5cde-4d5a-b00d-d60daad76398)] interface nsIVolume : nsISupports { // These MUST match the states from android's system/vold/Volume.h header @@ -48,6 +48,20 @@ interface nsIVolume : nsISupports // Determines if a mountlock is currently being held against this volume. readonly attribute boolean isMountLocked; + // Determines if media is actually present or not. Note, that when an sdcard + // is ejected, it may go through several tranistory states before finally + // arriving at STATE_NOMEDIA. So isMediaPresent may be false even when the + // current state isn't STATE_NOMEDIA. + readonly attribute boolean isMediaPresent; + + // Determines if the volume is currently being shared. This covers off + // more than just state == STATE_SHARED. isSharing will return true from the + // time that the volume leaves the mounted state, until it gets back to + // mounted, nomedia, or formatting states. This attribute is to allow + // device storage to suppress unwanted 'unavailable' status when + // transitioning from mounted to sharing and back again. + readonly attribute boolean isSharing; + nsIVolumeStat getStats(); // Whether this is a fake volume. diff --git a/dom/system/gonk/nsVolume.cpp b/dom/system/gonk/nsVolume.cpp index c0791364adc7..67061a5d1d05 100644 --- a/dom/system/gonk/nsVolume.cpp +++ b/dom/system/gonk/nsVolume.cpp @@ -51,7 +51,9 @@ nsVolume::nsVolume(const Volume* aVolume) mState(aVolume->State()), mMountGeneration(aVolume->MountGeneration()), mMountLocked(aVolume->IsMountLocked()), - mIsFake(false) + mIsFake(false), + mIsMediaPresent(aVolume->MediaPresent()), + mIsSharing(aVolume->IsSharing()) { } @@ -96,12 +98,24 @@ bool nsVolume::Equals(nsIVolume* aVolume) return true; } +NS_IMETHODIMP nsVolume::GetIsMediaPresent(bool *aIsMediaPresent) +{ + *aIsMediaPresent = mIsMediaPresent; + return NS_OK; +} + NS_IMETHODIMP nsVolume::GetIsMountLocked(bool *aIsMountLocked) { *aIsMountLocked = mMountLocked; return NS_OK; } +NS_IMETHODIMP nsVolume::GetIsSharing(bool *aIsSharing) +{ + *aIsSharing = mIsSharing; + return NS_OK; +} + NS_IMETHODIMP nsVolume::GetName(nsAString& aName) { aName = mName; @@ -154,9 +168,11 @@ void nsVolume::LogState() const { if (mState == nsIVolume::STATE_MOUNTED) { - LOG("nsVolume: %s state %s @ '%s' gen %d locked %d fake %d", + LOG("nsVolume: %s state %s @ '%s' gen %d locked %d fake %d " + "media %d sharing %d", NameStr().get(), StateStr(), MountPointStr().get(), - MountGeneration(), (int)IsMountLocked(), (int)IsFake()); + MountGeneration(), (int)IsMountLocked(), (int)IsFake(), + (int)IsMediaPresent(), (int)IsSharing()); return; } @@ -171,6 +187,8 @@ void nsVolume::Set(nsIVolume* aVolume) aVolume->GetMountPoint(mMountPoint); aVolume->GetState(&mState); aVolume->GetIsFake(&mIsFake); + aVolume->GetIsMediaPresent(&mIsMediaPresent); + aVolume->GetIsSharing(&mIsSharing); int32_t volMountGeneration; aVolume->GetMountGeneration(&volMountGeneration); @@ -237,6 +255,17 @@ nsVolume::UpdateMountLock(bool aMountLocked) MountGeneration(), aMountLocked)); } +void +nsVolume::SetIsFake(bool aIsFake) +{ + mIsFake = aIsFake; + if (mIsFake) { + // The media is always present for fake volumes. + mIsMediaPresent = true; + MOZ_ASSERT(!mIsSharing); + } +} + void nsVolume::SetState(int32_t aState) { diff --git a/dom/system/gonk/nsVolume.h b/dom/system/gonk/nsVolume.h index b2f85fdb1a2f..b77ae3a4be23 100644 --- a/dom/system/gonk/nsVolume.h +++ b/dom/system/gonk/nsVolume.h @@ -25,15 +25,19 @@ public: // This constructor is used by the UpdateVolumeRunnable constructor nsVolume(const Volume* aVolume); - // This constructor is used by ContentChild::RecvFileSystemUpdate + // This constructor is used by ContentChild::RecvFileSystemUpdate which is + // used to update the volume cache maintained in the child process. nsVolume(const nsAString& aName, const nsAString& aMountPoint, - const int32_t& aState, const int32_t& aMountGeneration) + const int32_t& aState, const int32_t& aMountGeneration, + const bool& aIsMediaPresent, const bool& aIsSharing) : mName(aName), mMountPoint(aMountPoint), mState(aState), mMountGeneration(aMountGeneration), mMountLocked(false), - mIsFake(false) + mIsFake(false), + mIsMediaPresent(aIsMediaPresent), + mIsSharing(aIsSharing) { } @@ -44,7 +48,9 @@ public: mState(STATE_INIT), mMountGeneration(-1), mMountLocked(true), // Needs to agree with Volume::Volume - mIsFake(false) + mIsFake(false), + mIsMediaPresent(false), + mIsSharing(false) { } @@ -75,7 +81,9 @@ private: void UpdateMountLock(bool aMountLocked); bool IsFake() const { return mIsFake; } - void SetIsFake(bool aIsFake) { mIsFake = aIsFake; } + bool IsMediaPresent() const { return mIsMediaPresent; } + bool IsSharing() const { return mIsSharing; } + void SetIsFake(bool aIsFake); void SetState(int32_t aState); nsString mName; @@ -84,6 +92,8 @@ private: int32_t mMountGeneration; bool mMountLocked; bool mIsFake; + bool mIsMediaPresent; + bool mIsSharing; }; } // system diff --git a/dom/system/gonk/nsVolumeService.cpp b/dom/system/gonk/nsVolumeService.cpp index 1e9cc29fa08e..8e87c0008bba 100644 --- a/dom/system/gonk/nsVolumeService.cpp +++ b/dom/system/gonk/nsVolumeService.cpp @@ -246,7 +246,9 @@ nsVolumeService::CreateOrGetVolumeByPath(const nsAString& aPath, nsIVolume** aRe // from the pathname, so that the caller can determine the volume size. nsCOMPtr vol = new nsVolume(NS_LITERAL_STRING("fake"), aPath, nsIVolume::STATE_MOUNTED, - -1 /*generation*/); + -1 /* generation */, + true /* isMediaPresent*/, + false /* isSharing */); vol.forget(aResult); return NS_OK; } @@ -375,7 +377,10 @@ NS_IMETHODIMP nsVolumeService::CreateFakeVolume(const nsAString& name, const nsAString& path) { if (XRE_GetProcessType() == GeckoProcessType_Default) { - nsRefPtr vol = new nsVolume(name, path, nsIVolume::STATE_INIT, -1); + nsRefPtr vol = new nsVolume(name, path, nsIVolume::STATE_INIT, + -1 /* mountGeneration */, + true /* isMediaPresent */, + false /* isSharing */); vol->SetIsFake(true); vol->LogState(); UpdateVolume(vol.get()); @@ -425,9 +430,11 @@ public: NS_IMETHOD Run() { MOZ_ASSERT(NS_IsMainThread()); - DBG("UpdateVolumeRunnable::Run '%s' state %s gen %d locked %d", + DBG("UpdateVolumeRunnable::Run '%s' state %s gen %d locked %d " + "media %d sharing %d", mVolume->NameStr().get(), mVolume->StateStr(), - mVolume->MountGeneration(), (int)mVolume->IsMountLocked()); + mVolume->MountGeneration(), (int)mVolume->IsMountLocked(), + (int)mVolume->IsMediaPresent(), mVolume->IsSharing()); mVolumeService->UpdateVolume(mVolume); mVolumeService = nullptr; @@ -443,9 +450,11 @@ private: void nsVolumeService::UpdateVolumeIOThread(const Volume* aVolume) { - DBG("UpdateVolumeIOThread: Volume '%s' state %s mount '%s' gen %d locked %d", + DBG("UpdateVolumeIOThread: Volume '%s' state %s mount '%s' gen %d locked %d " + "media %d sharing %d", aVolume->NameStr(), aVolume->StateStr(), aVolume->MountPoint().get(), - aVolume->MountGeneration(), (int)aVolume->IsMountLocked()); + aVolume->MountGeneration(), (int)aVolume->IsMountLocked(), + (int)aVolume->IsMediaPresent(), (int)aVolume->IsSharing()); MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop()); NS_DispatchToMainThread(new UpdateVolumeRunnable(this, aVolume)); } diff --git a/dom/system/gonk/ril_worker.js b/dom/system/gonk/ril_worker.js index bdcdb7d61324..53f4611b5ecc 100644 --- a/dom/system/gonk/ril_worker.js +++ b/dom/system/gonk/ril_worker.js @@ -2363,9 +2363,25 @@ let RIL = { * String containing PDP type to request. ("IP", "IPV6", ...) */ setupDataCall: function setupDataCall(options) { + // From ./hardware/ril/include/telephony/ril.h: + // ((const char **)data)[0] Radio technology to use: 0-CDMA, 1-GSM/UMTS, 2... + // for values above 2 this is RIL_RadioTechnology + 2. + // + // From frameworks/base/telephony/java/com/android/internal/telephony/DataConnection.java: + // if the mRilVersion < 6, radio technology must be GSM/UMTS or CDMA. + // Otherwise, it must be + 2 + // + // See also bug 901232 and 867873 + let radioTech; + if (RILQUIRKS_V5_LEGACY) { + radioTech = this._isCdma ? DATACALL_RADIOTECHNOLOGY_CDMA + : DATACALL_RADIOTECHNOLOGY_GSM; + } else { + radioTech = options.radioTech + 2; + } let token = Buf.newParcel(REQUEST_SETUP_DATA_CALL, options); Buf.writeUint32(7); - Buf.writeString(options.radioTech.toString()); + Buf.writeString(radioTech.toString()); Buf.writeString(DATACALL_PROFILE_DEFAULT.toString()); Buf.writeString(options.apn); Buf.writeString(options.user); diff --git a/gfx/layers/composite/APZCTreeManager.cpp b/gfx/layers/composite/APZCTreeManager.cpp index 35ddbf0f3909..7fd9c9d91b17 100644 --- a/gfx/layers/composite/APZCTreeManager.cpp +++ b/gfx/layers/composite/APZCTreeManager.cpp @@ -231,12 +231,6 @@ APZCTreeManager::ReceiveInputEvent(const InputData& aEvent) } } else if (mApzcForInputBlock) { APZC_LOG("Re-using APZC %p as continuation of event block\n", mApzcForInputBlock.get()); - // If we have an mApzcForInputBlock and it's the end of the touch sequence - // then null it out so we don't keep a dangling reference and leak things. - if (multiTouchInput.mType == MultiTouchInput::MULTITOUCH_CANCEL || - (multiTouchInput.mType == MultiTouchInput::MULTITOUCH_END && multiTouchInput.mTouches.Length() == 1)) { - mApzcForInputBlock = nullptr; - } } if (mApzcForInputBlock) { GetInputTransforms(mApzcForInputBlock, transformToApzc, transformToScreen); @@ -245,6 +239,12 @@ APZCTreeManager::ReceiveInputEvent(const InputData& aEvent) ApplyTransform(&(inputForApzc.mTouches[i].mScreenPoint), transformToApzc); } mApzcForInputBlock->ReceiveInputEvent(inputForApzc); + // If we have an mApzcForInputBlock and it's the end of the touch sequence + // then null it out so we don't keep a dangling reference and leak things. + if (multiTouchInput.mType == MultiTouchInput::MULTITOUCH_CANCEL || + (multiTouchInput.mType == MultiTouchInput::MULTITOUCH_END && multiTouchInput.mTouches.Length() == 1)) { + mApzcForInputBlock = nullptr; + } } break; } case PINCHGESTURE_INPUT: { @@ -302,12 +302,6 @@ APZCTreeManager::ReceiveInputEvent(const nsInputEvent& aEvent, } } else if (mApzcForInputBlock) { APZC_LOG("Re-using APZC %p as continuation of event block\n", mApzcForInputBlock.get()); - // If we have an mApzcForInputBlock and it's the end of the touch sequence - // then null it out so we don't keep a dangling reference and leak things. - if (touchEvent.message == NS_TOUCH_CANCEL || - (touchEvent.message == NS_TOUCH_END && touchEvent.touches.Length() == 1)) { - mApzcForInputBlock = nullptr; - } } if (mApzcForInputBlock) { GetInputTransforms(mApzcForInputBlock, transformToApzc, transformToScreen); @@ -322,7 +316,16 @@ APZCTreeManager::ReceiveInputEvent(const nsInputEvent& aEvent, ApplyTransform(&(outEvent->touches[i]->mRefPoint), outTransform); } - return mApzcForInputBlock->ReceiveInputEvent(inputForApzc); + nsEventStatus ret = mApzcForInputBlock->ReceiveInputEvent(inputForApzc); + + // If we have an mApzcForInputBlock and it's the end of the touch sequence + // then null it out so we don't keep a dangling reference and leak things. + if (touchEvent.message == NS_TOUCH_CANCEL || + (touchEvent.message == NS_TOUCH_END && touchEvent.touches.Length() == 1)) { + mApzcForInputBlock = nullptr; + } + + return ret; } break; } case NS_MOUSE_EVENT: { diff --git a/modules/libpref/src/init/all.js b/modules/libpref/src/init/all.js index 6a5c8ffd32f5..9fdf62f3d8ef 100644 --- a/modules/libpref/src/init/all.js +++ b/modules/libpref/src/init/all.js @@ -4322,6 +4322,11 @@ pref("dom.placeholder.show_on_focus", true); pref("wap.UAProf.url", ""); pref("wap.UAProf.tagname", "x-wap-profile"); +// MMS version 1.1 = 0x11 (or decimal 17) +// MMS version 1.3 = 0x13 (or decimal 19) +// @see OMA-TS-MMS_ENC-V1_3-20110913-A clause 7.3.34 +pref("dom.mms.version", 19); + // Retrieval mode for MMS // manual: Manual retrieval mode. // automatic: Automatic retrieval mode even in roaming.