browser/modules/WebappManager.jsm

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

michael@0 1 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 2 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
michael@0 3 * You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 4
michael@0 5 this.EXPORTED_SYMBOLS = ["WebappManager"];
michael@0 6
michael@0 7 let Ci = Components.interfaces;
michael@0 8 let Cc = Components.classes;
michael@0 9 let Cu = Components.utils;
michael@0 10
michael@0 11 Cu.import("resource://gre/modules/Services.jsm");
michael@0 12 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
michael@0 13 Cu.import("resource://gre/modules/Webapps.jsm");
michael@0 14 Cu.import("resource://gre/modules/AppsUtils.jsm");
michael@0 15 Cu.import("resource://gre/modules/Task.jsm");
michael@0 16 Cu.import("resource://gre/modules/Promise.jsm");
michael@0 17
michael@0 18 XPCOMUtils.defineLazyModuleGetter(this, "NativeApp",
michael@0 19 "resource://gre/modules/NativeApp.jsm");
michael@0 20
michael@0 21 XPCOMUtils.defineLazyModuleGetter(this, "WebappOSUtils",
michael@0 22 "resource://gre/modules/WebappOSUtils.jsm");
michael@0 23
michael@0 24 XPCOMUtils.defineLazyServiceGetter(this, "cpmm",
michael@0 25 "@mozilla.org/childprocessmessagemanager;1",
michael@0 26 "nsIMessageSender");
michael@0 27
michael@0 28 this.WebappManager = {
michael@0 29 // List of promises for in-progress installations
michael@0 30 installations: {},
michael@0 31
michael@0 32 init: function() {
michael@0 33 Services.obs.addObserver(this, "webapps-ask-install", false);
michael@0 34 Services.obs.addObserver(this, "webapps-launch", false);
michael@0 35 Services.obs.addObserver(this, "webapps-uninstall", false);
michael@0 36 cpmm.addMessageListener("Webapps:Install:Return:OK", this);
michael@0 37 cpmm.addMessageListener("Webapps:Install:Return:KO", this);
michael@0 38 cpmm.addMessageListener("Webapps:UpdateState", this);
michael@0 39 },
michael@0 40
michael@0 41 uninit: function() {
michael@0 42 Services.obs.removeObserver(this, "webapps-ask-install");
michael@0 43 Services.obs.removeObserver(this, "webapps-launch");
michael@0 44 Services.obs.removeObserver(this, "webapps-uninstall");
michael@0 45 cpmm.removeMessageListener("Webapps:Install:Return:OK", this);
michael@0 46 cpmm.removeMessageListener("Webapps:Install:Return:KO", this);
michael@0 47 cpmm.removeMessageListener("Webapps:UpdateState", this);
michael@0 48 },
michael@0 49
michael@0 50 receiveMessage: function(aMessage) {
michael@0 51 let data = aMessage.data;
michael@0 52
michael@0 53 let manifestURL = data.manifestURL ||
michael@0 54 (data.app && data.app.manifestURL) ||
michael@0 55 data.manifest;
michael@0 56
michael@0 57 if (!this.installations[manifestURL]) {
michael@0 58 return;
michael@0 59 }
michael@0 60
michael@0 61 if (aMessage.name == "Webapps:UpdateState") {
michael@0 62 if (data.error) {
michael@0 63 this.installations[manifestURL].reject(data.error);
michael@0 64 } else if (data.app.installState == "installed") {
michael@0 65 this.installations[manifestURL].resolve();
michael@0 66 }
michael@0 67 } else if (aMessage.name == "Webapps:Install:Return:OK" &&
michael@0 68 !data.isPackage) {
michael@0 69 let manifest = new ManifestHelper(data.app.manifest, data.app.origin);
michael@0 70 if (!manifest.appcache_path) {
michael@0 71 this.installations[manifestURL].resolve();
michael@0 72 }
michael@0 73 } else if (aMessage.name == "Webapps:Install:Return:KO") {
michael@0 74 this.installations[manifestURL].reject(data.error);
michael@0 75 }
michael@0 76 },
michael@0 77
michael@0 78 observe: function(aSubject, aTopic, aData) {
michael@0 79 let data = JSON.parse(aData);
michael@0 80 data.mm = aSubject;
michael@0 81
michael@0 82 switch(aTopic) {
michael@0 83 case "webapps-ask-install":
michael@0 84 let win = this._getWindowForId(data.oid);
michael@0 85 if (win && win.location.href == data.from) {
michael@0 86 this.doInstall(data, win);
michael@0 87 }
michael@0 88 break;
michael@0 89 case "webapps-launch":
michael@0 90 WebappOSUtils.launch(data);
michael@0 91 break;
michael@0 92 case "webapps-uninstall":
michael@0 93 WebappOSUtils.uninstall(data);
michael@0 94 break;
michael@0 95 }
michael@0 96 },
michael@0 97
michael@0 98 _getWindowForId: function(aId) {
michael@0 99 let someWindow = Services.wm.getMostRecentWindow(null);
michael@0 100 return someWindow && Services.wm.getOuterWindowWithId(aId);
michael@0 101 },
michael@0 102
michael@0 103 doInstall: function(aData, aWindow) {
michael@0 104 let browser = aWindow.QueryInterface(Ci.nsIInterfaceRequestor)
michael@0 105 .getInterface(Ci.nsIWebNavigation)
michael@0 106 .QueryInterface(Ci.nsIDocShell)
michael@0 107 .chromeEventHandler;
michael@0 108 let chromeDoc = browser.ownerDocument;
michael@0 109 let chromeWin = chromeDoc.defaultView;
michael@0 110 let popupProgressContent =
michael@0 111 chromeDoc.getElementById("webapps-install-progress-content");
michael@0 112
michael@0 113 let bundle = chromeWin.gNavigatorBundle;
michael@0 114
michael@0 115 let jsonManifest = aData.isPackage ? aData.app.updateManifest : aData.app.manifest;
michael@0 116
michael@0 117 let notification;
michael@0 118
michael@0 119 let mainAction = {
michael@0 120 label: bundle.getString("webapps.install"),
michael@0 121 accessKey: bundle.getString("webapps.install.accesskey"),
michael@0 122 callback: () => {
michael@0 123 notification.remove();
michael@0 124
michael@0 125 notification = chromeWin.PopupNotifications.
michael@0 126 show(browser,
michael@0 127 "webapps-install-progress",
michael@0 128 bundle.getString("webapps.install.inprogress"),
michael@0 129 "webapps-notification-icon");
michael@0 130
michael@0 131 let progressMeter = chromeDoc.createElement("progressmeter");
michael@0 132 progressMeter.setAttribute("mode", "undetermined");
michael@0 133 popupProgressContent.appendChild(progressMeter);
michael@0 134
michael@0 135 let manifestURL = aData.app.manifestURL;
michael@0 136
michael@0 137 let cleanup = () => {
michael@0 138 popupProgressContent.removeChild(progressMeter);
michael@0 139 delete this.installations[manifestURL];
michael@0 140 if (Object.getOwnPropertyNames(this.installations).length == 0) {
michael@0 141 notification.remove();
michael@0 142 }
michael@0 143 };
michael@0 144
michael@0 145 this.installations[manifestURL] = Promise.defer();
michael@0 146 this.installations[manifestURL].promise.then(null, (error) => {
michael@0 147 Cu.reportError("Error installing webapp: " + error);
michael@0 148 cleanup();
michael@0 149 });
michael@0 150
michael@0 151 let nativeApp = new NativeApp(aData.app, jsonManifest,
michael@0 152 aData.app.categories);
michael@0 153 let localDir;
michael@0 154 try {
michael@0 155 localDir = nativeApp.createProfile();
michael@0 156 } catch (ex) {
michael@0 157 Cu.reportError("Error installing webapp: " + ex);
michael@0 158 DOMApplicationRegistry.denyInstall(aData);
michael@0 159 cleanup();
michael@0 160 return;
michael@0 161 }
michael@0 162
michael@0 163 DOMApplicationRegistry.confirmInstall(aData, localDir,
michael@0 164 (aManifest, aZipPath) => Task.spawn((function*() {
michael@0 165 try {
michael@0 166 yield nativeApp.install(aManifest, aZipPath);
michael@0 167 yield this.installations[manifestURL].promise;
michael@0 168 notifyInstallSuccess(aData.app, nativeApp, bundle);
michael@0 169 } catch (ex) {
michael@0 170 Cu.reportError("Error installing webapp: " + ex);
michael@0 171 // TODO: Notify user that the installation has failed
michael@0 172 } finally {
michael@0 173 cleanup();
michael@0 174 }
michael@0 175 }).bind(this))
michael@0 176 );
michael@0 177 }
michael@0 178 };
michael@0 179
michael@0 180 let requestingURI = chromeWin.makeURI(aData.from);
michael@0 181 let manifest = new ManifestHelper(jsonManifest, aData.app.origin);
michael@0 182
michael@0 183 let host;
michael@0 184 try {
michael@0 185 host = requestingURI.host;
michael@0 186 } catch(e) {
michael@0 187 host = requestingURI.spec;
michael@0 188 }
michael@0 189
michael@0 190 let message = bundle.getFormattedString("webapps.requestInstall",
michael@0 191 [manifest.name, host], 2);
michael@0 192
michael@0 193 notification = chromeWin.PopupNotifications.show(browser,
michael@0 194 "webapps-install",
michael@0 195 message,
michael@0 196 "webapps-notification-icon",
michael@0 197 mainAction);
michael@0 198
michael@0 199 }
michael@0 200 }
michael@0 201
michael@0 202 function notifyInstallSuccess(aApp, aNativeApp, aBundle) {
michael@0 203 let launcher = {
michael@0 204 observe: function(aSubject, aTopic) {
michael@0 205 if (aTopic == "alertclickcallback") {
michael@0 206 WebappOSUtils.launch(aApp);
michael@0 207 }
michael@0 208 }
michael@0 209 };
michael@0 210
michael@0 211 try {
michael@0 212 let notifier = Cc["@mozilla.org/alerts-service;1"].
michael@0 213 getService(Ci.nsIAlertsService);
michael@0 214
michael@0 215 notifier.showAlertNotification(aNativeApp.iconURI.spec,
michael@0 216 aBundle.getString("webapps.install.success"),
michael@0 217 aNativeApp.appNameAsFilename,
michael@0 218 true, null, launcher);
michael@0 219 } catch (ex) {}
michael@0 220 }

mercurial