Skip to content

Commit

Permalink
Bug 967475 - Implement mozChromeNotifications API. r=mhenretty, r=bent
Browse files Browse the repository at this point in the history
--HG--
extra : rebase_source : 595b53c85f031784bd77591d4e0593e60b39ccfd
  • Loading branch information
Alexandre Lissy committed May 8, 2014
1 parent e75a7cb commit 8bf8be1
Show file tree
Hide file tree
Showing 23 changed files with 614 additions and 62 deletions.
13 changes: 8 additions & 5 deletions b2g/components/AlertsHelper.jsm
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,8 @@ let AlertsHelper = {
lang: listener.lang,
dir: listener.dir,
id: listener.id,
tag: listener.tag
tag: listener.tag,
timestamp: listener.timestamp
},
Services.io.newURI(listener.target, null, null),
Services.io.newURI(listener.manifestURL, null, null)
Expand Down Expand Up @@ -194,7 +195,7 @@ let AlertsHelper = {
},

showNotification: function(imageURL, title, text, textClickable, cookie,
uid, bidi, lang, manifestURL) {
uid, bidi, lang, manifestURL, timestamp) {
function send(appName, appIcon) {
SystemAppProxy._sendCustomEvent(kMozChromeNotificationEvent, {
type: kDesktopNotification,
Expand All @@ -206,7 +207,8 @@ let AlertsHelper = {
lang: lang,
appName: appName,
appIcon: appIcon,
manifestURL: manifestURL
manifestURL: manifestURL,
timestamp: timestamp
});
}

Expand Down Expand Up @@ -248,12 +250,13 @@ let AlertsHelper = {
lang: details.lang || undefined,
id: details.id || undefined,
dir: details.dir || undefined,
tag: details.tag || undefined
tag: details.tag || undefined,
timestamp: details.timestamp || 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.lang, details.manifestURL, details.timestamp);
},

closeAlert: function(name) {
Expand Down
8 changes: 6 additions & 2 deletions b2g/components/AlertsService.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ const kMessageAlertNotificationSend = "alert-notification-send";
const kMessageAlertNotificationClose = "alert-notification-close";

const kTopicAlertFinished = "alertfinished";
const kTopicAlertClickCallback = "alertclickcallback";

function AlertsService() {
Services.obs.addObserver(this, "xpcom-shutdown", false);
Expand Down Expand Up @@ -103,7 +104,8 @@ AlertsService.prototype = {
id: aDetails.id || undefined,
dbId: aDetails.dbId || undefined,
dir: aDetails.dir || undefined,
tag: aDetails.tag || undefined
tag: aDetails.tag || undefined,
timestamp: aDetails.timestamp || undefined
};

cpmm.sendAsyncMessage(kMessageAppNotificationSend, {
Expand Down Expand Up @@ -135,14 +137,16 @@ AlertsService.prototype = {
// the notification so the app get a change to react.
if (data.target) {
gSystemMessenger.sendMessage(kNotificationSystemMessageName, {
clicked: (topic === kTopicAlertClickCallback),
title: listener.title,
body: listener.text,
imageURL: listener.imageURL,
lang: listener.lang,
dir: listener.dir,
id: listener.id,
tag: listener.tag,
dbId: listener.dbId
dbId: listener.dbId,
timestamp: listener.timestamp
},
Services.io.newURI(data.target, null, null),
Services.io.newURI(listener.manifestURL, null, null)
Expand Down
2 changes: 2 additions & 0 deletions b2g/installer/package-manifest.in
Original file line number Diff line number Diff line change
Expand Up @@ -336,6 +336,8 @@
@BINPATH@/components/zipwriter.xpt

; JavaScript components
@BINPATH@/components/ChromeNotifications.js
@BINPATH@/components/ChromeNotifications.manifest
@BINPATH@/components/ConsoleAPI.manifest
@BINPATH@/components/ConsoleAPIStorage.js
@BINPATH@/components/BrowserElementParent.manifest
Expand Down
2 changes: 2 additions & 0 deletions browser/installer/package-manifest.in
Original file line number Diff line number Diff line change
Expand Up @@ -344,6 +344,8 @@
@BINPATH@/components/telemetry.xpt

; JavaScript components
@BINPATH@/components/ChromeNotifications.js
@BINPATH@/components/ChromeNotifications.manifest
@BINPATH@/components/ConsoleAPI.manifest
@BINPATH@/components/ConsoleAPIStorage.js
@BINPATH@/components/BrowserElementParent.manifest
Expand Down
9 changes: 9 additions & 0 deletions dom/bindings/BindingUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include "mozilla/DebugOnly.h"
#include "mozilla/FloatingPoint.h"
#include "mozilla/Assertions.h"
#include "mozilla/Preferences.h"

#include "AccessCheck.h"
#include "jsfriendapi.h"
Expand Down Expand Up @@ -2155,6 +2156,10 @@ ConvertJSValueToByteString(JSContext* cx, JS::Handle<JS::Value> v,
bool
IsInPrivilegedApp(JSContext* aCx, JSObject* aObj)
{
if (Preferences::GetBool("dom.ignore_webidl_scope_checks", false)) {
return true;
}

using mozilla::dom::workers::GetWorkerPrivateFromContext;
if (!NS_IsMainThread()) {
return GetWorkerPrivateFromContext(aCx)->IsInPrivilegedApp();
Expand All @@ -2169,6 +2174,10 @@ IsInPrivilegedApp(JSContext* aCx, JSObject* aObj)
bool
IsInCertifiedApp(JSContext* aCx, JSObject* aObj)
{
if (Preferences::GetBool("dom.ignore_webidl_scope_checks", false)) {
return true;
}

using mozilla::dom::workers::GetWorkerPrivateFromContext;
if (!NS_IsMainThread()) {
return GetWorkerPrivateFromContext(aCx)->IsInCertifiedApp();
Expand Down
9 changes: 7 additions & 2 deletions dom/interfaces/notification/nsINotificationStorage.idl
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ interface nsINotificationStorageCallback : nsISupports
/**
* Interface for notification persistence layer.
*/
[scriptable, uuid(b177b080-2a23-11e3-8224-0800200c9a66)]
[scriptable, uuid(cc4656d7-2a2a-47f1-8016-55891e833d64)]
interface nsINotificationStorage : nsISupports
{

Expand All @@ -55,6 +55,10 @@ interface nsINotificationStorage : nsISupports
* @param body: the notification body
* @param tag: notification tag, will replace any existing
* notifications with same origin/tag pair
* @param alertName: the alert identifier as used by system app.
* Stored in the database to avoid re-computing
* it. Built from origin and tag or id depending
* whether there is a tag defined.
*/
void put(in DOMString origin,
in DOMString id,
Expand All @@ -63,7 +67,8 @@ interface nsINotificationStorage : nsISupports
in DOMString lang,
in DOMString body,
in DOMString tag,
in DOMString icon);
in DOMString icon,
in DOMString alertName);

/**
* Retrieve a list of notifications.
Expand Down
113 changes: 113 additions & 0 deletions dom/src/notification/ChromeNotifications.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */

"use strict";

const DEBUG = false;

function debug(s) {
dump("-*- ChromeNotifications.js: " + s + "\n");
}

const Ci = Components.interfaces;
const Cu = Components.utils;

Cu.import("resource://gre/modules/XPCOMUtils.jsm");

XPCOMUtils.defineLazyModuleGetter(this, "Services",
"resource://gre/modules/Services.jsm");

XPCOMUtils.defineLazyServiceGetter(this, "cpmm",
"@mozilla.org/childprocessmessagemanager;1",
"nsIMessageSender");

XPCOMUtils.defineLazyServiceGetter(this, "appNotifier",
"@mozilla.org/system-alerts-service;1",
"nsIAppNotificationService");

const CHROMENOTIFICATIONS_CID = "{74f94093-8b37-497e-824f-c3b250a911da}";
const CHROMENOTIFICATIONS_CONTRACTID = "@mozilla.org/mozChromeNotifications;1";

function ChromeNotifications() {
this.innerWindowID = null;
this.resendCallback = null;
}

ChromeNotifications.prototype = {

init: function(aWindow) {
let util = aWindow.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindowUtils);
this.innerWindowID = util.currentInnerWindowID;
Services.obs.addObserver(this, "inner-window-destroyed", false);
cpmm.addMessageListener("Notification:GetAllCrossOrigin:Return:OK", this);
},

performResend: function(notifications) {
let resentNotifications = 0;

notifications.forEach(function(notification) {
appNotifier.showAppNotification(
notification.icon,
notification.title,
notification.body,
null,
{
manifestURL: notification.origin,
id: notification.alertName,
dir: notification.dir,
lang: notification.lang,
tag: notification.tag,
dbId: notification.id,
timestamp: notification.timestamp
}
);
resentNotifications++;
});

try {
this.resendCallback && this.resendCallback(resentNotifications);
} catch (ex) {
if (DEBUG) debug("Content sent exception: " + ex);
}
},

mozResendAllNotifications: function(resendCallback) {
this.resendCallback = resendCallback;
cpmm.sendAsyncMessage("Notification:GetAllCrossOrigin", {});
},

receiveMessage: function(message) {
switch (message.name) {
case "Notification:GetAllCrossOrigin:Return:OK":
this.performResend(message.data.notifications);
break;

default:
if (DEBUG) { debug("Unrecognized message: " + message.name); }
break;
}
},

observe: function(aSubject, aTopic, aData) {
if (DEBUG) debug("Topic: " + aTopic);
if (aTopic == "inner-window-destroyed") {
let wId = aSubject.QueryInterface(Ci.nsISupportsPRUint64).data;
if (wId != this.innerWindowID) {
return;
}
Services.obs.removeObserver(this, "inner-window-destroyed");
cpmm.removeMessageListener("Notification:GetAllCrossOrigin:Return:OK", this);
}
},

classID : Components.ID(CHROMENOTIFICATIONS_CID),
contractID : CHROMENOTIFICATIONS_CONTRACTID,
QueryInterface: XPCOMUtils.generateQI([Ci.nsIChromeNotifications,
Ci.nsIDOMGlobalPropertyInitializer,
Ci.nsIObserver,
Ci.nsIMessageListener]),
};

this.NSGetFactory = XPCOMUtils.generateNSGetFactory([ChromeNotifications]);
3 changes: 3 additions & 0 deletions dom/src/notification/ChromeNotifications.manifest
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# ChromeNotifications.js
component {74f94093-8b37-497e-824f-c3b250a911da} ChromeNotifications.js
contract @mozilla.org/mozChromeNotifications;1 {74f94093-8b37-497e-824f-c3b250a911da}
53 changes: 25 additions & 28 deletions dom/src/notification/Notification.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -423,6 +423,22 @@ Notification::Notification(const nsAString& aID, const nsAString& aTitle, const
mID(aID), mTitle(aTitle), mBody(aBody), mDir(aDir), mLang(aLang),
mTag(aTag), mIconUrl(aIconUrl), mIsClosed(false)
{
nsAutoString alertName;
DebugOnly<nsresult> rv = GetOrigin(GetOwner(), alertName);
MOZ_ASSERT(NS_SUCCEEDED(rv), "GetOrigin should not have failed");

// Get the notification name that is unique per origin + tag/ID.
// The name of the alert is of the form origin#tag/ID.
alertName.AppendLiteral("#");
if (!mTag.IsEmpty()) {
alertName.Append(NS_LITERAL_STRING("tag:"));
alertName.Append(mTag);
} else {
alertName.Append(NS_LITERAL_STRING("notag:"));
alertName.Append(mID);
}

mAlertName = alertName;
}

// static
Expand Down Expand Up @@ -462,14 +478,19 @@ Notification::Constructor(const GlobalObject& aGlobal,

nsString id;
notification->GetID(id);

nsString alertName;
notification->GetAlertName(alertName);

aRv = notificationStorage->Put(origin,
id,
aTitle,
DirectionToString(aOptions.mDir),
aOptions.mLang,
aOptions.mBody,
aOptions.mTag,
aOptions.mIcon);
aOptions.mIcon,
alertName);
if (aRv.Failed()) {
return nullptr;
}
Expand Down Expand Up @@ -557,10 +578,6 @@ Notification::ShowInternal()

nsCOMPtr<nsIObserver> observer = new NotificationObserver(this);

nsString alertName;
rv = GetAlertName(alertName);
NS_ENSURE_SUCCESS_VOID(rv);

#ifdef MOZ_B2G
nsCOMPtr<nsIAppNotificationService> appNotifier =
do_GetService("@mozilla.org/system-alerts-service;1");
Expand All @@ -578,7 +595,7 @@ Notification::ShowInternal()
AppNotificationServiceOptions ops;
ops.mTextClickable = true;
ops.mManifestURL = manifestUrl;
ops.mId = alertName;
ops.mId = mAlertName;
ops.mDbId = mID;
ops.mDir = DirectionToString(mDir);
ops.mLang = mLang;
Expand All @@ -602,7 +619,7 @@ Notification::ShowInternal()
nsString uniqueCookie = NS_LITERAL_STRING("notification:");
uniqueCookie.AppendInt(sCount++);
alertService->ShowAlertNotification(absoluteUrl, mTitle, mBody, true,
uniqueCookie, observer, alertName,
uniqueCookie, observer, mAlertName,
DirectionToString(mDir), mLang,
GetPrincipal());
}
Expand Down Expand Up @@ -771,10 +788,8 @@ Notification::CloseInternal()
nsCOMPtr<nsIAlertsService> alertService =
do_GetService(NS_ALERTSERVICE_CONTRACTID);
if (alertService) {
nsString alertName;
rv = GetAlertName(alertName);
if (NS_SUCCEEDED(rv)) {
alertService->CloseAlert(alertName, GetPrincipal());
alertService->CloseAlert(mAlertName, GetPrincipal());
}
}
}
Expand Down Expand Up @@ -812,24 +827,6 @@ Notification::GetOrigin(nsPIDOMWindow* aWindow, nsString& aOrigin)
return NS_OK;
}

nsresult
Notification::GetAlertName(nsString& aAlertName)
{
// Get the notification name that is unique per origin + tag/ID.
// The name of the alert is of the form origin#tag/ID.
nsresult rv = GetOrigin(GetOwner(), aAlertName);
NS_ENSURE_SUCCESS(rv, rv);
aAlertName.AppendLiteral("#");
if (!mTag.IsEmpty()) {
aAlertName.Append(NS_LITERAL_STRING("tag:"));
aAlertName.Append(mTag);
} else {
aAlertName.Append(NS_LITERAL_STRING("notag:"));
aAlertName.Append(mID);
}
return NS_OK;
}

} // namespace dom
} // namespace mozilla

Loading

0 comments on commit 8bf8be1

Please sign in to comment.