Bug 919496 - [app manager] Once an app has been installed, it doesn't show up in the 'installed app' tab. r=ochameau
authorPaul Rouget <paul@mozilla.com>
Sat, 05 Oct 2013 10:43:06 -0400
changeset 149973 daf000728e1ee467c9eadfb52a83f6981f521ead
parent 149972 9e6755e523d67d09effb369804c15402c224c4d1
child 149974 87fd173f56f185c01a652d984ada2accc296f8a4
push id25411
push userphilringnalda@gmail.com
push dateSun, 06 Oct 2013 00:39:03 +0000
treeherdermozilla-central@87fd173f56f1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersochameau
bugs919496
milestone27.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 919496 - [app manager] Once an app has been installed, it doesn't show up in the 'installed app' tab. r=ochameau
browser/devtools/app-manager/webapps-store.js
toolkit/devtools/apps/tests/unit/head_apps.js
toolkit/devtools/apps/tests/unit/test_webappsActor.js
toolkit/devtools/server/actors/webapps.js
--- a/browser/devtools/app-manager/webapps-store.js
+++ b/browser/devtools/app-manager/webapps-store.js
@@ -3,19 +3,16 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 const ObservableObject = require("devtools/shared/observable-object");
 const promise = require("sdk/core/promise");
 const {Connection} = require("devtools/client/connection-manager");
 
 const {Cu} = require("chrome");
 const dbgClient = Cu.import("resource://gre/modules/devtools/dbg-client.jsm");
-dbgClient.UnsolicitedNotifications.appOpen = "appOpen";
-dbgClient.UnsolicitedNotifications.appClose = "appClose"
-
 const _knownWebappsStores = new WeakMap();
 
 let WebappsStore;
 
 module.exports = WebappsStore = function(connection) {
   // If we already know about this connection,
   // let's re-use the existing store.
   if (_knownWebappsStores.has(connection)) {
@@ -98,16 +95,24 @@ WebappsStore.prototype = {
       client.addListener("appOpen", (type, { manifestURL }) => {
         this._onAppOpen(manifestURL);
       });
 
       client.addListener("appClose", (type, { manifestURL }) => {
         this._onAppClose(manifestURL);
       });
 
+      client.addListener("appInstall", (type, { manifestURL }) => {
+        this._onAppInstall(manifestURL);
+      });
+
+      client.addListener("appUninstall", (type, { manifestURL }) => {
+        this._onAppUninstall(manifestURL);
+      });
+
       return deferred.resolve();
     })
     return deferred.promise;
   },
 
   _getAllApps: function() {
     let deferred = promise.defer();
     let request = {
@@ -172,16 +177,20 @@ WebappsStore.prototype = {
     let idx = 0;
     (function getIcon() {
       if (idx == allApps.length) {
         return deferred.resolve();
       }
       let a = allApps[idx++];
       request.manifestURL = a.manifestURL;
       return client.request(request, (res) => {
+        if (res.error) {
+          Cu.reportError(res.message || res.error);
+        }
+
         if (res.url) {
           a.iconURL = res.url;
         }
         getIcon();
       });
     })();
 
     return deferred.promise;
@@ -199,9 +208,62 @@ WebappsStore.prototype = {
   _onAppClose: function(manifest) {
     let a = this._getAppFromManifest(manifest);
     a.running = false;
     let running = this.object.running;
     this.object.running = running.filter((m) => {
       return m != manifest;
     });
   },
+
+  _onAppInstall: function(manifest) {
+    let client = this._connection.client;
+    let request = {
+      to: this._webAppsActor,
+      type: "getApp",
+      manifestURL: manifest
+    };
+
+    client.request(request, (res) => {
+      if (res.error) {
+        if (res.error == "forbidden") {
+          // We got a notification for an app we don't have access to.
+          // Ignore.
+          return;
+        }
+        Cu.reportError(res.message || res.error);
+        return;
+      }
+
+      let app = res.app;
+      app.running = false;
+
+      let notFound = true;
+      let proxifiedApp;
+      for (let i = 0; i < this.object.all.length; i++) {
+        let storedApp = this.object.all[i];
+        if (storedApp.manifestURL == app.manifestURL) {
+          this.object.all[i] = app;
+          proxifiedApp = this.object.all[i];
+          notFound = false;
+          break;
+        }
+      }
+      if (notFound) {
+        this.object.all.push(app);
+        proxifiedApp = this.object.all[this.object.all.length - 1];
+      }
+
+      request.type = "getIconAsDataURL";
+      client.request(request, (res) => {
+        if (res.url) {
+          proxifiedApp.iconURL = res.url;
+        }
+      });
+    });
+  },
+
+  _onAppUninstall: function(manifest) {
+    this.object.all = this.object.all.filter((app) => {
+      return (app.manifestURL != manifest);
+    });
+  },
 }
--- a/toolkit/devtools/apps/tests/unit/head_apps.js
+++ b/toolkit/devtools/apps/tests/unit/head_apps.js
@@ -93,30 +93,28 @@ function do_get_webappsdir() {
   webappsDir.append("test_webapps");
   if (!webappsDir.exists())
     webappsDir.create(Ci.nsIFile.DIRECTORY_TYPE, parseInt("755", 8));
 
   var coreAppsDir = Services.dirsvc.get("ProfD", Ci.nsILocalFile);
   coreAppsDir.append("test_coreapps");
   if (!coreAppsDir.exists())
     coreAppsDir.create(Ci.nsIFile.DIRECTORY_TYPE, parseInt("755", 8));
-  var tmpDir = Services.dirsvc.get("TmpD", Ci.nsILocalFile);
 
   // Register our own provider for the profile directory.
   // It will return our special docshell profile directory.
   var provider = {
     getFile: function(prop, persistent) {
       persistent.value = true;
       if (prop == "webappsDir") {
         return webappsDir.clone();
       }
       else if (prop == "coreAppsDir") {
         return coreAppsDir.clone();
       }
-      return tmpDir.clone();
       throw Cr.NS_ERROR_FAILURE;
     },
     QueryInterface: function(iid) {
       if (iid.equals(Ci.nsIDirectoryServiceProvider) ||
           iid.equals(Ci.nsISupports)) {
         return this;
       }
       throw Cr.NS_ERROR_NO_INTERFACE;
--- a/toolkit/devtools/apps/tests/unit/test_webappsActor.js
+++ b/toolkit/devtools/apps/tests/unit/test_webappsActor.js
@@ -52,16 +52,33 @@ add_test(function testGetAll() {
         run_next_test();
         return;
       }
     }
     do_throw("Unable to find the test app by its id");
   });
 });
 
+add_test(function testGetApp() {
+  let manifestURL = APP_ORIGIN + "/manifest.webapp";
+  let request = {type: "getApp", manifestURL: manifestURL};
+  webappActorRequest(request, function (aResponse) {
+    do_check_true("app" in aResponse);
+    let app = aResponse.app;
+    do_check_eq(app.id, gAppId);
+    do_check_eq(app.name, "Test app");
+    do_check_eq(app.manifest.description, "Testing webapps actor");
+    do_check_eq(app.manifest.launch_path, "/index.html");
+    do_check_eq(app.origin, APP_ORIGIN);
+    do_check_eq(app.installOrigin, app.origin);
+    do_check_eq(app.manifestURL, app.origin + "/manifest.webapp");
+    run_next_test();
+  });
+});
+
 add_test(function testLaunchApp() {
   let manifestURL = APP_ORIGIN + "/manifest.webapp";
   let startPoint = "/index.html";
   let request = {
     type: "launch",
     manifestURL: manifestURL,
     startPoint: startPoint
   };
--- a/toolkit/devtools/server/actors/webapps.js
+++ b/toolkit/devtools/server/actors/webapps.js
@@ -539,16 +539,42 @@ WebappsActor.prototype = {
     let reg = DOMApplicationRegistry;
     reg.getAll(apps => {
       deferred.resolve({ apps: this._filterAllowedApps(apps) });
     });
 
     return deferred.promise;
   },
 
+  getApp: function wa_actorGetApp(aRequest) {
+    debug("getApp");
+
+    let manifestURL = aRequest.manifestURL;
+    if (!manifestURL) {
+      return { error: "missingParameter",
+               message: "missing parameter manifestURL" };
+    }
+
+    let reg = DOMApplicationRegistry;
+    let app = reg.getAppByManifestURL(manifestURL);
+    if (!app) {
+      return { error: "appNotFound" };
+    }
+
+    if (this._isAppAllowedForManifest(app.manifestURL)) {
+      let deferred = promise.defer();
+      reg.getManifestFor(manifestURL, function (manifest) {
+        app.manifest = manifest;
+        deferred.resolve({app: app});
+      });
+      return deferred.promise;
+    }
+    return { error: "forbidden" };
+  },
+
   _areCertifiedAppsAllowed: function wa__areCertifiedAppsAllowed() {
     let pref = "devtools.debugger.forbid-certified-apps";
     return !Services.prefs.getBoolPref(pref);
   },
 
   _isAppAllowedForManifest: function wa__isAppAllowedForManifest(aManifest) {
     if (this._areCertifiedAppsAllowed()) {
       return true;
@@ -950,16 +976,17 @@ WebappsActor.prototype.requestTypes = {
 };
 
 // Until we implement unix domain socket, we only enable app install
 // only on production devices
 if (Services.prefs.getBoolPref("devtools.debugger.enable-content-actors")) {
   let requestTypes = WebappsActor.prototype.requestTypes;
   requestTypes.uploadPackage = WebappsActor.prototype.uploadPackage;
   requestTypes.getAll = WebappsActor.prototype.getAll;
+  requestTypes.getApp = WebappsActor.prototype.getApp;
   requestTypes.launch = WebappsActor.prototype.launch;
   requestTypes.close  = WebappsActor.prototype.close;
   requestTypes.uninstall = WebappsActor.prototype.uninstall;
   requestTypes.listRunningApps = WebappsActor.prototype.listRunningApps;
   requestTypes.getAppActor = WebappsActor.prototype.getAppActor;
   requestTypes.watchApps = WebappsActor.prototype.watchApps;
   requestTypes.unwatchApps = WebappsActor.prototype.unwatchApps;
   requestTypes.getIconAsDataURL = WebappsActor.prototype.getIconAsDataURL;