--- a/b2g/chrome/content/shell.js
+++ b/b2g/chrome/content/shell.js
@@ -589,16 +589,18 @@ var WebappsHelper = {
case "webapps-install-denied":
DOMApplicationRegistry.denyInstall(installer);
break;
}
},
observe: function webapps_observe(subject, topic, data) {
let json = JSON.parse(data);
+ json.mm = subject;
+
switch(topic) {
case "webapps-launch":
DOMApplicationRegistry.getManifestFor(json.origin, function(aManifest) {
if (!aManifest)
return;
let manifest = new DOMApplicationManifest(aManifest, json.origin);
shell.sendChromeEvent({
--- a/browser/modules/webappsUI.jsm
+++ b/browser/modules/webappsUI.jsm
@@ -24,16 +24,17 @@ let webappsUI = {
uninit: function webappsUI_uninit() {
Services.obs.removeObserver(this, "webapps-ask-install");
Services.obs.removeObserver(this, "webapps-launch");
Services.obs.removeObserver(this, "webapps-uninstall");
},
observe: function webappsUI_observe(aSubject, aTopic, aData) {
let data = JSON.parse(aData);
+ data.mm = aSubject;
switch(aTopic) {
case "webapps-ask-install":
let [chromeWin, browser] = this._getBrowserForId(data.oid);
if (chromeWin)
this.doInstall(data, browser, chromeWin);
break;
case "webapps-launch":
--- a/dom/apps/src/Webapps.js
+++ b/dom/apps/src/Webapps.js
@@ -63,16 +63,17 @@ WebappsRegistry.prototype = {
if (!req)
return;
let app = msg.app;
switch (aMessage.name) {
case "Webapps:Install:Return:OK":
Services.DOMRequest.fireSuccess(req, createApplicationObject(this._window, app));
break;
case "Webapps:Install:Return:KO":
+ dump("XxXxX Webapps:Install:Return:KO\n");
Services.DOMRequest.fireError(req, msg.error || "DENIED");
break;
case "Webapps:GetSelf:Return:OK":
if (msg.apps.length) {
app = msg.apps[0];
Services.DOMRequest.fireSuccess(req, createApplicationObject(this._window, app));
} else {
Services.DOMRequest.fireSuccess(req, null);
@@ -163,16 +164,18 @@ WebappsRegistry.prototype = {
get mgmt() {
if (!this._mgmt)
this._mgmt = new WebappsApplicationMgmt(this._window);
return this._mgmt;
},
uninit: function() {
this._mgmt = null;
+ cpmm.sendAsyncMessage("Webapps:UnregisterForMessages",
+ ["Webapps:Install:Return:OK"]);
},
// mozIDOMApplicationRegistry2 implementation
installPackage: function(aPackageURL, aParams) {
let request = this.createRequest();
let requestID = this.getRequestId(request);
@@ -193,16 +196,18 @@ WebappsRegistry.prototype = {
// nsIDOMGlobalPropertyInitializer implementation
init: function(aWindow) {
this.initHelper(aWindow, ["Webapps:Install:Return:OK", "Webapps:Install:Return:KO",
"Webapps:GetInstalled:Return:OK",
"Webapps:GetSelf:Return:OK", "Webapps:GetSelf:Return:KO"]);
let util = this._window.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils);
this._id = util.outerWindowID;
+ cpmm.sendAsyncMessage("Webapps:RegisterForMessages",
+ ["Webapps:Install:Return:OK"]);
},
classID: Components.ID("{fff440b3-fae2-45c1-bf03-3b5a2e432270}"),
QueryInterface: XPCOMUtils.generateQI([Ci.mozIDOMApplicationRegistry,
#ifdef MOZ_PHOENIX
# Firefox Desktop: installPackage not implemented
#elifdef ANDROID
@@ -265,16 +270,18 @@ WebappsApplication.prototype = {
this.installTime = aApp.installTime;
this.status = "installed";
this.removable = aApp.removable;
this.progress = NaN;
this._onprogress = null;
this.initHelper(aWindow, ["Webapps:Uninstall:Return:OK",
"Webapps:Uninstall:Return:KO",
"Webapps:OfflineCache"]);
+ cpmm.sendAsyncMessage("Webapps:RegisterForMessages",
+ ["Webapps:Uninstall:Return:OK", "Webapps:OfflineCache"]);
},
set onprogress(aCallback) {
this._onprogress = aCallback;
},
get onprogress() {
return this._onprogress;
@@ -295,16 +302,18 @@ WebappsApplication.prototype = {
cpmm.sendAsyncMessage("Webapps:Uninstall", { origin: this.origin,
oid: this._id,
requestID: this.getRequestId(request) });
return request;
},
uninit: function() {
this._onprogress = null;
+ cpmm.sendAsyncMessage("Webapps:UnregisterForMessages",
+ ["Webapps:Uninstall:Return:OK", "Webapps:OfflineCache"]);
},
receiveMessage: function(aMessage) {
var msg = aMessage.json;
let req = this.takeRequest(msg.requestID);
if ((msg.oid != this._id || !req) && aMessage.name !== "Webapps:OfflineCache")
return;
switch (aMessage.name) {
@@ -351,32 +360,37 @@ function WebappsApplicationMgmt(aWindow)
//only pages with perm set can use some functions
this.hasPrivileges = perm == Ci.nsIPermissionManager.ALLOW_ACTION;
this.initHelper(aWindow, ["Webapps:GetAll:Return:OK", "Webapps:GetAll:Return:KO",
"Webapps:Install:Return:OK", "Webapps:Uninstall:Return:OK",
"Webapps:GetNotInstalled:Return:OK"]);
+ cpmm.sendAsyncMessage("Webapps:RegisterForMessages",
+ ["Webapps:Install:Return:OK", "Webapps:Uninstall:Return:OK"]);
+
this._oninstall = null;
this._onuninstall = null;
}
WebappsApplicationMgmt.prototype = {
__proto__: DOMRequestIpcHelper.prototype,
__exposedProps__: {
getAll: 'r',
getNotInstalled: 'r',
oninstall: 'rw',
onuninstall: 'rw'
},
uninit: function() {
this._oninstall = null;
this._onuninstall = null;
+ cpmm.sendAsyncMessage("Webapps:UnregisterForMessages",
+ ["Webapps:Install:Return:OK", "Webapps:Uninstall:Return:OK"]);
},
getAll: function() {
let request = this.createRequest();
cpmm.sendAsyncMessage("Webapps:GetAll", { oid: this._id,
requestID: this.getRequestId(request),
hasPrivileges: this.hasPrivileges });
return request;
--- a/dom/apps/src/Webapps.jsm
+++ b/dom/apps/src/Webapps.jsm
@@ -55,17 +55,18 @@ let DOMApplicationRegistry = {
allAppsLaunchable: false,
init: function() {
this.messages = ["Webapps:Install", "Webapps:Uninstall",
"Webapps:GetSelf",
"Webapps:GetInstalled", "Webapps:GetNotInstalled",
"Webapps:Launch", "Webapps:GetAll",
"Webapps:InstallPackage", "Webapps:GetBasePath",
- "Webapps:GetList"];
+ "Webapps:GetList", "Webapps:RegisterForMessages",
+ "Webapps:UnregisterForMessages"];
this.messages.forEach((function(msgName) {
ppmm.addMessageListener(msgName, this);
}).bind(this));
Services.obs.addObserver(this, "xpcom-shutdown", false);
this.appsFile = FileUtils.getFile(DIRECTORY_NAME,
@@ -314,62 +315,108 @@ let DOMApplicationRegistry = {
} catch (ex) {
Cu.reportError("DOMApplicationRegistry: Could not read from " +
aFile.path + " : " + ex);
if (aCallback)
aCallback(null);
}
},
+ addMessageListener: function(aMsgNames, aMm) {
+ aMsgNames.forEach(function (aMsgName) {
+ if (!(aMsgName in this.children)) {
+ this.children[aMsgName] = [];
+ }
+ this.children[aMsgName].push(aMm);
+ }, this);
+ },
+
+ removeMessageListener: function(aMsgNames, aMm) {
+ aMsgNames.forEach(function (aMsgName) {
+ if (!(aMsgName in this.children)) {
+ return;
+ }
+
+ let index;
+ if ((index = this.children[aMsgName].indexOf(aMm)) != -1) {
+ this.children[aMsgName].splice(index, 1);
+ }
+ }, this);
+ },
+
receiveMessage: function(aMessage) {
// nsIPrefBranch throws if pref does not exist, faster to simply write
// the pref instead of first checking if it is false.
Services.prefs.setBoolPref("dom.mozApps.used", true);
let msg = aMessage.json;
+ let mm = aMessage.target;
+ msg.mm = mm;
switch (aMessage.name) {
case "Webapps:Install":
// always ask for UI to install
- Services.obs.notifyObservers(this, "webapps-ask-install", JSON.stringify(msg));
+ Services.obs.notifyObservers(mm, "webapps-ask-install", JSON.stringify(msg));
break;
case "Webapps:GetSelf":
- this.getSelf(msg);
+ this.getSelf(msg, mm);
break;
case "Webapps:Uninstall":
- Services.obs.notifyObservers(this, "webapps-uninstall", JSON.stringify(msg));
+ Services.obs.notifyObservers(mm, "webapps-uninstall", JSON.stringify(msg));
this.uninstall(msg);
break;
case "Webapps:Launch":
- Services.obs.notifyObservers(this, "webapps-launch", JSON.stringify(msg));
+ Services.obs.notifyObservers(mm, "webapps-launch", JSON.stringify(msg));
break;
case "Webapps:GetInstalled":
- this.getInstalled(msg);
+ this.getInstalled(msg, mm);
break;
case "Webapps:GetNotInstalled":
- this.getNotInstalled(msg);
+ this.getNotInstalled(msg, mm);
break;
case "Webapps:GetAll":
if (msg.hasPrivileges)
- this.getAll(msg);
+ this.getAll(msg, mm);
else
- ppmm.broadcastAsyncMessage("Webapps:GetAll:Return:KO", msg);
+ mm.sendAsyncMessage("Webapps:GetAll:Return:KO", msg);
break;
case "Webapps:InstallPackage":
- this.installPackage(msg);
+ this.installPackage(msg, mm);
break;
case "Webapps:GetBasePath":
return this.webapps[msg.id].basePath;
break;
+ case "Webapps:RegisterForMessages":
+ this.addMessageListener(msg, mm);
+ break;
+ case "Webapps:UnregisterForMessages":
+ this.removeMessageListener(msg, mm);
+ break;
case "Webapps:GetList":
- this.children.push(aMessage.target);
+ this.addMessageListener(["Webapps:AddApp", "Webapps:RemoveApp"], mm);
return this.webapps;
}
},
+ // Some messages can be listened by several content processes:
+ // Webapps:AddApp
+ // Webapps:RemoveApp
+ // Webapps:Install:Return:OK
+ // Webapps:Uninstall:Return:OK
+ // Webapps:OfflineCache
+ broadcastMessage: function broadcastMessage(aMsgName, aContent) {
+ if (!(aMsgName in this.children)) {
+ return;
+ }
+
+ this.children[aMsgName].forEach(function _doBroadcast(aMsgMgr) {
+ aMsgMgr.sendAsyncMessage(aMsgName, aContent);
+ });
+ },
+
_getAppDir: function(aId) {
return FileUtils.getDir(DIRECTORY_NAME, ["webapps", aId], true, true);
},
_writeFile: function ss_writeFile(aFile, aData, aCallbak) {
// Initialize the file output stream.
let ostream = FileUtils.openSafeFileOutputStream(aFile);
@@ -391,17 +438,17 @@ let DOMApplicationRegistry = {
if (packageId) {
let dir = FileUtils.getDir("TmpD", ["webapps", packageId],
true, true);
try {
dir.remove(true);
} catch(e) {
}
}
- ppmm.broadcastAsyncMessage("Webapps:Install:Return:KO", aData);
+ aData.mm.sendAsyncMessage("Webapps:Install:Return:KO", aData);
},
confirmInstall: function(aData, aFromSync, aProfileDir, aOfflineCacheObserver) {
let app = aData.app;
app.removable = true;
let id = app.syncId || this._appId(app.origin);
let localId = this.getAppLocalIdByManifestURL(app.manifestURL);
@@ -453,21 +500,19 @@ let DOMApplicationRegistry = {
appObject.status = "installed";
appObject.name = app.manifest.name;
let manifest = new DOMApplicationManifest(app.manifest, app.origin);
if (!aFromSync)
this._saveApps((function() {
- ppmm.broadcastAsyncMessage("Webapps:Install:Return:OK", aData);
+ this.broadcastMessage("Webapps:Install:Return:OK", aData);
Services.obs.notifyObservers(this, "webapps-sync-install", appNote);
- this.children.forEach(function(aMsgMgr) {
- aMsgMgr.sendAsyncMessage("Webapps:AddApp", { id: id, app: appObject });
- });
+ this.broadcastMessage("Webapps:AddApp", { id: id, app: appObject });
}).bind(this));
#ifdef MOZ_SYS_MSG
this._registerSystemMessages(app.manifest, app);
this._registerActivities(app.manifest, app);
#endif
// if the manifest has an appcache_path property, use it to populate the appcache
@@ -534,17 +579,17 @@ let DOMApplicationRegistry = {
aData[index].manifest = aJSON;
if (index == aData.length - 1)
aFinalCallback(aData);
else
this._readManifests(aData, aFinalCallback, index + 1);
}).bind(this));
},
- installPackage: function(aData) {
+ installPackage: function(aData, aMm) {
// Here are the steps when installing a package:
// - create a temp directory where to store the app.
// - download the zip in this directory.
// - extract the manifest from the zip and check it.
// - ask confirmation to the user.
// - add the new app to the registry.
// If we fail at any step, we backout the previous ones and return an error.
@@ -579,20 +624,20 @@ let DOMApplicationRegistry = {
return true;
}
// Removes the directory we created, and sends an error to the DOM side.
function cleanup(aError) {
try {
dir.remove(true);
} catch (e) { }
- ppmm.broadcastAsyncMessage("Webapps:Install:Return:KO",
- { oid: aData.oid,
- requestID: aData.requestID,
- error: aError });
+ aMm.sendAsyncMessage("Webapps:Install:Return:KO",
+ { oid: aData.oid,
+ requestID: aData.requestID,
+ error: aError });
}
function getInferedStatus() {
// XXX Update once we have digital signatures (bug 772365)
return Ci.nsIPrincipal.APP_STATUS_INSTALLED;
}
function getAppManifestStatus(aManifest) {
@@ -720,101 +765,99 @@ let DOMApplicationRegistry = {
let dir = this._getAppDir(id);
try {
dir.remove(true);
} catch (e) {}
delete this.webapps[id];
this._saveApps((function() {
- ppmm.broadcastAsyncMessage("Webapps:Uninstall:Return:OK", aData);
+ this.broadcastMessage("Webapps:Uninstall:Return:OK", aData);
Services.obs.notifyObservers(this, "webapps-sync-uninstall", appNote);
- this.children.forEach(function(aMsgMgr) {
- aMsgMgr.broadcastAsyncMessage("Webapps:RemoveApp", { id: id });
- });
+ this.broadcastMessage("Webapps:RemoveApp", { id: id });
}).bind(this));
}
if (!found) {
- ppmm.broadcastAsyncMessage("Webapps:Uninstall:Return:KO", aData);
+ aData.mm.broadcastMessage("Webapps:Uninstall:Return:KO", aData);
}
},
- getSelf: function(aData) {
+ getSelf: function(aData, aMm) {
aData.apps = [];
let tmp = [];
let id = this._appId(aData.origin);
if (id && this._isLaunchable(this.webapps[id].origin)) {
let app = AppsUtils.cloneAppObject(this.webapps[id]);
aData.apps.push(app);
tmp.push({ id: id });
}
this._readManifests(tmp, (function(aResult) {
for (let i = 0; i < aResult.length; i++)
aData.apps[i].manifest = aResult[i].manifest;
- ppmm.broadcastAsyncMessage("Webapps:GetSelf:Return:OK", aData);
+ aMm.sendAsyncMessage("Webapps:GetSelf:Return:OK", aData);
}).bind(this));
},
- getInstalled: function(aData) {
+ getInstalled: function(aData, aMm) {
aData.apps = [];
let tmp = [];
for (let id in this.webapps) {
if (this.webapps[id].installOrigin == aData.origin &&
this._isLaunchable(this.webapps[id].origin)) {
aData.apps.push(AppsUtils.cloneAppObject(this.webapps[id]));
tmp.push({ id: id });
}
}
this._readManifests(tmp, (function(aResult) {
for (let i = 0; i < aResult.length; i++)
aData.apps[i].manifest = aResult[i].manifest;
- ppmm.broadcastAsyncMessage("Webapps:GetInstalled:Return:OK", aData);
+ aMm.sendAsyncMessage("Webapps:GetInstalled:Return:OK", aData);
}).bind(this));
},
- getNotInstalled: function(aData) {
+ getNotInstalled: function(aData, aMm) {
aData.apps = [];
let tmp = [];
for (let id in this.webapps) {
if (!this._isLaunchable(this.webapps[id].origin)) {
aData.apps.push(AppsUtils.cloneAppObject(this.webapps[id]));
tmp.push({ id: id });
}
}
this._readManifests(tmp, (function(aResult) {
for (let i = 0; i < aResult.length; i++)
aData.apps[i].manifest = aResult[i].manifest;
- ppmm.broadcastAsyncMessage("Webapps:GetNotInstalled:Return:OK", aData);
+ aMm.sendAsyncMessage("Webapps:GetNotInstalled:Return:OK", aData);
}).bind(this));
},
- getAll: function(aData) {
+ getAll: function(aData, aMm) {
aData.apps = [];
let tmp = [];
for (let id in this.webapps) {
let app = AppsUtils.cloneAppObject(this.webapps[id]);
if (!this._isLaunchable(app.origin))
continue;
aData.apps.push(app);
tmp.push({ id: id });
}
this._readManifests(tmp, (function(aResult) {
for (let i = 0; i < aResult.length; i++)
aData.apps[i].manifest = aResult[i].manifest;
- ppmm.broadcastAsyncMessage("Webapps:GetAll:Return:OK", aData);
+ aMm.sendAsyncMessage("Webapps:GetAll:Return:OK", aData);
}).bind(this));
},
getManifestFor: function(aOrigin, aCallback) {
if (!aCallback)
return;
let id = this._appId(aOrigin);
@@ -878,25 +921,25 @@ let DOMApplicationRegistry = {
continue;
let origin = this.webapps[record.id].origin;
delete this.webapps[record.id];
let dir = this._getAppDir(record.id);
try {
dir.remove(true);
} catch (e) {
}
- ppmm.broadcastAsyncMessage("Webapps:Uninstall:Return:OK", { origin: origin });
+ this.broadcastMessage("Webapps:Uninstall:Return:OK", { origin: origin });
} else {
if (this.webapps[record.id]) {
this.webapps[record.id] = record.value;
delete this.webapps[record.id].manifest;
} else {
let data = { app: record.value };
this.confirmInstall(data, true);
- ppmm.broadcastAsyncMessage("Webapps:Install:Return:OK", data);
+ this.broadcastMessage("Webapps:Install:Return:OK", data);
}
}
}
this._saveApps(aCallback);
},
getAllIDs: function() {
let apps = {};
@@ -992,17 +1035,19 @@ AppcacheObserver.prototype = {
// nsIOfflineCacheUpdateObserver implementation
updateStateChanged: function appObs_Update(aUpdate, aState) {
let mustSave = false;
let app = this.app;
let setStatus = function appObs_setStatus(aStatus) {
mustSave = (app.status != aStatus);
app.status = aStatus;
- ppmm.broadcastAsyncMessage("Webapps:OfflineCache", { manifest: app.manifestURL, status: aStatus });
+ DOMApplicationRegistry.broadcastMessage("Webapps:OfflineCache",
+ { manifest: app.manifestURL,
+ status: aStatus });
}
switch (aState) {
case Ci.nsIOfflineCacheUpdateObserver.STATE_ERROR:
aUpdate.removeObserver(this);
setStatus("cache-error");
break;
case Ci.nsIOfflineCacheUpdateObserver.STATE_NOUPDATE:
--- a/mobile/android/chrome/content/browser.js
+++ b/mobile/android/chrome/content/browser.js
@@ -6155,16 +6155,17 @@ var WebappsUI = {
Services.obs.removeObserver(this, "WebApps:InstallMarketplace", false);
},
DEFAULT_PREFS_FILENAME: "default-prefs.js",
observe: function observe(aSubject, aTopic, aData) {
let data = {};
try { data = JSON.parse(aData); }
+ data.mm = aSubject;
catch(ex) { }
switch (aTopic) {
case "webapps-install-error":
let msg = "";
switch (aData) {
case "INVALID_MANIFEST":
case "MANIFEST_PARSE_ERROR":
msg = Strings.browser.GetStringFromName("webapps.manifestInstallError");
--- a/webapprt/WebappsHandler.jsm
+++ b/webapprt/WebappsHandler.jsm
@@ -19,16 +19,17 @@ let WebappsHandler = {
init: function() {
Services.obs.addObserver(this, "webapps-ask-install", false);
Services.obs.addObserver(this, "webapps-launch", false);
Services.obs.addObserver(this, "webapps-uninstall", false);
},
observe: function(subject, topic, data) {
data = JSON.parse(data);
+ data.mm = subject;
switch (topic) {
case "webapps-ask-install":
let chromeWin = this._getWindowByOuterId(data.oid);
if (chromeWin)
this.doInstall(data, chromeWin);
break;
case "webapps-launch":
--- a/webapprt/content/mochitest.js
+++ b/webapprt/content/mochitest.js
@@ -56,16 +56,17 @@ function becomeWebapp(manifestURL, param
// We load DOMApplicationRegistry into a local scope to avoid appearing
// to leak it.
let scope = {};
Cu.import("resource://gre/modules/Webapps.jsm", scope);
scope.DOMApplicationRegistry.confirmInstall(JSON.parse(data));
let installRecord = JSON.parse(data);
+ installRecord.mm = subj;
installRecord.registryDir = Services.dirsvc.get("ProfD", Ci.nsIFile).path;
WebappRT.config = installRecord;
onBecome();
}
Services.obs.addObserver(observeInstall, "webapps-ask-install", false);
// Step 1: Install the app at the URL specified by the manifest.