1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
3 * You can obtain one at http://mozilla.org/MPL/2.0/. */
5 this.EXPORTED_SYMBOLS = ["WebappManager"];
7 let Ci = Components.interfaces;
8 let Cc = Components.classes;
9 let Cu = Components.utils;
11 Cu.import("resource://gre/modules/Services.jsm");
12 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
13 Cu.import("resource://gre/modules/Webapps.jsm");
14 Cu.import("resource://gre/modules/AppsUtils.jsm");
15 Cu.import("resource://gre/modules/Task.jsm");
16 Cu.import("resource://gre/modules/Promise.jsm");
18 XPCOMUtils.defineLazyModuleGetter(this, "NativeApp",
19 "resource://gre/modules/NativeApp.jsm");
21 XPCOMUtils.defineLazyModuleGetter(this, "WebappOSUtils",
22 "resource://gre/modules/WebappOSUtils.jsm");
24 XPCOMUtils.defineLazyServiceGetter(this, "cpmm",
25 "@mozilla.org/childprocessmessagemanager;1",
28 this.WebappManager = {
29 // List of promises for in-progress installations
33 Services.obs.addObserver(this, "webapps-ask-install", false);
34 Services.obs.addObserver(this, "webapps-ask-uninstall", false);
35 Services.obs.addObserver(this, "webapps-launch", false);
36 Services.obs.addObserver(this, "webapps-uninstall", false);
37 cpmm.addMessageListener("Webapps:Install:Return:OK", this);
38 cpmm.addMessageListener("Webapps:Install:Return:KO", this);
39 cpmm.addMessageListener("Webapps:UpdateState", this);
43 Services.obs.removeObserver(this, "webapps-ask-install");
44 Services.obs.removeObserver(this, "webapps-ask-uninstall");
45 Services.obs.removeObserver(this, "webapps-launch");
46 Services.obs.removeObserver(this, "webapps-uninstall");
47 cpmm.removeMessageListener("Webapps:Install:Return:OK", this);
48 cpmm.removeMessageListener("Webapps:Install:Return:KO", this);
49 cpmm.removeMessageListener("Webapps:UpdateState", this);
52 receiveMessage: function(aMessage) {
53 let data = aMessage.data;
55 let manifestURL = data.manifestURL ||
56 (data.app && data.app.manifestURL) ||
59 if (!this.installations[manifestURL]) {
63 if (aMessage.name == "Webapps:UpdateState") {
65 this.installations[manifestURL].reject(data.error);
66 } else if (data.app.installState == "installed") {
67 this.installations[manifestURL].resolve();
69 } else if (aMessage.name == "Webapps:Install:Return:OK" &&
71 let manifest = new ManifestHelper(data.app.manifest,
73 data.app.manifestURL);
74 if (!manifest.appcache_path) {
75 this.installations[manifestURL].resolve();
77 } else if (aMessage.name == "Webapps:Install:Return:KO") {
78 this.installations[manifestURL].reject(data.error);
82 observe: function(aSubject, aTopic, aData) {
83 let data = JSON.parse(aData);
88 case "webapps-ask-install":
89 win = this._getWindowForId(data.oid);
90 if (win && win.location.href == data.from) {
91 this.doInstall(data, win);
94 case "webapps-ask-uninstall":
95 win = this._getWindowForId(data.windowId);
96 if (win && win.location.href == data.from) {
97 this.doUninstall(data, win);
100 case "webapps-launch":
101 WebappOSUtils.launch(data);
103 case "webapps-uninstall":
104 WebappOSUtils.uninstall(data);
109 _getWindowForId: function(aId) {
110 let someWindow = Services.wm.getMostRecentWindow(null);
111 return someWindow && Services.wm.getOuterWindowWithId(aId);
114 doInstall: function(aData, aWindow) {
115 let browser = aWindow.QueryInterface(Ci.nsIInterfaceRequestor)
116 .getInterface(Ci.nsIWebNavigation)
117 .QueryInterface(Ci.nsIDocShell)
119 let chromeDoc = browser.ownerDocument;
120 let chromeWin = chromeDoc.defaultView;
121 let popupProgressContent =
122 chromeDoc.getElementById("webapps-install-progress-content");
124 let bundle = chromeWin.gNavigatorBundle;
126 let jsonManifest = aData.isPackage ? aData.app.updateManifest : aData.app.manifest;
131 label: bundle.getString("webapps.install"),
132 accessKey: bundle.getString("webapps.install.accesskey"),
134 notification.remove();
136 notification = chromeWin.PopupNotifications.
138 "webapps-install-progress",
139 bundle.getString("webapps.install.inprogress"),
140 "webapps-notification-icon");
142 let progressMeter = chromeDoc.createElement("progressmeter");
143 progressMeter.setAttribute("mode", "undetermined");
144 popupProgressContent.appendChild(progressMeter);
146 let manifestURL = aData.app.manifestURL;
148 let nativeApp = new NativeApp(aData.app, jsonManifest,
149 aData.app.categories);
151 this.installations[manifestURL] = Promise.defer();
152 this.installations[manifestURL].promise.then(() => {
153 notifyInstallSuccess(aData.app, nativeApp, bundle);
155 Cu.reportError("Error installing webapp: " + error);
157 popupProgressContent.removeChild(progressMeter);
158 delete this.installations[manifestURL];
159 if (Object.getOwnPropertyNames(this.installations).length == 0) {
160 notification.remove();
166 localDir = nativeApp.createProfile();
168 DOMApplicationRegistry.denyInstall(aData);
172 DOMApplicationRegistry.confirmInstall(aData, localDir,
173 Task.async(function*(aApp, aManifest, aZipPath) {
175 yield nativeApp.install(aApp, aManifest, aZipPath);
177 Cu.reportError("Error installing webapp: " + ex);
185 let requestingURI = chromeWin.makeURI(aData.from);
187 let manifest = new ManifestHelper(jsonManifest, app.origin, app.manifestURL);
191 host = requestingURI.host;
193 host = requestingURI.spec;
196 let message = bundle.getFormattedString("webapps.requestInstall",
197 [manifest.name, host], 2);
199 notification = chromeWin.PopupNotifications.show(browser,
202 "webapps-notification-icon",
207 doUninstall: function(aData, aWindow) {
208 let browser = aWindow.QueryInterface(Ci.nsIInterfaceRequestor)
209 .getInterface(Ci.nsIWebNavigation)
210 .QueryInterface(Ci.nsIDocShell)
212 let chromeDoc = browser.ownerDocument;
213 let chromeWin = chromeDoc.defaultView;
215 let bundle = chromeWin.gNavigatorBundle;
216 let jsonManifest = aData.app.manifest;
221 label: bundle.getString("webapps.uninstall"),
222 accessKey: bundle.getString("webapps.uninstall.accesskey"),
224 notification.remove();
225 DOMApplicationRegistry.confirmUninstall(aData);
229 let secondaryAction = {
230 label: bundle.getString("webapps.doNotUninstall"),
231 accessKey: bundle.getString("webapps.doNotUninstall.accesskey"),
233 notification.remove();
234 DOMApplicationRegistry.denyUninstall(aData, "USER_DECLINED");
238 let manifest = new ManifestHelper(jsonManifest, aData.app.origin,
239 aData.app.manifestURL);
241 let message = bundle.getFormattedString("webapps.requestUninstall",
244 notification = chromeWin.PopupNotifications.show(
245 browser, "webapps-uninstall", message,
246 "webapps-notification-icon",
247 mainAction, [secondaryAction]);
251 function notifyInstallSuccess(aApp, aNativeApp, aBundle) {
253 observe: function(aSubject, aTopic) {
254 if (aTopic == "alertclickcallback") {
255 WebappOSUtils.launch(aApp);
261 let notifier = Cc["@mozilla.org/alerts-service;1"].
262 getService(Ci.nsIAlertsService);
264 notifier.showAlertNotification(aNativeApp.iconURI.spec,
265 aBundle.getString("webapps.install.success"),
266 aNativeApp.appNameAsFilename,
267 true, null, launcher);