зеркало из https://github.com/mozilla/gecko-dev.git
Bug 899585 - Add custom data support in the Notification constructor r=baku
This commit is contained in:
Родитель
10638101c5
Коммит
29ee85a120
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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<nsIAlertsService> 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;
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -542,6 +542,7 @@ parent:
|
|||
nsString name,
|
||||
nsString bidi,
|
||||
nsString lang,
|
||||
nsString data,
|
||||
Principal principal);
|
||||
|
||||
CloseAlert(nsString name, Principal principal);
|
||||
|
|
|
@ -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++;
|
||||
|
|
|
@ -111,6 +111,7 @@ DesktopNotification::PostDesktopNotification()
|
|||
uniqueName,
|
||||
NS_LITERAL_STRING("auto"),
|
||||
EmptyString(),
|
||||
EmptyString(),
|
||||
principal);
|
||||
}
|
||||
|
||||
|
|
|
@ -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<NotificationOptions> 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<JSObject*> 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<nsPIDOMWindow> window = do_QueryInterface(aGlobal.GetAsSupports());
|
||||
MOZ_ASSERT(window, "Window should not be null.");
|
||||
|
||||
nsRefPtr<Notification> notification = CreateInternal(window,
|
||||
EmptyString(),
|
||||
aTitle,
|
||||
aOptions);
|
||||
|
||||
// Make a structured clone of the aOptions.mData object
|
||||
JS::Rooted<JS::Value> data(aGlobal.Context(), aOptions.mData);
|
||||
notification->InitFromJSVal(aGlobal.Context(), data, aRv);
|
||||
if (aRv.Failed()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Queue a task to show the notification.
|
||||
nsCOMPtr<nsIRunnable> showNotificationTask =
|
||||
new NotificationTask(notification, NotificationTask::eShow);
|
||||
|
@ -435,6 +453,13 @@ Notification::Constructor(const GlobalObject& aGlobal,
|
|||
nsString alertName;
|
||||
notification->GetAlertName(alertName);
|
||||
|
||||
nsString dataString;
|
||||
nsCOMPtr<nsIStructuredCloneContainer> 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<nsIObserver> 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<nsIAppNotificationService> 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<JS::Value> 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<JS::Value> 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
|
||||
|
||||
|
|
|
@ -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<Notification> 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<OwningNonNull<NotificationPermissionCallback> >& aCallback,
|
||||
ErrorResult& aRv);
|
||||
|
@ -91,11 +98,17 @@ public:
|
|||
}
|
||||
|
||||
virtual JSObject* WrapObject(JSContext* aCx) MOZ_OVERRIDE;
|
||||
|
||||
void GetData(JSContext* aCx, JS::MutableHandle<JS::Value> aRetval);
|
||||
|
||||
void InitFromJSVal(JSContext* aCx, JS::Handle<JS::Value> 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<Notification> CreateInternal(nsPIDOMWindow* aWindow,
|
||||
const nsAString& aID,
|
||||
|
@ -145,6 +158,10 @@ protected:
|
|||
nsString mLang;
|
||||
nsString mTag;
|
||||
nsString mIconUrl;
|
||||
nsCOMPtr<nsIStructuredCloneContainer> mDataObjectContainer;
|
||||
|
||||
// It's null until GetData is first called
|
||||
nsCOMPtr<nsIVariant> mData;
|
||||
|
||||
nsString mAlertName;
|
||||
|
||||
|
@ -153,6 +170,8 @@ protected:
|
|||
static uint32_t sCount;
|
||||
|
||||
private:
|
||||
virtual ~Notification();
|
||||
|
||||
nsIPrincipal* GetPrincipal();
|
||||
};
|
||||
|
||||
|
|
|
@ -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); }
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
},
|
||||
|
|
|
@ -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
|
||||
}
|
||||
};
|
||||
})();
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
<script type="text/javascript">
|
||||
|
||||
var info = NotificationTest.info;
|
||||
var options;
|
||||
|
||||
var steps = [
|
||||
function () {
|
||||
|
@ -62,13 +63,8 @@
|
|||
function (done) {
|
||||
info("Test create notification");
|
||||
|
||||
var options = {
|
||||
dir: "auto",
|
||||
lang: "",
|
||||
body: "This is a notification body",
|
||||
tag: "sometag",
|
||||
icon: "icon.png"
|
||||
};
|
||||
options = NotificationTest.payload;
|
||||
|
||||
var notification = new Notification("This is a title", options);
|
||||
|
||||
ok(notification, "Notification exists");
|
||||
|
@ -77,12 +73,15 @@
|
|||
is(notification.onerror, null, "onerror() should be null");
|
||||
is(notification.onclose, null, "onclose() should be null");
|
||||
is(typeof notification.close, "function", "close() should exist");
|
||||
is(typeof notification.data, "object", "data should be a JS object");
|
||||
|
||||
is(notification.dir, options.dir, "auto should get set");
|
||||
is(notification.lang, options.lang, "lang should get set");
|
||||
is(notification.body, options.body, "body should get set");
|
||||
is(notification.tag, options.tag, "tag should get set");
|
||||
is(notification.icon, options.icon, "icon should get set");
|
||||
ok(NotificationTest.customDataMatches(notification.data),
|
||||
"data should get set");
|
||||
|
||||
// store notification in test context
|
||||
this.notification = notification;
|
||||
|
|
|
@ -94,13 +94,8 @@
|
|||
done();
|
||||
};
|
||||
|
||||
var payload = {
|
||||
body: "Body",
|
||||
tag: "fakeTag",
|
||||
icon: "icon.jpg",
|
||||
lang: "en-US",
|
||||
dir: "ltr"
|
||||
};
|
||||
var payload = NotificationTest.payload;
|
||||
|
||||
var notif2 = new Notification("Title2", payload);
|
||||
ok(notif2, "Notification object is valid");
|
||||
notifications.push(notif2);
|
||||
|
@ -156,6 +151,16 @@
|
|||
is(notif.dir, "ltr", "Notification dir is valid: " + notif.dir);
|
||||
is(notif.tag, "fakeTag", "Notification tag is valid: " + notif.tag);
|
||||
ok((notif.timestamp >= now), "Notification timestamp is valid: (" + notif.timestamp + " >= " + now + ")");
|
||||
|
||||
var scContainer =
|
||||
SpecialPowers.Cc["@mozilla.org/docshell/structured-clone-container;1"].
|
||||
createInstance(SpecialPowers.Ci.nsIStructuredCloneContainer);
|
||||
scContainer.initFromBase64(notif.data, 4);
|
||||
|
||||
var dataObj = scContainer.deserializeToVariant().SpecialPowers_wrappedObject;
|
||||
ok(NotificationTest.customDataMatches(dataObj),
|
||||
"Notification data is valid");
|
||||
|
||||
notif2.close();
|
||||
});
|
||||
}
|
||||
|
|
|
@ -45,13 +45,8 @@
|
|||
function (done) {
|
||||
info("Test adding a notification, and making sure get returns it");
|
||||
NotificationTest.allowNotifications();
|
||||
var options = {
|
||||
dir: "auto",
|
||||
lang: "",
|
||||
body: "This is a notification body",
|
||||
tag: "sometag",
|
||||
icon: "icon.png"
|
||||
};
|
||||
var options = NotificationTest.payload;
|
||||
|
||||
var notification = new Notification("This is a title", options);
|
||||
var promise = Notification.get();
|
||||
promise.then(function (notifications) {
|
||||
|
@ -61,6 +56,11 @@
|
|||
if (notification.tag === options.tag) {
|
||||
ok(true, "should contain newly created notification");
|
||||
for (var key in options) {
|
||||
if (key === "data") {
|
||||
ok(NotificationTest.customDataMatches(notification.data),
|
||||
"data property should match");
|
||||
continue;
|
||||
}
|
||||
is(notification[key], options[key], key + " property should match");
|
||||
}
|
||||
notification.close();
|
||||
|
|
|
@ -14,4 +14,5 @@ dictionary AppNotificationServiceOptions {
|
|||
DOMString dir = "";
|
||||
DOMString lang = "";
|
||||
DOMString tag = "";
|
||||
DOMString data = "";
|
||||
};
|
||||
|
|
|
@ -49,6 +49,9 @@ interface Notification : EventTarget {
|
|||
[Pure]
|
||||
readonly attribute DOMString? icon;
|
||||
|
||||
[Constant]
|
||||
readonly attribute any data;
|
||||
|
||||
void close();
|
||||
};
|
||||
|
||||
|
@ -58,6 +61,7 @@ dictionary NotificationOptions {
|
|||
DOMString body = "";
|
||||
DOMString tag = "";
|
||||
DOMString icon = "";
|
||||
any data = null;
|
||||
};
|
||||
|
||||
dictionary GetNotificationOptions {
|
||||
|
|
|
@ -69,6 +69,7 @@ NS_IMETHODIMP nsAlertsService::ShowAlertNotification(const nsAString & aImageUrl
|
|||
const nsAString & aAlertName,
|
||||
const nsAString & aBidi,
|
||||
const nsAString & aLang,
|
||||
const nsAString & aData,
|
||||
nsIPrincipal * aPrincipal)
|
||||
{
|
||||
if (XRE_GetProcessType() == GeckoProcessType_Content) {
|
||||
|
@ -85,6 +86,7 @@ NS_IMETHODIMP nsAlertsService::ShowAlertNotification(const nsAString & aImageUrl
|
|||
PromiseFlatString(aAlertName),
|
||||
PromiseFlatString(aBidi),
|
||||
PromiseFlatString(aLang),
|
||||
PromiseFlatString(aData),
|
||||
IPC::Principal(aPrincipal));
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -100,7 +102,8 @@ NS_IMETHODIMP nsAlertsService::ShowAlertNotification(const nsAString & aImageUrl
|
|||
if (sysAlerts) {
|
||||
return sysAlerts->ShowAlertNotification(aImageUrl, aAlertTitle, aAlertText, aAlertTextClickable,
|
||||
aAlertCookie, aAlertListener, aAlertName,
|
||||
aBidi, aLang, IPC::Principal(aPrincipal));
|
||||
aBidi, aLang, aData,
|
||||
IPC::Principal(aPrincipal));
|
||||
}
|
||||
|
||||
if (!ShouldShowAlert()) {
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
|
||||
interface nsIPrincipal;
|
||||
|
||||
[scriptable, uuid(160e87e1-d57d-456b-b6ea-17826f6ea7a8)]
|
||||
[scriptable, uuid(d446bede-fcf7-403d-b6b6-5fd67b19ba58)]
|
||||
interface nsIAlertsService : nsISupports
|
||||
{
|
||||
/**
|
||||
|
@ -61,6 +61,7 @@ interface nsIAlertsService : nsISupports
|
|||
[optional] in AString name,
|
||||
[optional] in AString dir,
|
||||
[optional] in AString lang,
|
||||
[optional] in AString data,
|
||||
[optional] in nsIPrincipal principal);
|
||||
|
||||
/**
|
||||
|
|
|
@ -2750,7 +2750,7 @@ nsDownload::SetState(DownloadState aState)
|
|||
message, !removeWhenDone,
|
||||
mPrivate ? NS_LITERAL_STRING("private") : NS_LITERAL_STRING("non-private"),
|
||||
mDownloadManager, EmptyString(), NS_LITERAL_STRING("auto"),
|
||||
EmptyString(), nullptr);
|
||||
EmptyString(), EmptyString(), nullptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -202,6 +202,7 @@ OSXNotificationCenter::ShowAlertNotification(const nsAString & aImageUrl, const
|
|||
const nsAString & aAlertName,
|
||||
const nsAString & aBidi,
|
||||
const nsAString & aLang,
|
||||
const nsAString & aData,
|
||||
nsIPrincipal * aPrincipal)
|
||||
{
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
|
||||
|
|
Загрузка…
Ссылка в новой задаче