Bug 814074 - Send a system message to the application when the application is not running anymore but waits for a notification. r=fabrice. a=blocking-basecamp.

This commit is contained in:
Vivien Nicolas 2012-12-03 15:42:36 +01:00
parent 618d19c490
commit f7ee3900b3
3 changed files with 136 additions and 64 deletions

View File

@ -73,6 +73,10 @@ function getContentWindow() {
return shell.contentBrowser.contentWindow;
}
function debug(str) {
dump(' -*- Shell.js: ' + str + '\n');
}
var shell = {
get CrashSubmit() {
@ -611,41 +615,62 @@ var AlertsHelper = {
if (!detail || !detail.id)
return;
let listener = this._listeners[detail.id];
let uid = detail.id;
let listener = this._listeners[uid];
if (!listener)
return;
let topic = detail.type == "desktop-notification-click" ? "alertclickcallback"
: "alertfinished";
if (detail.id.startsWith("alert")) {
listener.observer.observe(null, topic, listener.cookie);
} else {
listener.mm.sendAsyncMessage("app-notification-return",
{ id: detail.id,
type: detail.type });
if (uid.startsWith("app-notif")) {
listener.mm.sendAsyncMessage("app-notification-return", {
uid: uid,
topic: topic,
target: listener.target
});
} else if (uid.startsWith("alert")) {
try {
listener.observer.observe(null, topic, listener.cookie);
} catch (e) { }
}
// we're done with this notification
if (topic === "alertfinished")
delete this._listeners[detail.id];
if (topic === "alertfinished") {
delete this._listeners[uid];
}
},
registerListener: function alert_registerListener(cookie, alertListener) {
let id = "alert" + this._count++;
this._listeners[id] = { observer: alertListener, cookie: cookie };
return id;
let uid = "alert" + this._count++;
this._listeners[uid] = { observer: alertListener, cookie: cookie };
return uid;
},
registerAppListener: function alertRegisterAppListener(id, mm, title, text,
manifestURL, imageURL) {
this._listeners[id] = {
mm: mm,
title: title,
text: text,
manifestURL: manifestURL,
imageURL: imageURL
};
registerAppListener: function alert_registerAppListener(uid, listener) {
this._listeners[uid] = listener;
let app = DOMApplicationRegistry.getAppByManifestURL(listener.manifestURL);
DOMApplicationRegistry.getManifestFor(app.origin, function(manifest) {
let helper = new ManifestHelper(manifest, app.origin);
let getNotificationURLFor = function(messages) {
if (!messages)
return null;
for (let i = 0; i < messages.length; i++) {
let message = messages[i];
if (message === "notification") {
return helper.fullLaunchPath();
} else if ("notification" in message) {
return helper.resolveFromOrigin(message["notification"]);
}
}
}
listener.target = getNotificationURLFor(manifest.messages);
// Bug 816944 - Support notification messages for entry_points.
});
},
showNotification: function alert_showNotification(imageUrl,
@ -653,13 +678,13 @@ var AlertsHelper = {
text,
textClickable,
cookie,
id,
uid,
name,
manifestUrl) {
function send(appName, appIcon) {
shell.sendChromeEvent({
type: "desktop-notification",
id: id,
id: uid,
icon: imageUrl,
title: title,
text: text,
@ -668,17 +693,17 @@ var AlertsHelper = {
});
}
// If we have a manifest URL, get the icon and title from the manifest
// to prevent spoofing.
if (manifestUrl && manifestUrl.length) {
let app = DOMApplicationRegistry.getAppByManifestURL(manifestUrl);
DOMApplicationRegistry.getManifestFor(app.origin, function(aManifest) {
let helper = new ManifestHelper(aManifest, app.origin);
send(helper.name, helper.iconURLForSize(128));
});
} else {
if (!manifestUrl || !manifestUrl.length) {
send(null, null);
}
// If we have a manifest URL, get the icon and title from the manifest
// to prevent spoofing.
let app = DOMApplicationRegistry.getAppByManifestURL(manifestUrl);
DOMApplicationRegistry.getManifestFor(app.origin, function(aManifest) {
let helper = new ManifestHelper(aManifest, app.origin);
send(helper.name, helper.iconURLForSize(128));
});
},
showAlertNotification: function alert_showAlertNotification(imageUrl,
@ -688,19 +713,25 @@ var AlertsHelper = {
cookie,
alertListener,
name) {
let id = this.registerListener(null, alertListener);
let uid = this.registerListener(null, alertListener);
this.showNotification(imageUrl, title, text, textClickable, cookie,
id, name, null);
uid, name, null);
},
receiveMessage: function alert_receiveMessage(message) {
let data = message.data;
let listener = {
mm: message.target,
title: data.title,
text: data.text,
manifestURL: data.manifestURL,
imageURL: data.imageURL
}
this.registerAppListener(data.uid, listener);
this.registerAppListener(data.id, message.target, data.title, data.text,
data.manifestURL, data.imageURL);
this.showNotification(data.imageURL, data.title, data.text,
data.textClickable, null,
data.id, null, data.manifestURL);
data.uid, null, data.manifestURL);
},
}

View File

@ -9,18 +9,29 @@ const Cc = Components.classes;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
XPCOMUtils.defineLazyServiceGetter(this, "gSystemMessenger",
"@mozilla.org/system-message-internal;1",
"nsISystemMessagesInternal");
XPCOMUtils.defineLazyServiceGetter(this, "uuidGenerator",
"@mozilla.org/uuid-generator;1",
"nsIUUIDGenerator");
XPCOMUtils.defineLazyGetter(this, "cpmm", function() {
return Cc["@mozilla.org/childprocessmessagemanager;1"]
.getService(Ci.nsIMessageSender);
});
function debug(str) {
dump("=*= AlertsService.js : " + str + "\n");
}
// -----------------------------------------------------------------------
// Alerts Service
// -----------------------------------------------------------------------
function AlertsService() {
cpmm.addMessageListener("app-notification-return", this);
this._id = 0;
}
AlertsService.prototype = {
@ -43,43 +54,67 @@ AlertsService.prototype = {
},
// nsIAppNotificationService
_listeners: [],
receiveMessage: function receiveMessage(aMessage) {
let data = aMessage.data;
if (aMessage.name !== "app-notification-return" ||
!this._listeners[data.id]) {
return;
}
let obs = this._listeners[data.id];
let topic = data.type == "desktop-notification-click" ? "alertclickcallback"
: "alertfinished";
obs.observe(null, topic, null);
// we're done with this notification
if (topic === "alertfinished")
delete this._listeners[data.id];
},
// This method is called in the content process, so we remote the call
// to shell.js
showAppNotification: function showAppNotification(aImageURL,
aTitle,
aText,
aTextClickable,
aManifestURL,
aAlertListener) {
let id = "app-notif" + this._id++;
this._listeners[id] = aAlertListener;
let uid = "app-notif-" + uuidGenerator.generateUUID();
this._listeners[uid] = {
observer: aAlertListener,
title: aTitle,
text: aText,
manifestURL: aManifestURL,
imageURL: aImageURL
};
cpmm.sendAsyncMessage("app-notification-send", {
imageURL: aImageURL,
title: aTitle,
text: aText,
textClickable: aTextClickable,
manifestURL: aManifestURL,
id: id
uid: uid
});
},
// AlertsService.js custom implementation
_listeners: [],
receiveMessage: function receiveMessage(aMessage) {
let data = aMessage.data;
let listener = this._listeners[data.uid];
if (aMessage.name !== "app-notification-return" || !listener) {
return;
}
let topic = data.topic;
try {
listener.observer.observe(null, topic, null);
} catch (e) {
// It seems like there is no callbacks anymore, forward the click on
// notification via a system message containing the title/text/icon of
// the notification so the app get a change to react.
if (data.target) {
gSystemMessenger.sendMessage("notification", {
title: listener.title,
body: listener.text,
imageURL: listener.imageURL
},
Services.io.newURI(data.target, null, null),
Services.io.newURI(listener.manifestURL, null, null));
}
cpmm.sendAsyncMessage("app-notification-sysmsg-request", listener);
}
// we're done with this notification
if (topic === "alertfinished") {
delete this._listeners[data.uid];
}
}
};

View File

@ -170,12 +170,18 @@ class AlertServiceObserver: public nsIObserver
const char *aTopic,
const PRUnichar *aData)
{
// forward to parent
if (mNotification)
if (mNotification) {
#ifdef MOZ_B2G
if (NS_FAILED(mNotification->CheckInnerWindowCorrectness()))
return NS_ERROR_NOT_AVAILABLE;
#endif
mNotification->HandleAlertServiceNotification(aTopic);
}
return NS_OK;
};
private:
nsDOMDesktopNotification* mNotification;
};