Bug 773214 - Make AddonInstall/AddonInstallWrapper aware of different icon sizes; r=Unfocused
authorGeoff Lankow <geoff@darktrojan.net>
Thu, 23 Aug 2012 18:49:29 +1200
changeset 105181 d98216c47a77bf3e15b892c2d0b81f03908a5881
parent 105180 c80863b9bf12e417f1c43116d088545001a2150b
child 105182 be2dc5ca1acba2ba20036fc6bcf1c657f4268401
push id55
push usershu@rfrn.org
push dateThu, 30 Aug 2012 01:33:09 +0000
reviewersUnfocused
bugs773214
milestone17.0a1
Bug 773214 - Make AddonInstall/AddonInstallWrapper aware of different icon sizes; r=Unfocused
toolkit/mozapps/extensions/AddonManager.jsm
toolkit/mozapps/extensions/AddonRepository.jsm
toolkit/mozapps/extensions/XPIProvider.jsm
toolkit/mozapps/extensions/test/xpcshell/test_install_icons.js
toolkit/mozapps/extensions/test/xpcshell/xpcshell.ini
--- a/toolkit/mozapps/extensions/AddonManager.jsm
+++ b/toolkit/mozapps/extensions/AddonManager.jsm
@@ -1271,26 +1271,26 @@ var AddonManagerInternal = {
    * @param  aCallback
    *         A callback to pass the AddonInstall to
    * @param  aMimetype
    *         The mimetype of the add-on
    * @param  aHash
    *         An optional hash of the add-on
    * @param  aName
    *         An optional placeholder name while the add-on is being downloaded
-   * @param  aIconURL
-   *         An optional placeholder icon URL while the add-on is being downloaded
+   * @param  aIcons
+   *         Optional placeholder icons while the add-on is being downloaded
    * @param  aVersion
    *         An optional placeholder version while the add-on is being downloaded
    * @param  aLoadGroup
    *         An optional nsILoadGroup to associate any network requests with
    * @throws if the aUrl, aCallback or aMimetype arguments are not specified
    */
   getInstallForURL: function AMI_getInstallForURL(aUrl, aCallback, aMimetype,
-                                                  aHash, aName, aIconURL,
+                                                  aHash, aName, aIcons,
                                                   aVersion, aLoadGroup) {
     if (!gStarted)
       throw Components.Exception("AddonManager is not initialized",
                                  Cr.NS_ERROR_NOT_INITIALIZED);
 
     if (!aUrl || typeof aUrl != "string")
       throw Components.Exception("aURL must be a non-empty string",
                                  Cr.NS_ERROR_INVALID_ARG);
@@ -1306,33 +1306,39 @@ var AddonManagerInternal = {
     if (aHash && typeof aHash != "string")
       throw Components.Exception("aHash must be a string or null",
                                  Cr.NS_ERROR_INVALID_ARG);
 
     if (aName && typeof aName != "string")
       throw Components.Exception("aName must be a string or null",
                                  Cr.NS_ERROR_INVALID_ARG);
 
-    if (aIconURL && typeof aIconURL != "string")
-      throw Components.Exception("aIconURL must be a string or null",
-                                 Cr.NS_ERROR_INVALID_ARG);
+    if (aIcons) {
+      if (typeof aIcons == "string")
+        aIcons = { "32": aIcons };
+      else if (typeof aIcons != "object")
+        throw Components.Exception("aIcons must be a string, an object or null",
+                                   Cr.NS_ERROR_INVALID_ARG);
+    } else {
+      aIcons = {};
+    }
 
     if (aVersion && typeof aVersion != "string")
       throw Components.Exception("aVersion must be a string or null",
                                  Cr.NS_ERROR_INVALID_ARG);
 
     if (aLoadGroup && (!(aLoadGroup instanceof Ci.nsILoadGroup)))
       throw Components.Exception("aLoadGroup must be a nsILoadGroup or null",
                                  Cr.NS_ERROR_INVALID_ARG);
 
     let providers = this.providers.slice(0);
     for (let provider of providers) {
       if (callProvider(provider, "supportsMimetype", false, aMimetype)) {
         callProvider(provider, "getInstallForURL", null,
-                     aUrl, aHash, aName, aIconURL, aVersion, aLoadGroup,
+                     aUrl, aHash, aName, aIcons, aVersion, aLoadGroup,
                      function(aInstall) {
           safeCall(aCallback, aInstall);
         });
         return;
       }
     }
     safeCall(aCallback, null);
   },
@@ -2216,20 +2222,20 @@ var AddonManager = {
 
 #ifdef MOZ_EM_DEBUG
   get __AddonManagerInternal__() {
     return AddonManagerInternal;
   },
 #endif
 
   getInstallForURL: function AM_getInstallForURL(aUrl, aCallback, aMimetype,
-                                                 aHash, aName, aIconURL,
+                                                 aHash, aName, aIcons,
                                                  aVersion, aLoadGroup) {
     AddonManagerInternal.getInstallForURL(aUrl, aCallback, aMimetype, aHash,
-                                          aName, aIconURL, aVersion, aLoadGroup);
+                                          aName, aIcons, aVersion, aLoadGroup);
   },
 
   getInstallForFile: function AM_getInstallForFile(aFile, aCallback, aMimetype) {
     AddonManagerInternal.getInstallForFile(aFile, aCallback, aMimetype);
   },
 
   /**
    * Gets an array of add-on IDs that changed during the most recent startup.
--- a/toolkit/mozapps/extensions/AddonRepository.jsm
+++ b/toolkit/mozapps/extensions/AddonRepository.jsm
@@ -1245,17 +1245,17 @@ var AddonRepository = {
         pendingResults--;
         if (pendingResults == 0)
           self._reportSuccess(results, aTotalResults);
       }
 
       if (aResult.xpiURL) {
         AddonManager.getInstallForURL(aResult.xpiURL, callback,
                                       "application/x-xpinstall", aResult.xpiHash,
-                                      addon.name, addon.iconURL, addon.version);
+                                      addon.name, addon.icons, addon.version);
       }
       else {
         callback(null);
       }
     });
   },
 
   // Parses addon_compatibility nodes, that describe compatibility overrides.
--- a/toolkit/mozapps/extensions/XPIProvider.jsm
+++ b/toolkit/mozapps/extensions/XPIProvider.jsm
@@ -3138,30 +3138,30 @@ var XPIProvider = {
    * Called to get an AddonInstall to download and install an add-on from a URL.
    *
    * @param  aUrl
    *         The URL to be installed
    * @param  aHash
    *         A hash for the install
    * @param  aName
    *         A name for the install
-   * @param  aIconURL
-   *         An icon URL for the install
+   * @param  aIcons
+   *         Icon URLs for the install
    * @param  aVersion
    *         A version for the install
    * @param  aLoadGroup
    *         An nsILoadGroup to associate requests with
    * @param  aCallback
    *         A callback to pass the AddonInstall to
    */
-  getInstallForURL: function XPI_getInstallForURL(aUrl, aHash, aName, aIconURL,
+  getInstallForURL: function XPI_getInstallForURL(aUrl, aHash, aName, aIcons,
                                                   aVersion, aLoadGroup, aCallback) {
     AddonInstall.createDownload(function getInstallForURL_createDownload(aInstall) {
       aCallback(aInstall.wrapper);
-    }, aUrl, aHash, aName, aIconURL, aVersion, aLoadGroup);
+    }, aUrl, aHash, aName, aIcons, aVersion, aLoadGroup);
   },
 
   /**
    * Called to get an AddonInstall to install an add-on from a local file.
    *
    * @param  aFile
    *         The file to be installed
    * @param  aCallback
@@ -4045,16 +4045,17 @@ function AddonInstall(aInstallLocation, 
     this.originalHash = {
       algorithm: hashSplit[0],
       data: hashSplit[1]
     };
   }
   this.hash = this.originalHash;
   this.loadGroup = aLoadGroup;
   this.listeners = [];
+  this.icons = {};
   this.existingAddon = aExistingAddon;
   this.error = 0;
   if (aLoadGroup)
     this.window = aLoadGroup.notificationCallbacks
                             .getInterface(Ci.nsIDOMWindow);
   else
     this.window = null;
 }
@@ -4069,17 +4070,17 @@ AddonInstall.prototype = {
   loadGroup: null,
   badCertHandler: null,
   listeners: null,
   restartDownload: false,
 
   name: null,
   type: null,
   version: null,
-  iconURL: null,
+  icons: null,
   releaseNotesURI: null,
   sourceURI: null,
   file: null,
   ownsTempFile: false,
   certificate: null,
   certName: null,
 
   linkedInstalls: null,
@@ -4096,17 +4097,17 @@ AddonInstall.prototype = {
    *
    * @param  aManifest
    *         The cached manifest for the staged install
    */
   initStagedInstall: function AI_initStagedInstall(aManifest) {
     this.name = aManifest.name;
     this.type = aManifest.type;
     this.version = aManifest.version;
-    this.iconURL = aManifest.iconURL;
+    this.icons = aManifest.icons;
     this.releaseNotesURI = aManifest.releaseNotesURI ?
                            NetUtil.newURI(aManifest.releaseNotesURI) :
                            null
     this.sourceURI = aManifest.sourceURI ?
                      NetUtil.newURI(aManifest.sourceURI) :
                      null;
     this.file = null;
     this.addon = aManifest;
@@ -4215,27 +4216,27 @@ AddonInstall.prototype = {
    * Initialises this install to be a download from a remote url.
    *
    * @param  aCallback
    *         The callback to pass the initialised AddonInstall to
    * @param  aName
    *         An optional name for the add-on
    * @param  aType
    *         An optional type for the add-on
-   * @param  aIconURL
-   *         An optional icon for the add-on
+   * @param  aIcons
+   *         Optional icons for the add-on
    * @param  aVersion
    *         An optional version for the add-on
    */
-  initAvailableDownload: function AI_initAvailableDownload(aName, aType, aIconURL, aVersion, aCallback) {
+  initAvailableDownload: function AI_initAvailableDownload(aName, aType, aIcons, aVersion, aCallback) {
     this.state = AddonManager.STATE_AVAILABLE;
     this.name = aName;
     this.type = aType;
     this.version = aVersion;
-    this.iconURL = aIconURL;
+    this.icons = aIcons;
     this.progress = 0;
     this.maxProgress = -1;
 
     XPIProvider.installs.push(this);
     AddonManagerPrivate.callInstallListeners("onNewInstall", this.listeners,
                                              this.wrapper);
 
     aCallback(this);
@@ -5152,33 +5153,33 @@ AddonInstall.createInstall = function AI
  * @param  aCallback
  *         The callback to pass the new AddonInstall to
  * @param  aUri
  *         The URI to download
  * @param  aHash
  *         A hash for the add-on
  * @param  aName
  *         A name for the add-on
- * @param  aIconURL
- *         An icon URL for the add-on
+ * @param  aIcons
+ *         An icon URLs for the add-on
  * @param  aVersion
  *         A version for the add-on
  * @param  aLoadGroup
  *         An nsILoadGroup to associate the download with
  */
-AddonInstall.createDownload = function AI_createDownload(aCallback, aUri, aHash, aName, aIconURL,
+AddonInstall.createDownload = function AI_createDownload(aCallback, aUri, aHash, aName, aIcons,
                                        aVersion, aLoadGroup) {
   let location = XPIProvider.installLocationsByName[KEY_APP_PROFILE];
   let url = NetUtil.newURI(aUri);
 
   let install = new AddonInstall(location, url, aHash, null, null, aLoadGroup);
   if (url instanceof Ci.nsIFileURL)
     install.initLocalInstall(aCallback);
   else
-    install.initAvailableDownload(aName, null, aIconURL, aVersion, aCallback);
+    install.initAvailableDownload(aName, null, aIcons, aVersion, aCallback);
 };
 
 /**
  * Creates a new AddonInstall for an update.
  *
  * @param  aCallback
  *         The callback to pass the new AddonInstall to
  * @param  aAddon
@@ -5199,38 +5200,40 @@ AddonInstall.createUpdate = function AI_
 
   let install = new AddonInstall(aAddon._installLocation, url,
                                  aUpdate.updateHash, releaseNotesURI, aAddon);
   if (url instanceof Ci.nsIFileURL) {
     install.initLocalInstall(aCallback);
   }
   else {
     install.initAvailableDownload(aAddon.selectedLocale.name, aAddon.type,
-                                  aAddon.iconURL, aUpdate.version, aCallback);
+                                  aAddon.icons, aUpdate.version, aCallback);
   }
 };
 
 /**
  * Creates a wrapper for an AddonInstall that only exposes the public API
  *
  * @param  install
  *         The AddonInstall to create a wrapper for
  */
 function AddonInstallWrapper(aInstall) {
 #ifdef MOZ_EM_DEBUG
   this.__defineGetter__("__AddonInstallInternal__", function AIW_debugGetter() {
     return aInstall;
   });
 #endif
 
-  ["name", "type", "version", "iconURL", "releaseNotesURI", "file", "state", "error",
+  ["name", "type", "version", "icons", "releaseNotesURI", "file", "state", "error",
    "progress", "maxProgress", "certificate", "certName"].forEach(function(aProp) {
     this.__defineGetter__(aProp, function AIW_propertyGetter() aInstall[aProp]);
   }, this);
 
+  this.__defineGetter__("iconURL", function AIW_iconURL() aInstall.icons[32]);
+
   this.__defineGetter__("existingAddon", function AIW_existingAddonGetter() {
     return createWrapper(aInstall.existingAddon);
   });
   this.__defineGetter__("addon", function AIW_addonGetter() createWrapper(aInstall.addon));
   this.__defineGetter__("sourceURI", function AIW_sourceURIGetter() aInstall.sourceURI);
 
   this.__defineGetter__("linkedInstalls", function AIW_linkedInstallsGetter() {
     if (!aInstall.linkedInstalls)
new file mode 100644
--- /dev/null
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_install_icons.js
@@ -0,0 +1,55 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+var addon_url = "http://localhost:4444/test.xpi";
+var icon32_url = "http://localhost:4444/icon.png";
+var icon64_url = "http://localhost:4444/icon64.png";
+
+function run_test() {
+  do_test_pending();
+  createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "1.9.2");
+  startupManager();
+
+  test_1();
+}
+
+function test_1() {
+  AddonManager.getInstallForURL(addon_url, function(aInstall) {
+    do_check_eq(aInstall.iconURL, null);
+    do_check_neq(aInstall.icons, null);
+    do_check_eq(aInstall.icons[32], undefined);
+    do_check_eq(aInstall.icons[64], undefined);
+    test_2();
+  }, "application/x-xpinstall", null, null, null, null, null);
+}
+
+function test_2() {
+  AddonManager.getInstallForURL(addon_url, function(aInstall) {
+    do_check_eq(aInstall.iconURL, icon32_url);
+    do_check_neq(aInstall.icons, null);
+    do_check_eq(aInstall.icons[32], icon32_url);
+    do_check_eq(aInstall.icons[64], undefined);
+    test_3();
+  }, "application/x-xpinstall", null, null, icon32_url, null, null);
+}
+
+function test_3() {
+  AddonManager.getInstallForURL(addon_url, function(aInstall) {
+    do_check_eq(aInstall.iconURL, icon32_url);
+    do_check_neq(aInstall.icons, null);
+    do_check_eq(aInstall.icons[32], icon32_url);
+    do_check_eq(aInstall.icons[64], undefined);
+    test_4();
+  }, "application/x-xpinstall", null, null, { "32": icon32_url }, null, null);
+}
+
+function test_4() {
+  AddonManager.getInstallForURL(addon_url, function(aInstall) {
+    do_check_eq(aInstall.iconURL, icon32_url);
+    do_check_neq(aInstall.icons, null);
+    do_check_eq(aInstall.icons[32], icon32_url);
+    do_check_eq(aInstall.icons[64], icon64_url);
+    do_test_finished();
+  }, "application/x-xpinstall", null, null, { "32": icon32_url, "64": icon64_url }, null, null);
+}
--- a/toolkit/mozapps/extensions/test/xpcshell/xpcshell.ini
+++ b/toolkit/mozapps/extensions/test/xpcshell/xpcshell.ini
@@ -164,16 +164,17 @@ skip-if = os == "android"
 [test_gfxBlacklist_No_Comparison.js]
 [test_gfxBlacklist_OK.js]
 [test_gfxBlacklist_OS.js]
 [test_gfxBlacklist_Vendor.js]
 [test_gfxBlacklist_prefs.js]
 [test_hasbinarycomponents.js]
 [test_hotfix.js]
 [test_install.js]
+[test_install_icons.js]
 # Bug 676992: test consistently hangs on Android
 skip-if = os == "android"
 [test_install_strictcompat.js]
 # Bug 676992: test consistently hangs on Android
 skip-if = os == "android"
 [test_locale.js]
 [test_locked.js]
 [test_locked_strictcompat.js]