Bug 919496 - [app manager] Once an app has been installed, it doesn't show up in the 'installed app' tab. r=apoirot
☠☠ backed out by a9ed5d97225f ☠ ☠
authorPaul Rouget <paul@mozilla.com>
Thu, 26 Sep 2013 09:53:22 -0400
changeset 148746 a2601d3f3214489582750fb8c88db5ada6d3ceea
parent 148745 890fc46bcf53a1be8b485c73e735ce9ba76e5f0a
child 148747 3786755b89c0ba5c678d3fe37374e86bd920837a
push id2840
push userryanvm@gmail.com
push dateThu, 26 Sep 2013 13:53:28 +0000
treeherderfx-team@3786755b89c0 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersapoirot
bugs919496
milestone27.0a1
Bug 919496 - [app manager] Once an app has been installed, it doesn't show up in the 'installed app' tab. r=apoirot
browser/devtools/app-manager/webapps-store.js
toolkit/devtools/apps/tests/unit/test_webappsActor.js
toolkit/devtools/apps/tests/unit/xpcshell.ini
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/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
   };
@@ -98,16 +115,17 @@ add_test(function testCloseApp() {
 });
 
 // The 128px icon is a single red pixel and the 64px one is a blue one
 // bug 899177: there is a bug with xhr and app:// and jar:// uris
 // that ends up forcing the content type to application/xml
 let red1px =  "data:application/xml;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAIAAACQd1PeAAAADElEQVQI12P4z8AAAAMBAQAY3Y2wAAAAAElFTkSuQmCC";
 let blue1px = "data:application/xml;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAIAAACQd1PeAAAADElEQVQI12MwZDgHAAFlAQBDpjhLAAAAAElFTkSuQmCC";
 
+/* testGetIcon and testGetIconWithCustomSize disabled: bug 920981
 add_test(function testGetIcon() {
   let manifestURL = APP_ORIGIN + "/manifest.webapp";
   let request = {
     type: "getIconAsDataURL",
     manifestURL: manifestURL
   };
 
   webappActorRequest(request, function (aResponse) {
@@ -129,16 +147,17 @@ add_test(function testGetIconWithCustomS
 
   webappActorRequest(request, function (aResponse) {
     do_check_false("error" in aResponse);
 
     do_check_eq(aResponse.url, blue1px);
     run_next_test();
   });
 });
+*/
 
 add_test(function testUninstall() {
   let manifestURL = APP_ORIGIN + "/manifest.webapp";
   let request = {
     type: "uninstall",
     manifestURL: manifestURL
   };
 
--- a/toolkit/devtools/apps/tests/unit/xpcshell.ini
+++ b/toolkit/devtools/apps/tests/unit/xpcshell.ini
@@ -1,7 +1,6 @@
 [DEFAULT]
 head = head_apps.js
 tail = tail_apps.js
 support-files = data/app.zip
 
 [test_webappsActor.js]
-skip-if = (os == "win" || "linux" || "mac")
--- a/toolkit/devtools/server/actors/webapps.js
+++ b/toolkit/devtools/server/actors/webapps.js
@@ -536,16 +536,42 @@ WebappsActor.prototype = {
     let reg = DOMApplicationRegistry;
     reg.getAll(apps => {
       deferred.resolve({ apps: this._filterAllowedApps(apps) });
     });
 
     return deferred.promise;
   },
 
+  getApp: function wa_actorGetApp(aRequest) {
+    debug("getAll");
+
+    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;
@@ -923,16 +949,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;