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

     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",
    26                                    "nsIMessageSender");
    28 this.WebappManager = {
    29   // List of promises for in-progress installations
    30   installations: {},
    32   init: function() {
    33     Services.obs.addObserver(this, "webapps-ask-install", false);
    34     Services.obs.addObserver(this, "webapps-launch", false);
    35     Services.obs.addObserver(this, "webapps-uninstall", false);
    36     cpmm.addMessageListener("Webapps:Install:Return:OK", this);
    37     cpmm.addMessageListener("Webapps:Install:Return:KO", this);
    38     cpmm.addMessageListener("Webapps:UpdateState", this);
    39   },
    41   uninit: function() {
    42     Services.obs.removeObserver(this, "webapps-ask-install");
    43     Services.obs.removeObserver(this, "webapps-launch");
    44     Services.obs.removeObserver(this, "webapps-uninstall");
    45     cpmm.removeMessageListener("Webapps:Install:Return:OK", this);
    46     cpmm.removeMessageListener("Webapps:Install:Return:KO", this);
    47     cpmm.removeMessageListener("Webapps:UpdateState", this);
    48   },
    50   receiveMessage: function(aMessage) {
    51     let data = aMessage.data;
    53     let manifestURL = data.manifestURL ||
    54                       (data.app && data.app.manifestURL) ||
    55                       data.manifest;
    57     if (!this.installations[manifestURL]) {
    58       return;
    59     }
    61     if (aMessage.name == "Webapps:UpdateState") {
    62       if (data.error) {
    63         this.installations[manifestURL].reject(data.error);
    64       } else if (data.app.installState == "installed") {
    65         this.installations[manifestURL].resolve();
    66       }
    67     } else if (aMessage.name == "Webapps:Install:Return:OK" &&
    68                !data.isPackage) {
    69       let manifest = new ManifestHelper(data.app.manifest, data.app.origin);
    70       if (!manifest.appcache_path) {
    71         this.installations[manifestURL].resolve();
    72       }
    73     } else if (aMessage.name == "Webapps:Install:Return:KO") {
    74       this.installations[manifestURL].reject(data.error);
    75     }
    76   },
    78   observe: function(aSubject, aTopic, aData) {
    79     let data = JSON.parse(aData);
    80     data.mm = aSubject;
    82     switch(aTopic) {
    83       case "webapps-ask-install":
    84         let win = this._getWindowForId(data.oid);
    85         if (win && win.location.href == data.from) {
    86           this.doInstall(data, win);
    87         }
    88         break;
    89       case "webapps-launch":
    90         WebappOSUtils.launch(data);
    91         break;
    92       case "webapps-uninstall":
    93         WebappOSUtils.uninstall(data);
    94         break;
    95     }
    96   },
    98   _getWindowForId: function(aId) {
    99     let someWindow = Services.wm.getMostRecentWindow(null);
   100     return someWindow && Services.wm.getOuterWindowWithId(aId);
   101   },
   103   doInstall: function(aData, aWindow) {
   104     let browser = aWindow.QueryInterface(Ci.nsIInterfaceRequestor)
   105                          .getInterface(Ci.nsIWebNavigation)
   106                          .QueryInterface(Ci.nsIDocShell)
   107                          .chromeEventHandler;
   108     let chromeDoc = browser.ownerDocument;
   109     let chromeWin = chromeDoc.defaultView;
   110     let popupProgressContent =
   111       chromeDoc.getElementById("webapps-install-progress-content");
   113     let bundle = chromeWin.gNavigatorBundle;
   115     let jsonManifest = aData.isPackage ? aData.app.updateManifest : aData.app.manifest;
   117     let notification;
   119     let mainAction = {
   120       label: bundle.getString("webapps.install"),
   121       accessKey: bundle.getString("webapps.install.accesskey"),
   122       callback: () => {
   123         notification.remove();
   125         notification = chromeWin.PopupNotifications.
   126                         show(browser,
   127                              "webapps-install-progress",
   128                              bundle.getString("webapps.install.inprogress"),
   129                              "webapps-notification-icon");
   131         let progressMeter = chromeDoc.createElement("progressmeter");
   132         progressMeter.setAttribute("mode", "undetermined");
   133         popupProgressContent.appendChild(progressMeter);
   135         let manifestURL = aData.app.manifestURL;
   137         let cleanup = () => {
   138           popupProgressContent.removeChild(progressMeter);
   139           delete this.installations[manifestURL];
   140           if (Object.getOwnPropertyNames(this.installations).length == 0) {
   141             notification.remove();
   142           }
   143         };
   145         this.installations[manifestURL] = Promise.defer();
   146         this.installations[manifestURL].promise.then(null, (error) => {
   147           Cu.reportError("Error installing webapp: " + error);
   148           cleanup();
   149         });
   151         let nativeApp = new NativeApp(aData.app, jsonManifest,
   152                                       aData.app.categories);
   153         let localDir;
   154         try {
   155           localDir = nativeApp.createProfile();
   156         } catch (ex) {
   157           Cu.reportError("Error installing webapp: " + ex);
   158           DOMApplicationRegistry.denyInstall(aData);
   159           cleanup();
   160           return;
   161         }
   163         DOMApplicationRegistry.confirmInstall(aData, localDir,
   164           (aManifest, aZipPath) => Task.spawn((function*() {
   165             try {
   166               yield nativeApp.install(aManifest, aZipPath);
   167               yield this.installations[manifestURL].promise;
   168               notifyInstallSuccess(aData.app, nativeApp, bundle);
   169             } catch (ex) {
   170               Cu.reportError("Error installing webapp: " + ex);
   171               // TODO: Notify user that the installation has failed
   172             } finally {
   173               cleanup();
   174             }
   175           }).bind(this))
   176         );
   177       }
   178     };
   180     let requestingURI = chromeWin.makeURI(aData.from);
   181     let manifest = new ManifestHelper(jsonManifest, aData.app.origin);
   183     let host;
   184     try {
   185       host = requestingURI.host;
   186     } catch(e) {
   187       host = requestingURI.spec;
   188     }
   190     let message = bundle.getFormattedString("webapps.requestInstall",
   191                                             [manifest.name, host], 2);
   193     notification = chromeWin.PopupNotifications.show(browser,
   194                                                      "webapps-install",
   195                                                      message,
   196                                                      "webapps-notification-icon",
   197                                                      mainAction);
   199   }
   200 }
   202 function notifyInstallSuccess(aApp, aNativeApp, aBundle) {
   203   let launcher = {
   204     observe: function(aSubject, aTopic) {
   205       if (aTopic == "alertclickcallback") {
   206         WebappOSUtils.launch(aApp);
   207       }
   208     }
   209   };
   211   try {
   212     let notifier = Cc["@mozilla.org/alerts-service;1"].
   213                    getService(Ci.nsIAlertsService);
   215     notifier.showAlertNotification(aNativeApp.iconURI.spec,
   216                                    aBundle.getString("webapps.install.success"),
   217                                    aNativeApp.appNameAsFilename,
   218                                    true, null, launcher);
   219   } catch (ex) {}
   220 }

mercurial