diff --git a/b2g/components/AlertsHelper.jsm b/b2g/components/AlertsHelper.jsm index 52caa7b15298..1065fa2f533a 100644 --- a/b2g/components/AlertsHelper.jsm +++ b/b2g/components/AlertsHelper.jsm @@ -149,7 +149,8 @@ let AlertsHelper = { dir: listener.dir, id: listener.id, tag: listener.tag, - timestamp: listener.timestamp + timestamp: listener.timestamp, + data: listener.dataObj }, Services.io.newURI(listener.target, null, null), Services.io.newURI(listener.manifestURL, null, null) @@ -199,8 +200,32 @@ let AlertsHelper = { }); }, + deserializeStructuredClone: function(dataString) { + if (!dataString) { + return null; + } + let scContainer = Cc["@mozilla.org/docshell/structured-clone-container;1"]. + createInstance(Ci.nsIStructuredCloneContainer); + + // The maximum supported structured-clone serialization format version + // as defined in "js/public/StructuredClone.h" + let JS_STRUCTURED_CLONE_VERSION = 4; + scContainer.initFromBase64(dataString, JS_STRUCTURED_CLONE_VERSION); + let dataObj = scContainer.deserializeToVariant(); + + // We have to check whether dataObj contains DOM objects (supported by + // nsIStructuredCloneContainer, but not by Cu.cloneInto), e.g. ImageData. + // After the structured clone callback systems will be unified, we'll not + // have to perform this check anymore. + try { + let data = Cu.cloneInto(dataObj, {}); + } catch(e) { dataObj = null; } + + return dataObj; + }, + showNotification: function(imageURL, title, text, textClickable, cookie, - uid, bidi, lang, manifestURL, timestamp) { + uid, bidi, lang, dataObj, manifestURL, timestamp) { function send(appName, appIcon) { SystemAppProxy._sendCustomEvent(kMozChromeNotificationEvent, { type: kDesktopNotification, @@ -213,7 +238,8 @@ let AlertsHelper = { appName: appName, appIcon: appIcon, manifestURL: manifestURL, - timestamp: timestamp + timestamp: timestamp, + data: dataObj }); } @@ -238,15 +264,17 @@ let AlertsHelper = { currentListener.observer.observe(null, kTopicAlertFinished, currentListener.cookie); } + let dataObj = this.deserializeStructuredClone(data.dataStr); this.registerListener(data.name, data.cookie, data.alertListener); this.showNotification(data.imageURL, data.title, data.text, data.textClickable, data.cookie, data.name, data.bidi, - data.lang, null); + data.lang, dataObj, null); }, showAppNotification: function(aMessage) { let data = aMessage.data; let details = data.details; + let dataObject = this.deserializeStructuredClone(details.data); let listener = { mm: aMessage.target, title: data.title, @@ -257,12 +285,14 @@ let AlertsHelper = { id: details.id || undefined, dir: details.dir || undefined, tag: details.tag || undefined, - timestamp: details.timestamp || undefined + timestamp: details.timestamp || undefined, + dataObj: dataObject || undefined }; this.registerAppListener(data.uid, listener); this.showNotification(data.imageURL, data.title, data.text, details.textClickable, null, data.uid, details.dir, - details.lang, details.manifestURL, details.timestamp); + details.lang, dataObject, details.manifestURL, + details.timestamp); }, closeAlert: function(name) { diff --git a/b2g/components/AlertsService.js b/b2g/components/AlertsService.js index 3ce6ce21acad..58b9ae36a30a 100644 --- a/b2g/components/AlertsService.js +++ b/b2g/components/AlertsService.js @@ -69,7 +69,7 @@ AlertsService.prototype = { // nsIAlertsService showAlertNotification: function(aImageUrl, aTitle, aText, aTextClickable, aCookie, aAlertListener, aName, aBidi, - aLang) { + aLang, aDataStr) { cpmm.sendAsyncMessage(kMessageAlertNotificationSend, { imageURL: aImageUrl, title: aTitle, @@ -79,7 +79,8 @@ AlertsService.prototype = { listener: aAlertListener, id: aName, dir: aBidi, - lang: aLang + lang: aLang, + dataStr: aDataStr }); }, @@ -95,6 +96,7 @@ AlertsService.prototype = { let uid = (aDetails.id == "") ? "app-notif-" + uuidGenerator.generateUUID() : aDetails.id; + let dataObj = this.deserializeStructuredClone(aDetails.data); this._listeners[uid] = { observer: aAlertListener, title: aTitle, @@ -106,7 +108,8 @@ AlertsService.prototype = { dbId: aDetails.dbId || undefined, dir: aDetails.dir || undefined, tag: aDetails.tag || undefined, - timestamp: aDetails.timestamp || undefined + timestamp: aDetails.timestamp || undefined, + dataObj: dataObj || undefined }; cpmm.sendAsyncMessage(kMessageAppNotificationSend, { @@ -151,7 +154,8 @@ AlertsService.prototype = { id: listener.id, tag: listener.tag, dbId: listener.dbId, - timestamp: listener.timestamp + timestamp: listener.timestamp, + data: listener.dataObj || undefined, }, Services.io.newURI(data.target, null, null), Services.io.newURI(listener.manifestURL, null, null) @@ -167,6 +171,30 @@ AlertsService.prototype = { } delete this._listeners[data.uid]; } + }, + + deserializeStructuredClone: function(dataString) { + if (!dataString) { + return null; + } + let scContainer = Cc["@mozilla.org/docshell/structured-clone-container;1"]. + createInstance(Ci.nsIStructuredCloneContainer); + + // The maximum supported structured-clone serialization format version + // as defined in "js/public/StructuredClone.h" + let JS_STRUCTURED_CLONE_VERSION = 4; + scContainer.initFromBase64(dataString, JS_STRUCTURED_CLONE_VERSION); + let dataObj = scContainer.deserializeToVariant(); + + // We have to check whether dataObj contains DOM objects (supported by + // nsIStructuredCloneContainer, but not by Cu.cloneInto), e.g. ImageData. + // After the structured clone callback systems will be unified, we'll not + // have to perform this check anymore. + try { + let data = Cu.cloneInto(dataObj, {}); + } catch(e) { dataObj = null; } + + return dataObj; } }; diff --git a/dom/interfaces/base/nsIStructuredCloneContainer.idl b/dom/interfaces/base/nsIStructuredCloneContainer.idl index 25b8676bf2f2..dee370970177 100644 --- a/dom/interfaces/base/nsIStructuredCloneContainer.idl +++ b/dom/interfaces/base/nsIStructuredCloneContainer.idl @@ -46,7 +46,7 @@ interface nsIStructuredCloneContainer : nsISupports void initFromBase64(in AString aData,in unsigned long aFormatVersion); /** - * Deserialize the object this conatiner holds, returning it wrapped as + * Deserialize the object this container holds, returning it wrapped as * an nsIVariant. */ [implicit_jscontext] diff --git a/dom/interfaces/notification/nsINotificationStorage.idl b/dom/interfaces/notification/nsINotificationStorage.idl index da3b89212e1c..4fd0c7e0b2fa 100644 --- a/dom/interfaces/notification/nsINotificationStorage.idl +++ b/dom/interfaces/notification/nsINotificationStorage.idl @@ -4,7 +4,7 @@ #include "domstubs.idl" -[scriptable, uuid(fb089720-1c5c-11e3-b773-0800200c9a66)] +[scriptable, uuid(9b12f566-2c7f-48ef-990d-e5092a71d11e)] interface nsINotificationStorageCallback : nsISupports { /** @@ -26,7 +26,8 @@ interface nsINotificationStorageCallback : nsISupports in DOMString lang, in DOMString body, in DOMString tag, - in DOMString icon); + in DOMString icon, + in DOMString data); /** * Callback function used to notify C++ the we have returned @@ -39,7 +40,7 @@ interface nsINotificationStorageCallback : nsISupports /** * Interface for notification persistence layer. */ -[scriptable, uuid(cc4656d7-2a2a-47f1-8016-55891e833d64)] +[scriptable, uuid(1be733d9-d614-43f2-9fd4-8f573a33b215)] interface nsINotificationStorage : nsISupports { @@ -68,7 +69,8 @@ interface nsINotificationStorage : nsISupports in DOMString body, in DOMString tag, in DOMString icon, - in DOMString alertName); + in DOMString alertName, + in DOMString data); /** * Retrieve a list of notifications. diff --git a/dom/ipc/ContentParent.cpp b/dom/ipc/ContentParent.cpp index 8f8f447a66ca..c5d97af43d4b 100755 --- a/dom/ipc/ContentParent.cpp +++ b/dom/ipc/ContentParent.cpp @@ -3361,6 +3361,7 @@ ContentParent::RecvShowAlertNotification(const nsString& aImageUrl, const nsStri const nsString& aText, const bool& aTextClickable, const nsString& aCookie, const nsString& aName, const nsString& aBidi, const nsString& aLang, + const nsString& aData, const IPC::Principal& aPrincipal) { #ifdef MOZ_CHILD_PERMISSIONS @@ -3374,7 +3375,8 @@ ContentParent::RecvShowAlertNotification(const nsString& aImageUrl, const nsStri nsCOMPtr sysAlerts(do_GetService(NS_ALERTSERVICE_CONTRACTID)); if (sysAlerts) { sysAlerts->ShowAlertNotification(aImageUrl, aTitle, aText, aTextClickable, - aCookie, this, aName, aBidi, aLang, aPrincipal); + aCookie, this, aName, aBidi, aLang, + aData, aPrincipal); } return true; } diff --git a/dom/ipc/ContentParent.h b/dom/ipc/ContentParent.h index 84f93501a01c..c7166e5d6e54 100644 --- a/dom/ipc/ContentParent.h +++ b/dom/ipc/ContentParent.h @@ -530,6 +530,7 @@ private: const nsString& aText, const bool& aTextClickable, const nsString& aCookie, const nsString& aName, const nsString& aBidi, const nsString& aLang, + const nsString& aData, const IPC::Principal& aPrincipal) MOZ_OVERRIDE; virtual bool RecvCloseAlert(const nsString& aName, diff --git a/dom/ipc/PContent.ipdl b/dom/ipc/PContent.ipdl index f90a178fb853..0baf16f10fed 100644 --- a/dom/ipc/PContent.ipdl +++ b/dom/ipc/PContent.ipdl @@ -542,6 +542,7 @@ parent: nsString name, nsString bidi, nsString lang, + nsString data, Principal principal); CloseAlert(nsString name, Principal principal); diff --git a/dom/src/notification/ChromeNotifications.js b/dom/src/notification/ChromeNotifications.js index 11e0af818e32..15f81fbe8148 100644 --- a/dom/src/notification/ChromeNotifications.js +++ b/dom/src/notification/ChromeNotifications.js @@ -60,7 +60,8 @@ ChromeNotifications.prototype = { lang: notification.lang, tag: notification.tag, dbId: notification.id, - timestamp: notification.timestamp + timestamp: notification.timestamp, + data: notification.data } ); resentNotifications++; diff --git a/dom/src/notification/DesktopNotification.cpp b/dom/src/notification/DesktopNotification.cpp index c3ba7db189bd..9ce200df2311 100644 --- a/dom/src/notification/DesktopNotification.cpp +++ b/dom/src/notification/DesktopNotification.cpp @@ -111,6 +111,7 @@ DesktopNotification::PostDesktopNotification() uniqueName, NS_LITERAL_STRING("auto"), EmptyString(), + EmptyString(), principal); } diff --git a/dom/src/notification/Notification.cpp b/dom/src/notification/Notification.cpp index b96dee214139..7fbabfa3186a 100644 --- a/dom/src/notification/Notification.cpp +++ b/dom/src/notification/Notification.cpp @@ -4,6 +4,7 @@ #include "mozilla/dom/Notification.h" #include "mozilla/dom/AppNotificationServiceOptionsBinding.h" +#include "mozilla/dom/BindingUtils.h" #include "mozilla/dom/OwningNonNull.h" #include "mozilla/dom/Promise.h" #include "mozilla/Preferences.h" @@ -16,10 +17,12 @@ #include "nsIPermissionManager.h" #include "nsIUUIDGenerator.h" #include "nsServiceManagerUtils.h" +#include "nsStructuredCloneContainer.h" #include "nsToolkitCompsCID.h" #include "nsGlobalWindow.h" #include "nsDOMJSUtils.h" #include "nsIScriptSecurityManager.h" +#include "nsIXPConnect.h" #include "mozilla/dom/PermissionMessageUtils.h" #include "mozilla/Services.h" #include "nsContentPermissionHelper.h" @@ -57,11 +60,12 @@ public: const nsAString& aBody, const nsAString& aTag, const nsAString& aIcon, + const nsAString& aData, JSContext* aCx) { MOZ_ASSERT(!aID.IsEmpty()); - NotificationOptions options; + RootedDictionary options(aCx); options.mDir = Notification::StringToDirection(nsString(aDir)); options.mLang = aLang; options.mBody = aBody; @@ -71,6 +75,12 @@ public: aID, aTitle, options); + ErrorResult rv; + notification->InitFromBase64(aCx, aData, rv); + if (rv.Failed()) { + return rv.ErrorCode(); + } + JSAutoCompartment ac(aCx, mGlobal); JS::Rooted element(aCx, notification->WrapObject(aCx)); NS_ENSURE_TRUE(element, NS_ERROR_FAILURE); @@ -371,7 +381,7 @@ NotificationObserver::Observe(nsISupports* aSubject, const char* aTopic, Notification::Notification(const nsAString& aID, const nsAString& aTitle, const nsAString& aBody, NotificationDirection aDir, const nsAString& aLang, const nsAString& aTag, const nsAString& aIconUrl, - nsPIDOMWindow* aWindow) + nsPIDOMWindow* aWindow) : DOMEventTargetHelper(aWindow), mID(aID), mTitle(aTitle), mBody(aBody), mDir(aDir), mLang(aLang), mTag(aTag), mIconUrl(aIconUrl), mIsClosed(false) @@ -404,11 +414,19 @@ Notification::Constructor(const GlobalObject& aGlobal, MOZ_ASSERT(NS_IsMainThread()); nsCOMPtr window = do_QueryInterface(aGlobal.GetAsSupports()); MOZ_ASSERT(window, "Window should not be null."); + nsRefPtr notification = CreateInternal(window, EmptyString(), aTitle, aOptions); + // Make a structured clone of the aOptions.mData object + JS::Rooted data(aGlobal.Context(), aOptions.mData); + notification->InitFromJSVal(aGlobal.Context(), data, aRv); + if (aRv.Failed()) { + return nullptr; + } + // Queue a task to show the notification. nsCOMPtr showNotificationTask = new NotificationTask(notification, NotificationTask::eShow); @@ -435,6 +453,13 @@ Notification::Constructor(const GlobalObject& aGlobal, nsString alertName; notification->GetAlertName(alertName); + nsString dataString; + nsCOMPtr scContainer; + scContainer = notification->GetDataCloneContainer(); + if (scContainer) { + scContainer->GetDataAsBase64(dataString); + } + aRv = notificationStorage->Put(origin, id, aTitle, @@ -443,7 +468,9 @@ Notification::Constructor(const GlobalObject& aGlobal, aOptions.mBody, aOptions.mTag, aOptions.mIcon, - alertName); + alertName, + dataString); + if (aRv.Failed()) { return nullptr; } @@ -481,10 +508,29 @@ Notification::CreateInternal(nsPIDOMWindow* aWindow, aOptions.mLang, aOptions.mTag, aOptions.mIcon, - aWindow); + aWindow); return notification.forget(); } +Notification::~Notification() {} + +NS_IMPL_CYCLE_COLLECTION_CLASS(Notification) +NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(Notification, DOMEventTargetHelper) + NS_IMPL_CYCLE_COLLECTION_UNLINK(mData) + NS_IMPL_CYCLE_COLLECTION_UNLINK(mDataObjectContainer) +NS_IMPL_CYCLE_COLLECTION_UNLINK_END + +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(Notification, DOMEventTargetHelper) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mData) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDataObjectContainer) +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END + +NS_IMPL_ADDREF_INHERITED(Notification, DOMEventTargetHelper) +NS_IMPL_RELEASE_INHERITED(Notification, DOMEventTargetHelper) + +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(Notification) +NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper) + nsIPrincipal* Notification::GetPrincipal() { @@ -531,6 +577,13 @@ Notification::ShowInternal() nsCOMPtr observer = new NotificationObserver(this); + // mDataObjectContainer might be uninitialized here because the notification + // was constructed with an undefined data property. + nsString dataStr; + if (mDataObjectContainer) { + mDataObjectContainer->GetDataAsBase64(dataStr); + } + #ifdef MOZ_B2G nsCOMPtr appNotifier = do_GetService("@mozilla.org/system-alerts-service;1"); @@ -553,6 +606,7 @@ Notification::ShowInternal() ops.mDir = DirectionToString(mDir); ops.mLang = mLang; ops.mTag = mTag; + ops.mData = dataStr; if (!ToJSValue(cx, ops, &val)) { NS_WARNING("Converting dict to object failed!"); @@ -574,7 +628,7 @@ Notification::ShowInternal() alertService->ShowAlertNotification(absoluteUrl, mTitle, mBody, true, uniqueCookie, observer, mAlertName, DirectionToString(mDir), mLang, - GetPrincipal()); + dataStr, GetPrincipal()); } void @@ -780,6 +834,54 @@ Notification::GetOrigin(nsPIDOMWindow* aWindow, nsString& aOrigin) return NS_OK; } +nsIStructuredCloneContainer* Notification::GetDataCloneContainer() +{ + return mDataObjectContainer; +} + +void +Notification::GetData(JSContext* aCx, + JS::MutableHandle aRetval) +{ + if (!mData && mDataObjectContainer) { + nsresult rv; + rv = mDataObjectContainer->DeserializeToVariant(aCx, getter_AddRefs(mData)); + if (NS_WARN_IF(NS_FAILED(rv))) { + aRetval.setNull(); + return; + } + } + if (!mData) { + aRetval.setNull(); + return; + } + VariantToJsval(aCx, mData, aRetval); +} + +void +Notification::InitFromJSVal(JSContext* aCx, JS::Handle aData, + ErrorResult& aRv) +{ + if (mDataObjectContainer || aData.isNull()) { + return; + } + mDataObjectContainer = new nsStructuredCloneContainer(); + aRv = mDataObjectContainer->InitFromJSVal(aData); +} + +void Notification::InitFromBase64(JSContext* aCx, const nsAString& aData, + ErrorResult& aRv) +{ + if (mDataObjectContainer || aData.IsEmpty()) { + return; + } + + auto container = new nsStructuredCloneContainer(); + aRv = container->InitFromBase64(aData, JS_STRUCTURED_CLONE_VERSION, + aCx); + mDataObjectContainer = container; +} + } // namespace dom } // namespace mozilla diff --git a/dom/src/notification/Notification.h b/dom/src/notification/Notification.h index ae83174b7d4f..924a3838deec 100644 --- a/dom/src/notification/Notification.h +++ b/dom/src/notification/Notification.h @@ -13,6 +13,8 @@ #include "nsCycleCollectionParticipant.h" class nsIPrincipal; +class nsIStructuredCloneContainer; +class nsIVariant; namespace mozilla { namespace dom { @@ -34,6 +36,9 @@ public: IMPL_EVENT_HANDLER(error) IMPL_EVENT_HANDLER(close) + NS_DECL_ISUPPORTS_INHERITED + NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(Notification, DOMEventTargetHelper) + static already_AddRefed Constructor(const GlobalObject& aGlobal, const nsAString& aTitle, const NotificationOptions& aOption, @@ -72,6 +77,8 @@ public: aRetval = mIconUrl; } + nsIStructuredCloneContainer* GetDataCloneContainer(); + static void RequestPermission(const GlobalObject& aGlobal, const Optional >& aCallback, ErrorResult& aRv); @@ -91,11 +98,17 @@ public: } virtual JSObject* WrapObject(JSContext* aCx) MOZ_OVERRIDE; + + void GetData(JSContext* aCx, JS::MutableHandle aRetval); + + void InitFromJSVal(JSContext* aCx, JS::Handle aData, ErrorResult& aRv); + + void InitFromBase64(JSContext* aCx, const nsAString& aData, ErrorResult& aRv); protected: Notification(const nsAString& aID, const nsAString& aTitle, const nsAString& aBody, NotificationDirection aDir, const nsAString& aLang, const nsAString& aTag, const nsAString& aIconUrl, - nsPIDOMWindow* aWindow); + nsPIDOMWindow* aWindow); static already_AddRefed CreateInternal(nsPIDOMWindow* aWindow, const nsAString& aID, @@ -145,6 +158,10 @@ protected: nsString mLang; nsString mTag; nsString mIconUrl; + nsCOMPtr mDataObjectContainer; + + // It's null until GetData is first called + nsCOMPtr mData; nsString mAlertName; @@ -153,6 +170,8 @@ protected: static uint32_t sCount; private: + virtual ~Notification(); + nsIPrincipal* GetPrincipal(); }; diff --git a/dom/src/notification/NotificationStorage.js b/dom/src/notification/NotificationStorage.js index bc32f9fc5b1c..cbf94cb6c7dd 100644 --- a/dom/src/notification/NotificationStorage.js +++ b/dom/src/notification/NotificationStorage.js @@ -71,7 +71,8 @@ NotificationStorage.prototype = { } }, - put: function(origin, id, title, dir, lang, body, tag, icon, alertName) { + put: function(origin, id, title, dir, lang, body, tag, icon, alertName, + data) { if (DEBUG) { debug("PUT: " + id + ": " + title); } var notification = { id: id, @@ -83,7 +84,8 @@ NotificationStorage.prototype = { icon: icon, alertName: alertName, timestamp: new Date().getTime(), - origin: origin + origin: origin, + data: data }; this._notifications[id] = notification; @@ -202,7 +204,8 @@ NotificationStorage.prototype = { notification.lang, notification.body, notification.tag, - notification.icon); + notification.icon, + notification.data); } catch (e) { if (DEBUG) { debug("Error calling callback handle: " + e); } } diff --git a/dom/tests/mochitest/notification/MockServices.js b/dom/tests/mochitest/notification/MockServices.js index 28c5f7750ae2..bfe506a7d2ae 100644 --- a/dom/tests/mochitest/notification/MockServices.js +++ b/dom/tests/mochitest/notification/MockServices.js @@ -48,7 +48,8 @@ var MockServices = (function () { dbId: aDetails.dbId || undefined, dir: aDetails.dir || undefined, tag: aDetails.tag || undefined, - timestamp: aDetails.timestamp || undefined + timestamp: aDetails.timestamp || undefined, + data: aDetails.data || undefined }; this.showAlertNotification(aImageUrl, aTitle, aText, true, "", listener, aDetails.id); }, diff --git a/dom/tests/mochitest/notification/NotificationTest.js b/dom/tests/mochitest/notification/NotificationTest.js index 871ec137a632..ae56283aa281 100644 --- a/dom/tests/mochitest/notification/NotificationTest.js +++ b/dom/tests/mochitest/notification/NotificationTest.js @@ -43,6 +43,34 @@ var NotificationTest = (function () { })(tests); } + var fakeCustomData = (function () { + var buffer = new ArrayBuffer(2); + var dv = new DataView(buffer).setInt16(0, 42, true); + var canvas = document.createElement("canvas"); + canvas.width = canvas.height = 100; + var context = canvas.getContext("2d"); + + var map = new Map(); + var set = new Set(); + map.set("test", 42); + set.add(4); set.add(2); + + return { + primitives: { + a: 123, + b: "test", + c: true, + d: [1, 2, 3] + }, + date: new Date(2013, 2, 1, 1, 10), + regexp: new RegExp("[^.]+"), + arrayBuffer: buffer, + imageData: context.createImageData(100, 100), + map: map, + set: set + }; + })(); + // NotificationTest API return { run: function (tests, callback) { @@ -68,6 +96,33 @@ var NotificationTest = (function () { // TODO: how?? }, - info: info + info: info, + + customDataMatches: function(dataObj) { + var url = "http://www.domain.com"; + try { + return (JSON.stringify(dataObj.primitives) === + JSON.stringify(fakeCustomData.primitives)) && + (dataObj.date.toDateString() === + fakeCustomData.date.toDateString()) && + (dataObj.regexp.exec(url)[0].substr(7) === "www") && + (new Int16Array(dataObj.arrayBuffer)[0] === 42) && + (JSON.stringify(dataObj.imageData.data) === + JSON.stringify(fakeCustomData.imageData.data)) && + (dataObj.map.get("test") == 42) && + (dataObj.set.has(4) && dataObj.set.has(2)); + } catch(e) { + return false; + } + }, + + payload: { + body: "Body", + tag: "fakeTag", + icon: "icon.jpg", + lang: "en-US", + dir: "ltr", + data: fakeCustomData + } }; })(); diff --git a/dom/tests/mochitest/notification/desktop-notification/notification_common.js b/dom/tests/mochitest/notification/desktop-notification/notification_common.js index 74b6f6b2df98..47d9d22da978 100644 --- a/dom/tests/mochitest/notification/desktop-notification/notification_common.js +++ b/dom/tests/mochitest/notification/desktop-notification/notification_common.js @@ -9,7 +9,8 @@ var registrar = SpecialPowers.wrap(SpecialPowers.Components).manager. var mockAlertsService = { showAlertNotification: function(imageUrl, title, text, textClickable, - cookie, alertListener, name, bidi, lang) { + cookie, alertListener, name, bidi, + lang, data) { // probably should do this async.... SpecialPowers.wrap(alertListener).observe(null, "alertshow", cookie); @@ -22,7 +23,8 @@ var mockAlertsService = { showAppNotification: function(imageUrl, title, text, alertListener, details) { this.showAlertNotification(imageUrl, title, text, details.textClickable, "", - alertListener, details.name, details.dir, details.lang); + alertListener, details.name, details.dir, + details.lang, details.data); }, QueryInterface: function(aIID) { diff --git a/dom/tests/mochitest/notification/desktop-notification/test_notification_tag.html b/dom/tests/mochitest/notification/desktop-notification/test_notification_tag.html index ac4a46d24973..086ff0a7b57a 100644 --- a/dom/tests/mochitest/notification/desktop-notification/test_notification_tag.html +++ b/dom/tests/mochitest/notification/desktop-notification/test_notification_tag.html @@ -24,7 +24,8 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=782211 var mockAlertsService = { showAlertNotification: function(imageUrl, title, text, textClickable, - cookie, alertListener, name, dir, lang) { + cookie, alertListener, name, dir, + lang, data) { notificationsCreated.push(name); if (notificationsCreated.length == 3) { checkNotifications(); diff --git a/dom/tests/mochitest/notification/desktop-notification/test_system_principal.xul b/dom/tests/mochitest/notification/desktop-notification/test_system_principal.xul index 60f9d56bca97..52312a76635a 100644 --- a/dom/tests/mochitest/notification/desktop-notification/test_system_principal.xul +++ b/dom/tests/mochitest/notification/desktop-notification/test_system_principal.xul @@ -24,7 +24,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=874090 var mockAlertsService = { showAlertNotification: function(imageUrl, title, text, textClickable, - cookie, alertListener, name, dir, lang) { + cookie, alertListener, name, dir, lang, data) { ok(true, "System principal was granted permission and is able to call showAlertNotification."); unregisterMock(); SimpleTest.finish(); diff --git a/dom/tests/mochitest/notification/test_notification_basics.html b/dom/tests/mochitest/notification/test_notification_basics.html index d65a0fde51cb..cfc9da345277 100644 --- a/dom/tests/mochitest/notification/test_notification_basics.html +++ b/dom/tests/mochitest/notification/test_notification_basics.html @@ -14,6 +14,7 @@