Backing out patches for bug 552965 and bug 553455 due to test failures.
authorDave Townsend <dtownsend@oxymoronical.com>
Wed, 30 Jun 2010 16:51:05 -0700
changeset 46465 644557496f7973d451f768a62f79a21e4c8e6547
parent 46464 fb46b41289353b96b69d28077912abfff04d8987
child 46466 32438076b9b8ed3c4becda9d7a7fa3d8c0453fdf
push idunknown
push userunknown
push dateunknown
bugs552965, 553455
milestone2.0b2pre
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
Backing out patches for bug 552965 and bug 553455 due to test failures.
browser/base/content/browser.css
browser/base/content/browser.js
browser/base/content/browser.xul
browser/base/content/test/Makefile.in
browser/base/content/test/browser_bug553455.js
browser/locales/en-US/chrome/browser/browser.properties
browser/themes/gnomestripe/browser/browser.css
browser/themes/pinstripe/browser/browser.css
browser/themes/winstripe/browser/browser.css
toolkit/locales/en-US/chrome/mozapps/extensions/extensions.properties
toolkit/mozapps/extensions/XPIProvider.jsm
toolkit/mozapps/extensions/amWebInstallListener.js
toolkit/mozapps/extensions/test/xpinstall/Makefile.in
toolkit/mozapps/extensions/test/xpinstall/head.js
--- a/browser/base/content/browser.css
+++ b/browser/base/content/browser.css
@@ -318,12 +318,11 @@ window[chromehidden~="toolbar"] toolbar:
 }
 
 /* notification anchors should only be visible when their associated
    notifications are */
 .notification-anchor-icon {
   display: none;
 }
 
-#notification-popup-box[anchorid="geo-notification-icon"] > #geo-notification-icon,
-#notification-popup-box[anchorid="addons-notification-icon"] > #addons-notification-icon {
+#notification-popup-box[anchorid="geo-notification-icon"] > #geo-notification-icon {
   display: -moz-box;
 }
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -125,25 +125,16 @@ XPCOMUtils.defineLazyGetter(window, "gFi
   return findbar;
 });
 
 __defineGetter__("gPrefService", function() {
   delete this.gPrefService;
   return this.gPrefService = Services.prefs;
 });
 
-__defineGetter__("AddonManager", function() {
-  Cu.import("resource://gre/modules/AddonManager.jsm");
-  return this.AddonManager;
-});
-__defineSetter__("AddonManager", function (val) {
-  delete this.AddonManager;
-  return this.AddonManager = val;
-});
-
 __defineGetter__("PluralForm", function() {
   Cu.import("resource://gre/modules/PluralForm.jsm");
   return this.PluralForm;
 });
 __defineSetter__("PluralForm", function (val) {
   delete this.PluralForm;
   return this.PluralForm = val;
 });
@@ -627,152 +618,79 @@ const gXPInstallObserver = {
         return browser;
     }
     return null;
   },
 
   observe: function (aSubject, aTopic, aData)
   {
     var brandBundle = document.getElementById("bundle_brand");
-    var installInfo = aSubject.QueryInterface(Components.interfaces.amIWebInstallInfo);
-    var win = installInfo.originatingWindow;
-    var shell = win.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
-                   .getInterface(Components.interfaces.nsIWebNavigation)
-                   .QueryInterface(Components.interfaces.nsIDocShell);
-    var browser = this._getBrowser(shell);
-    if (!browser)
-      return;
-    const anchorID = "addons-notification-icon";
-    var messageString, action;
-    var brandShortName = brandBundle.getString("brandShortName");
-    var host = installInfo.originatingURI ? installInfo.originatingURI.host : browser.currentURI.host;
-
-    var notificationID = aTopic;
-
     switch (aTopic) {
     case "addon-install-blocked":
-      var enabled = true;
-      try {
-        enabled = gPrefService.getBoolPref("xpinstall.enabled");
-      }
-      catch (e) {
-      }
-
-      if (!enabled) {
-        notificationID = "xpinstall-disabled"
-        if (PopupNotifications.getNotification(notificationID, browser))
-          return;
-
-        if (gPrefService.prefIsLocked("xpinstall.enabled")) {
-          messageString = gNavigatorBundle.getString("xpinstallDisabledMessageLocked");
-          buttons = [];
+      var installInfo = aSubject.QueryInterface(Components.interfaces.amIWebInstallInfo);
+      var win = installInfo.originatingWindow;
+      var shell = win.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
+                     .getInterface(Components.interfaces.nsIWebNavigation)
+                     .QueryInterface(Components.interfaces.nsIDocShell);
+      var browser = this._getBrowser(shell);
+      if (browser) {
+        var host = installInfo.originatingURI.host;
+        var brandShortName = brandBundle.getString("brandShortName");
+        var notificationName, messageString, buttons;
+        var enabled = true;
+        try {
+          enabled = gPrefService.getBoolPref("xpinstall.enabled");
+        }
+        catch (e) {
+        }
+        if (!enabled) {
+          notificationName = "xpinstall-disabled"
+          if (gPrefService.prefIsLocked("xpinstall.enabled")) {
+            messageString = gNavigatorBundle.getString("xpinstallDisabledMessageLocked");
+            buttons = [];
+          }
+          else {
+            messageString = gNavigatorBundle.getFormattedString("xpinstallDisabledMessage",
+                                                                [brandShortName, host]);
+
+            buttons = [{
+              label: gNavigatorBundle.getString("xpinstallDisabledButton"),
+              accessKey: gNavigatorBundle.getString("xpinstallDisabledButton.accesskey"),
+              popup: null,
+              callback: function editPrefs() {
+                gPrefService.setBoolPref("xpinstall.enabled", true);
+                return false;
+              }
+            }];
+          }
         }
         else {
-          messageString = gNavigatorBundle.getFormattedString("xpinstallDisabledMessage",
+          notificationName = "xpinstall"
+          messageString = gNavigatorBundle.getFormattedString("xpinstallPromptWarning",
                                                               [brandShortName, host]);
 
-          action = {
-            label: gNavigatorBundle.getString("xpinstallDisabledButton"),
-            accessKey: gNavigatorBundle.getString("xpinstallDisabledButton.accesskey"),
-            callback: function editPrefs() {
-              gPrefService.setBoolPref("xpinstall.enabled", true);
+          buttons = [{
+            label: gNavigatorBundle.getString("xpinstallPromptAllowButton"),
+            accessKey: gNavigatorBundle.getString("xpinstallPromptAllowButton.accesskey"),
+            popup: null,
+            callback: function() {
+              installInfo.install();
+              return false;
             }
-          };
+          }];
+        }
+
+        var notificationBox = gBrowser.getNotificationBox(browser);
+        if (!notificationBox.getNotificationWithValue(notificationName)) {
+          const priority = notificationBox.PRIORITY_WARNING_MEDIUM;
+          const iconURL = "chrome://mozapps/skin/update/update.png";
+          notificationBox.appendNotification(messageString, notificationName,
+                                             iconURL, priority, buttons);
         }
       }
-      else {
-        if (PopupNotifications.getNotification(notificationID, browser))
-          return;
-
-        messageString = gNavigatorBundle.getFormattedString("xpinstallPromptWarning",
-                                                            [brandShortName, host]);
-
-        action = {
-          label: gNavigatorBundle.getString("xpinstallPromptAllowButton"),
-          accessKey: gNavigatorBundle.getString("xpinstallPromptAllowButton.accesskey"),
-          callback: function() {
-            installInfo.install();
-          }
-        };
-      }
-
-      PopupNotifications.show(browser, notificationID, messageString, anchorID,
-                              action);
-      break;
-    case "addon-install-failed":
-      // TODO This isn't terribly ideal for the multiple failure case
-      installInfo.installs.forEach(function(aInstall) {
-        var error = "addonError";
-        if (aInstall.error != 0)
-          error += aInstall.error;
-        else if (aInstall.addon.blocklistState == Ci.nsIBlocklistService.STATE_BLOCKED)
-          error += "Blocklisted";
-        else
-          error += "Incompatible";
-
-        messageString = gNavigatorBundle.getString(error);
-        messageString = messageString.replace("#1", aInstall.name);
-        messageString = messageString.replace("#2", host);
-        messageString = messageString.replace("#3", brandShortName);
-        messageString = messageString.replace("#4", Services.appinfo.version);
-
-        PopupNotifications.show(browser, notificationID, messageString, anchorID,
-                                action);
-      });
-      break;
-    case "addon-install-complete":
-      var notification = PopupNotifications.getNotification(notificationID, browser);
-      if (notification)
-        PopupNotifications.remove(notification);
-
-      var needsRestart = installInfo.installs.some(function(i) {
-        return (i.addon.pendingOperations & AddonManager.PENDING_INSTALL) != 0;
-      });
-
-      if (needsRestart) {
-        messageString = gNavigatorBundle.getString("addonsInstalledNeedsRestart");
-        action = {
-          label: gNavigatorBundle.getString("addonInstallRestartButton"),
-          accessKey: gNavigatorBundle.getString("addonInstallRestartButton.accesskey"),
-          callback: function() {
-            Application.restart();
-          }
-        };
-      }
-      else {
-        messageString = gNavigatorBundle.getString("addonsInstalled");
-        action = {
-          label: gNavigatorBundle.getString("addonInstallManage"),
-          accessKey: gNavigatorBundle.getString("addonInstallManage.accesskey"),
-          callback: function() {
-            // Calculate the add-on type that is most popular in the list of
-            // installs
-            var types = {};
-            var bestType = null;
-            installInfo.installs.forEach(function(aInstall) {
-              if (aInstall.type in types)
-                types[aInstall.type]++;
-              else
-                types[aInstall.type] = 1;
-              if (!bestType || types[aInstall.type] > types[bestType])
-                bestType = aInstall.type;
-            });
-
-            BrowserOpenAddonsMgr("addons://list/" + bestType);
-          }
-        };
-      }
-
-      messageString = PluralForm.get(installInfo.installs.length, messageString);
-      messageString = messageString.replace("#1", installInfo.installs[0].name);
-      messageString = messageString.replace("#2", installInfo.installs.length);
-      messageString = messageString.replace("#3", brandShortName);
-
-      PopupNotifications.show(browser, notificationID, messageString, anchorID,
-                              action);
       break;
     }
   }
 };
 
 // Simple gestures support
 //
 // As per bug #412486, web content must not be allowed to receive any
@@ -1295,18 +1213,16 @@ function prepareForStartup() {
 
   // setup simple gestures support
   gGestureSupport.init(true);
 }
 
 function delayedStartup(isLoadingBlank, mustLoadSidebar) {
   Services.obs.addObserver(gSessionHistoryObserver, "browser:purge-session-history", false);
   Services.obs.addObserver(gXPInstallObserver, "addon-install-blocked", false);
-  Services.obs.addObserver(gXPInstallObserver, "addon-install-failed", false);
-  Services.obs.addObserver(gXPInstallObserver, "addon-install-complete", false);
 
   BrowserOffline.init();
   OfflineApps.init();
 
   gBrowser.addEventListener("pageshow", function(evt) { setTimeout(pageShowEventHandlers, 0, evt); }, true);
 
   // Ensure login manager is up and running.
   Cc["@mozilla.org/login-manager;1"].getService(Ci.nsILoginManager);
@@ -1517,18 +1433,16 @@ function BrowserShutdown()
     FullZoom.destroy();
   }
   catch(ex) {
     Components.utils.reportError(ex);
   }
 
   Services.obs.removeObserver(gSessionHistoryObserver, "browser:purge-session-history");
   Services.obs.removeObserver(gXPInstallObserver, "addon-install-blocked");
-  Services.obs.removeObserver(gXPInstallObserver, "addon-install-failed");
-  Services.obs.removeObserver(gXPInstallObserver, "addon-install-complete");
   Services.obs.removeObserver(gPluginHandler.pluginCrashed, "plugin-crashed");
 
   try {
     gBrowser.removeProgressListener(window.XULBrowserWindow);
     gBrowser.removeTabsProgressListener(window.TabsProgressListener);
   } catch (ex) {
   }
 
--- a/browser/base/content/browser.xul
+++ b/browser/base/content/browser.xul
@@ -603,17 +603,16 @@
                  ontextreverted="return this.handleRevert();"
                  pageproxystate="invalid"
                  onsearchbegin="LocationBarHelpers._searchBegin();"
                  onsearchcomplete="LocationBarHelpers._searchComplete();"
                  onfocus="document.getElementById('identity-box').style.MozUserFocus= 'normal'"
                  onblur="setTimeout(function() document.getElementById('identity-box').style.MozUserFocus = '', 0);">
           <box id="notification-popup-box" hidden="true" align="center">
             <image id="geo-notification-icon" class="notification-anchor-icon"/>
-            <image id="addons-notification-icon" class="notification-anchor-icon"/>
           </box>
           <!-- Use onclick instead of normal popup= syntax since the popup
                code fires onmousedown, and hence eats our favicon drag events.
                We only add the identity-box button to the tab order when the location bar
                has focus, otherwise pressing F6 focuses it instead of the location bar -->
           <box id="identity-box" role="button"
                onclick="gIdentityHandler.handleIdentityButtonEvent(event);"
                onkeypress="gIdentityHandler.handleIdentityButtonEvent(event);">
--- a/browser/base/content/test/Makefile.in
+++ b/browser/base/content/test/Makefile.in
@@ -124,17 +124,16 @@ endif
                  browser_bug484315.js \
                  browser_bug491431.js \
                  browser_bug495058.js \
                  browser_bug517902.js \
                  browser_bug520538.js \
                  browser_bug521216.js \
                  browser_bug537474.js \
                  browser_bug550565.js \
-                 browser_bug553455.js \
                  browser_bug555224.js \
                  browser_bug555767.js \
                  browser_bug556061.js \
                  browser_bug562649.js \
                  browser_bug563588.js \
                  browser_contextSearchTabPosition.js \
                  browser_ctrlTab.js \
                  browser_discovery.js \
deleted file mode 100644
--- a/browser/base/content/test/browser_bug553455.js
+++ /dev/null
@@ -1,270 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- * http://creativecommons.org/publicdomain/zero/1.0/
- */
-
-const TESTROOT = "http://example.com/browser/toolkit/mozapps/extensions/test/xpinstall/";
-const XPINSTALL_URL = "chrome://mozapps/content/xpinstall/xpinstallConfirm.xul";
-
-function wait_for_notification(aCallback) {
-  PopupNotifications.panel.addEventListener("popupshown", function() {
-    PopupNotifications.panel.removeEventListener("popupshown", arguments.callee, false);
-    aCallback(PopupNotifications.panel);
-  }, false);
-}
-
-function wait_for_install_dialog(aCallback) {
-  Services.wm.addListener({
-    onOpenWindow: function(aXULWindow) {
-      Services.wm.removeListener(this);
-
-      var domwindow = aXULWindow.QueryInterface(Ci.nsIInterfaceRequestor)
-                                .getInterface(Ci.nsIDOMWindowInternal);
-      domwindow.addEventListener("load", function() {
-        domwindow.removeEventListener("load", arguments.callee, false);
-
-        is(domwindow.document.location.href, XPINSTALL_URL, "Should have seen the right window open");
-
-        // Allow other window load listeners to execute before passing to callback
-        executeSoon(function() {
-          // Override the countdown timer on the accept button
-          var button = domwindow.document.documentElement.getButton("accept");
-          button.disabled = false;
-
-          aCallback(domwindow);
-        });
-      }, false);
-    },
-
-    onCloseWindow: function(aXULWindow) {
-    },
-
-    onWindowTitleChange: function(aXULWindow, aNewTitle) {
-    }
-  });
-}
-
-var TESTS = [
-function test_blocked_install() {
-  var triggers = encodeURIComponent(JSON.stringify({
-    "XPI": "unsigned.xpi"
-  }));
-  gBrowser.selectedTab = gBrowser.addTab();
-  gBrowser.loadURI(TESTROOT + "installtrigger.html?" + triggers);
-
-  // Wait for the blocked notification
-  wait_for_notification(function(aPanel) {
-    let notification = aPanel.childNodes[0];
-    is(notification.id, "addon-install-blocked", "Should have seen the install blocked");
-    is(notification.button.label, "Allow", "Should have seen the right button");
-
-    // Click on Allow
-    EventUtils.synthesizeMouse(notification.button, 20, 10, {});
-
-    // Wait for the install confirmation dialog
-    wait_for_install_dialog(function(aWindow) {
-      aWindow.document.documentElement.acceptDialog();
-
-      // Wait for the complete notification
-      wait_for_notification(function(aPanel) {
-        let notification = aPanel.childNodes[0];
-        is(notification.id, "addon-install-complete", "Should have seen the install complete");
-        is(notification.button.label, "Restart Now", "Should have seen the right button");
-
-        AddonManager.getAllInstalls(function(aInstalls) {
-        is(aInstalls.length, 1, "Should be one pending install");
-          aInstalls[0].cancel();
-
-          gBrowser.removeTab(gBrowser.selectedTab);
-          runNextTest();
-        });
-      });
-    });
-  });
-},
-
-function test_whitelisted_install() {
-  var pm = Services.perms;
-  pm.add(makeURI("http://example.com/"), "install", pm.ALLOW_ACTION);
-
-  var triggers = encodeURIComponent(JSON.stringify({
-    "XPI": "unsigned.xpi"
-  }));
-  gBrowser.selectedTab = gBrowser.addTab();
-  gBrowser.loadURI(TESTROOT + "installtrigger.html?" + triggers);
-
-  // Wait for the install confirmation dialog
-  wait_for_install_dialog(function(aWindow) {
-    aWindow.document.documentElement.acceptDialog();
-
-    // Wait for the complete notification
-    wait_for_notification(function(aPanel) {
-      let notification = aPanel.childNodes[0];
-      is(notification.id, "addon-install-complete", "Should have seen the install complete");
-      is(notification.button.label, "Restart Now", "Should have seen the right button");
-
-      AddonManager.getAllInstalls(function(aInstalls) {
-        is(aInstalls.length, 1, "Should be one pending install");
-        aInstalls[0].cancel();
-
-        gBrowser.removeTab(gBrowser.selectedTab);
-        Services.perms.remove("example.com", "install");
-        runNextTest();
-      });
-    });
-  });
-},
-
-function test_failed_download() {
-  var pm = Services.perms;
-  pm.add(makeURI("http://example.com/"), "install", pm.ALLOW_ACTION);
-
-  var triggers = encodeURIComponent(JSON.stringify({
-    "XPI": "missing.xpi"
-  }));
-  gBrowser.selectedTab = gBrowser.addTab();
-  gBrowser.loadURI(TESTROOT + "installtrigger.html?" + triggers);
-
-  // Wait for the failed notification
-  wait_for_notification(function(aPanel) {
-    let notification = aPanel.childNodes[0];
-    is(notification.id, "addon-install-failed", "Should have seen the install fail");
-
-    gBrowser.removeTab(gBrowser.selectedTab);
-    Services.perms.remove("example.com", "install");
-    runNextTest();
-  });
-},
-
-function test_corrupt_file() {
-  var pm = Services.perms;
-  pm.add(makeURI("http://example.com/"), "install", pm.ALLOW_ACTION);
-
-  var triggers = encodeURIComponent(JSON.stringify({
-    "XPI": "corrupt.xpi"
-  }));
-  gBrowser.selectedTab = gBrowser.addTab();
-  gBrowser.loadURI(TESTROOT + "installtrigger.html?" + triggers);
-
-  // Wait for the failed notification
-  wait_for_notification(function(aPanel) {
-    let notification = aPanel.childNodes[0];
-    is(notification.id, "addon-install-failed", "Should have seen the install fail");
-
-    gBrowser.removeTab(gBrowser.selectedTab);
-    Services.perms.remove("example.com", "install");
-    runNextTest();
-  });
-},
-
-function test_incompatible() {
-  var pm = Services.perms;
-  pm.add(makeURI("http://example.com/"), "install", pm.ALLOW_ACTION);
-
-  var triggers = encodeURIComponent(JSON.stringify({
-    "XPI": "incompatible.xpi"
-  }));
-  gBrowser.selectedTab = gBrowser.addTab();
-  gBrowser.loadURI(TESTROOT + "installtrigger.html?" + triggers);
-
-  // Wait for the failed notification
-  wait_for_notification(function(aPanel) {
-    let notification = aPanel.childNodes[0];
-    is(notification.id, "addon-install-failed", "Should have seen the install fail");
-
-    gBrowser.removeTab(gBrowser.selectedTab);
-    Services.perms.remove("example.com", "install");
-    runNextTest();
-  });
-},
-
-function test_restartless() {
-  var pm = Services.perms;
-  pm.add(makeURI("http://example.com/"), "install", pm.ALLOW_ACTION);
-
-  var triggers = encodeURIComponent(JSON.stringify({
-    "XPI": "restartless.xpi"
-  }));
-  gBrowser.selectedTab = gBrowser.addTab();
-  gBrowser.loadURI(TESTROOT + "installtrigger.html?" + triggers);
-
-  // Wait for the install confirmation dialog
-  wait_for_install_dialog(function(aWindow) {
-    aWindow.document.documentElement.acceptDialog();
-
-    // Wait for the complete notification
-    wait_for_notification(function(aPanel) {
-      let notification = aPanel.childNodes[0];
-      is(notification.id, "addon-install-complete", "Should have seen the install complete");
-      is(notification.button.label, "Open Add-ons Manager", "Should have seen the right button");
-
-      AddonManager.getAllInstalls(function(aInstalls) {
-        is(aInstalls.length, 0, "Should be no pending installs");
-
-        AddonManager.getAddonByID("restartless-xpi@tests.mozilla.org", function(aAddon) {
-          aAddon.uninstall();
-
-          gBrowser.removeTab(gBrowser.selectedTab);
-          Services.perms.remove("example.com", "install");
-          runNextTest();
-        });
-      });
-    });
-  });
-},
-
-function test_multiple() {
-  var pm = Services.perms;
-  pm.add(makeURI("http://example.com/"), "install", pm.ALLOW_ACTION);
-
-  var triggers = encodeURIComponent(JSON.stringify({
-    "Unsigned XPI": "unsigned.xpi",
-    "Restartless XPI": "restartless.xpi"
-  }));
-  gBrowser.selectedTab = gBrowser.addTab();
-  gBrowser.loadURI(TESTROOT + "installtrigger.html?" + triggers);
-
-  // Wait for the install confirmation dialog
-  wait_for_install_dialog(function(aWindow) {
-    aWindow.document.documentElement.acceptDialog();
-
-    // Wait for the complete notification
-    wait_for_notification(function(aPanel) {
-      let notification = aPanel.childNodes[0];
-      is(notification.id, "addon-install-complete", "Should have seen the install complete");
-      is(notification.button.label, "Restart Now", "Should have seen the right button");
-
-      AddonManager.getAllInstalls(function(aInstalls) {
-        is(aInstalls.length, 1, "Should be one pending install");
-        aInstalls[0].cancel();
-
-        AddonManager.getAddonByID("restartless-xpi@tests.mozilla.org", function(aAddon) {
-          aAddon.uninstall();
-
-          gBrowser.removeTab(gBrowser.selectedTab);
-          Services.perms.remove("example.com", "install");
-          runNextTest();
-        });
-      });
-    });
-  });
-}
-];
-
-function runNextTest() {
-  AddonManager.getAllInstalls(function(aInstalls) {
-    is(aInstalls.length, 0, "Should be no active installs");
-
-    if (TESTS.length == 0) {
-      finish();
-      return;
-    }
-
-    TESTS.shift()();
-  });
-}
-
-function test() {
-  waitForExplicitFinish();
-
-  runNextTest();
-}
--- a/browser/locales/en-US/chrome/browser/browser.properties
+++ b/browser/locales/en-US/chrome/browser/browser.properties
@@ -30,37 +30,16 @@ xpinstallPromptAllowButton=Allow
 # Be sure you do not choose an accesskey that is used elsewhere in the active context (e.g. main menu bar, submenu of the warning popup button)
 # See http://www.mozilla.org/access/keyboard/accesskey for details
 xpinstallPromptAllowButton.accesskey=A
 xpinstallDisabledMessageLocked=Software installation has been disabled by your system administrator.
 xpinstallDisabledMessage=Software installation is currently disabled. Click Enable and try again.
 xpinstallDisabledButton=Enable
 xpinstallDisabledButton.accesskey=n
 
-# LOCALIZATION NOTE (addonsInstalled, addonsInstalledNeedsRestart):
-# Semi-colon list of plural forms. See:
-# http://developer.mozilla.org/en/docs/Localization_and_Plurals
-# #1 first add-on's name, #2 number of add-ons, #3 application name
-addonsInstalled=#1 has been installed successfully.;#2 add-ons have been installed successfully.
-addonsInstalledNeedsRestart=#1 will be installed after you restart #3.;#2 add-ons will be installed after you restart #3.
-addonInstallRestartButton=Restart Now
-addonInstallRestartButton.accesskey=R
-addonInstallManage=Open Add-ons Manager
-addonInstallManage.accesskey=O
-
-# LOCALIZATION NOTE (addonError-1, addonError-2, addonError-3, addonError-4, addonErrorIncompatible, addonErrorBlocklisted):
-# #1 is the add-on name, #2 is the host name, #3 is the application name
-# #4 is the application version
-addonError-1=The add-on could not be downloaded because of a connection failure on #2.
-addonError-2=The add-on from #2 could not be installed because it does not match the add-on #3 expected.
-addonError-3=The add-on downloaded from #2 could not be installed because it appears to be corrupt.
-addonError-4=#1 could not be installed because Firefox cannot modify the needed file.
-addonErrorIncompatible=#1 could not be installed because it is not compatible with #3 #4.
-addonErrorBlocklisted=#1 could not be installed because it has a high risk of causing stability or security problems.
-
 # LOCALIZATION NOTE (lwthemeInstallRequest.message): %S will be replaced with
 # the host name of the site.
 lwthemeInstallRequest.message=This site (%S) attempted to install a theme.
 lwthemeInstallRequest.allowButton=Allow
 lwthemeInstallRequest.allowButton.accesskey=a
 
 lwthemePostInstallNotification.message=A new theme has been installed.
 lwthemePostInstallNotification.undoButton=Undo
--- a/browser/themes/gnomestripe/browser/browser.css
+++ b/browser/themes/gnomestripe/browser/browser.css
@@ -983,43 +983,27 @@ toolbar[iconsize="small"] #fullscreen-bu
   height: 64px;
   -moz-margin-end: 10px;
 }
 
 .popup-notification-icon[popupid="geolocation"] {
   list-style-image: url(chrome://browser/skin/Geo.png);
 }
 
-.popup-notification-icon[popupid="xpinstall-disabled"],
-.popup-notification-icon[popupid="addon-install-blocked"],
-.popup-notification-icon[popupid="addon-install-failed"],
-.popup-notification-icon[popupid="addon-install-complete"] {
-  list-style-image: url(chrome://mozapps/skin/extensions/extensionGeneric.png);
-  width: 32px;
-  height: 32px;
-}
-
 /* Notification icon box */
 #notification-popup-box {
   margin: 0 3px;
 }
 
-.notification-anchor-icon {
+#geo-notification-icon {
+  list-style-image: url(chrome://browser/skin/Geo.png);
   width: 16px;
   height: 16px;
 }
 
-#geo-notification-icon {
-  list-style-image: url(chrome://browser/skin/Geo.png);
-}
-
-#addons-notification-icon {
-  list-style-image: url(chrome://mozapps/skin/extensions/extensionGeneric-16.png);
-}
-
 /* Feed icon */
 #feed-button,
 #feed-button > .button-box,
 #feed-button:hover:active > .button-box {
   padding: 0px;
   margin: 0px;
   border: 0px; 
   background-color: transparent;
--- a/browser/themes/pinstripe/browser/browser.css
+++ b/browser/themes/pinstripe/browser/browser.css
@@ -1817,53 +1817,37 @@ toolbarbutton.chevron > .toolbarbutton-m
   margin-top: -1px;
   margin-left: -27px;
 }
 
 #notification-popup-box {
   margin: 0 3px;
 }
 
-.notification-anchor-icon {
+#geo-notification-icon {
+  list-style-image: url(chrome://browser/skin/Geo.png);
   width: 16px;
   height: 16px;
   margin: 0 2px;
 }
 
-#geo-notification-icon {
-  list-style-image: url(chrome://browser/skin/Geo.png);
-}
-
-#addons-notification-icon {
-  list-style-image: url(chrome://mozapps/skin/extensions/extensionGeneric-16.png);
-}
-
 .popup-notification-description {
   color: #fff;
 }
 
 .popup-notification-icon {
   width: 64px;
   height: 64px;
   -moz-margin-end: 10px;
 }
 
 .popup-notification-icon[popupid="geolocation"] {
   list-style-image: url(chrome://browser/skin/Geo.png);
 }
 
-.popup-notification-icon[popupid="xpinstall-disabled"],
-.popup-notification-icon[popupid="addon-install-blocked"],
-.popup-notification-icon[popupid="addon-install-failed"],
-.popup-notification-icon[popupid="addon-install-complete"] {
-  list-style-image: url(chrome://mozapps/skin/extensions/extensionGeneric.png);
-  width: 32px;
-  height: 32px;
-}
-
 #identity-popup-container,
 #identity-popup-notification-container {
   margin: 4px 3px 2px -30px;
   color: #fff;
 }
 
 #identity-popup-content-box {
   margin-top: 4px;
--- a/browser/themes/winstripe/browser/browser.css
+++ b/browser/themes/winstripe/browser/browser.css
@@ -1601,43 +1601,27 @@ toolbarbutton.bookmark-item[dragover="tr
   height: 64px;
   -moz-margin-end: 10px;
 }
 
 .popup-notification-icon[popupid="geolocation"] {
   list-style-image: url(chrome://browser/skin/Geo.png);
 }
 
-.popup-notification-icon[popupid="xpinstall-disabled"],
-.popup-notification-icon[popupid="addon-install-blocked"],
-.popup-notification-icon[popupid="addon-install-failed"],
-.popup-notification-icon[popupid="addon-install-complete"] {
-  list-style-image: url(chrome://mozapps/skin/extensions/extensionGeneric.png);
-  width: 32px;
-  height: 32px;
-}
-
 /* Notification icon box */
 #notification-popup-box {
   margin: 0 3px;
 }
 
-.notification-anchor-icon {
+#geo-notification-icon {
+  list-style-image: url(chrome://browser/skin/Geo.png);
   width: 16px;
   height: 16px;
 }
 
-#geo-notification-icon {
-  list-style-image: url(chrome://browser/skin/Geo.png);
-}
-
-#addons-notification-icon {
-  list-style-image: url(chrome://mozapps/skin/extensions/extensionGeneric-16.png);
-}
-
 #identity-popup-container {
   min-width: 280px;
   padding: 9px;
 }
 
 #download-monitor {
   list-style-image: url("chrome://browser/skin/Toolbar.png");
   -moz-image-region: rect(0, 108px, 18px, 90px);
--- a/toolkit/locales/en-US/chrome/mozapps/extensions/extensions.properties
+++ b/toolkit/locales/en-US/chrome/mozapps/extensions/extensions.properties
@@ -25,16 +25,20 @@ uninstallNotice=%S has been removed.
 numReviews=#1 review;#1 reviews
 
 #LOCALIZATION NOTE (dateUpdated) %S is the date the addon was last updated
 dateUpdated=Updated %S
 
 #LOCALIZATION NOTE (incompatibleWith) %1$S is brand name, %2$S is application version
 incompatibleWith=Incompatible with %1$S %2$S
 
+incompatibleTitle2=Incompatible add-on
+#LOCALIZATION NOTE (incompatibleMessage2) %1$S is add-on name, %2$% is add-on version, %3$% is application name, %4$% is application version
+incompatibleMessage2=%1$S %2$S could not be installed because it is not compatible with %3$S %4$S.
+
 installDownloading=Downloading
 installDownloaded=Downloaded
 installDownloadFailed=Error downloading
 installVerifying=Verifying
 installInstalling=Installing
 installInstallPending=Ready to install
 installUpdatePending=Ready to update
 installEnablePending=Restart to enable
--- a/toolkit/mozapps/extensions/XPIProvider.jsm
+++ b/toolkit/mozapps/extensions/XPIProvider.jsm
@@ -546,17 +546,18 @@ function extractFiles(aZipFile, aDir) {
       let target = getTargetFile(aDir, entryName);
       if (!target.exists()) {
         try {
           target.create(Ci.nsILocalFile.DIRECTORY_TYPE,
                         FileUtils.PERMS_DIRECTORY);
         }
         catch (e) {
           ERROR("extractFiles: failed to create target directory for " +
-                "extraction file = " + target.path + ", exception = " + e);
+                "extraction file = " + target.path + ", exception = " + e +
+                "\n");
         }
       }
     }
 
     entries = zipReader.findEntries(null);
     while (entries.hasMore()) {
       let entryName = entries.getNext();
       let target = getTargetFile(aDir, entryName);
@@ -4117,17 +4118,17 @@ AddonInstall.prototype = {
    * Notify listeners that the download failed.
    *
    * @param  aReason
    *         Something to log about the failure
    * @param  error
    *         The error code to pass to the listeners
    */
   downloadFailed: function(aReason, aError) {
-    WARN("Download failed: " + aError);
+    WARN("Download failed: " + aError + "\n");
     this.state = AddonManager.STATE_DOWNLOAD_FAILED;
     this.error = aReason;
     XPIProvider.removeActiveInstall(this);
     AddonManagerPrivate.callInstallListeners("onDownloadFailed", this.listeners,
                                              this.wrapper);
     try {
       this.file.remove(true);
     }
--- a/toolkit/mozapps/extensions/amWebInstallListener.js
+++ b/toolkit/mozapps/extensions/amWebInstallListener.js
@@ -56,192 +56,141 @@ Components.utils.import("resource://gre/
   this.__defineGetter__(aName, function() {
     Components.utils.import("resource://gre/modules/AddonLogging.jsm");
 
     LogManager.getLogger("addons.weblistener", this);
     return this[aName];
   });
 }, this);
 
-function notifyObservers(aTopic, aWindow, aUri, aInstalls) {
-  let info = {
-    originatingWindow: aWindow,
-    originatingURI: aUri,
-    installs: aInstalls,
-
-    QueryInterface: XPCOMUtils.generateQI([Ci.amIWebInstallInfo])
-  };
-  Services.obs.notifyObservers(info, aTopic, null);
-}
-
 /**
  * Creates a new installer to monitor downloads and prompt to install when
  * ready
  *
  * @param  aWindow
  *         The window that started the installations
  * @param  aUrl
  *         The URL that started the installations
  * @param  aInstalls
  *         An array of AddonInstalls
  */
 function Installer(aWindow, aUrl, aInstalls) {
   this.window = aWindow;
   this.url = aUrl;
   this.downloads = aInstalls;
-  this.installed = [];
+  this.installs = [];
 
-  notifyObservers("addon-install-started", aWindow, aUrl, aInstalls);
+  this.bundle = Cc["@mozilla.org/intl/stringbundle;1"].
+                getService(Ci.nsIStringBundleService).
+                createBundle("chrome://mozapps/locale/extensions/extensions.properties");
 
+  this.count = aInstalls.length;
   aInstalls.forEach(function(aInstall) {
     aInstall.addListener(this);
 
-    // Start downloading if it hasn't already begun
-    if (aInstall.state == AddonManager.STATE_AVAILABLE)
+    // Might already be a local file
+    if (aInstall.state == AddonManager.STATE_DOWNLOADED)
+      this.onDownloadEnded(aInstall);
+    else if (aInstall.state == AddonManager.STATE_DOWNLOAD_FAILED)
+      this.onDownloadFailed(aInstall);
+    else
       aInstall.install();
   }, this);
-
-  this.checkAllDownloaded();
 }
 
 Installer.prototype = {
   window: null,
   downloads: null,
-  installed: null,
+  installs: null,
+  count: null,
 
   /**
    * Checks if all downloads are now complete and if so prompts to install.
    */
   checkAllDownloaded: function() {
-    var failed = [];
-    var installs = [];
-
-    for (let i = 0; i < this.downloads.length; i++) {
-      let install = this.downloads[i];
-      switch (install.state) {
-      case AddonManager.STATE_AVAILABLE:
-      case AddonManager.STATE_DOWNLOADING:
-        // Exit early if any add-ons haven't started downloading yet or are
-        // still downloading
-        return;
-      case AddonManager.STATE_DOWNLOAD_FAILED:
-        failed.push(install);
-        break;
-      case AddonManager.STATE_DOWNLOADED:
-        // App disabled items are not compatible and so fail to install
-        if (install.addon.appDisabled)
-          failed.push(install);
-        else
-          installs.push(install);
-        break;
-      default:
-        WARN("Download of " + install.sourceURL + " in unexpected state " +
-             install.state);
-      }
-    }
-
-    this.downloads = installs;
-
-    if (failed.length > 0) {
-      // Stop listening and cancel any installs that are failed because of
-      // compatibility reasons.
-      failed.forEach(function(aInstall) {
-        if (aInstall.state == AddonManager.STATE_DOWNLOADED) {
-          aInstall.removeListener(this);
-          aInstall.cancel();
-        }
-      }, this);
-      notifyObservers("addon-install-failed", this.window, this.url, failed);
-    }
-
-    // If none of the downloads were successful then exit early
-    if (this.downloads.length == 0)
+    if (--this.count > 0)
       return;
 
-    // Check for a custom installation prompt that may be provided by the
-    // applicaton
+    // Maybe none of the downloads were sucessful
+    if (this.installs.length == 0)
+      return;
+
     if ("@mozilla.org/addons/web-install-prompt;1" in Cc) {
       try {
         let prompt = Cc["@mozilla.org/addons/web-install-prompt;1"].
                      getService(Ci.amIWebInstallPrompt);
-        prompt.confirm(this.window, this.url, this.downloads, this.downloads.length);
+        prompt.confirm(this.window, this.url, this.installs, this.installs.length);
         return;
       }
       catch (e) {}
     }
 
     let args = {};
     args.url = this.url;
-    args.installs = this.downloads;
+    args.installs = this.installs;
     args.wrappedJSObject = args;
 
     Services.ww.openWindow(this.window, "chrome://mozapps/content/xpinstall/xpinstallConfirm.xul",
                            null, "chrome,modal,centerscreen", args);
   },
 
-  /**
-   * Checks if all installs are now complete and if so notifies observers.
-   */
-  checkAllInstalled: function() {
-    var failed = [];
-
-    for (let i = 0; i < this.downloads.length; i++) {
-      let install = this.downloads[i];
-      switch(install.state) {
-      case AddonManager.STATE_DOWNLOADED:
-      case AddonManager.STATE_INSTALLING:
-        // Exit early if any add-ons haven't started installing yet or are
-        // still installing
-        return;
-      case AddonManager.STATE_INSTALL_FAILED:
-        failed.push(install);
-        break;
-      }
-    }
-
-    this.downloads = null;
-
-    if (failed.length > 0)
-      notifyObservers("addon-install-failed", this.window, this.url, failed);
-
-    if (this.installed.length > 0)
-      notifyObservers("addon-install-complete", this.window, this.url, this.installed);
-    this.installed = null;
-  },
-
   onDownloadCancelled: function(aInstall) {
     aInstall.removeListener(this);
+
     this.checkAllDownloaded();
   },
 
   onDownloadFailed: function(aInstall) {
     aInstall.removeListener(this);
+
+    // TODO show some better error
+    Services.prompt.alert(this.window, "Download Failed", "The download of " +
+                          aInstall.sourceURL + " failed: " + aInstall.error);
     this.checkAllDownloaded();
   },
 
   onDownloadEnded: function(aInstall) {
+    aInstall.removeListener(this);
+
+    if (aInstall.addon.appDisabled) {
+      // App disabled items are not compatible
+      aInstall.cancel();
+
+      let title = null;
+      let text = null;
+
+      let problems = "";
+      if (!aInstall.addon.isCompatible)
+        problems += "incompatible, ";
+      if (!aInstall.addon.providesUpdatesSecurely)
+        problems += "insecure updates, ";
+      if (aInstall.addon.blocklistState == Ci.nsIBlocklistService.STATE_BLOCKED) {
+        problems += "blocklisted, ";
+        title = bundle.GetStringFromName("blocklistedInstallTitle2");
+        text = this.bundle.formatStringFromName("blocklistedInstallMsg2",
+                                                [install.addon.name], 1);
+      }
+      problems = problems.substring(0, problems.length - 2);
+      WARN("Not installing " + aInstall.addon.id + " because of the following: " + problems);
+
+      title = this.bundle.GetStringFromName("incompatibleTitle2", 1);
+      text = this.bundle.formatStringFromName("incompatibleMessage2",
+                                              [aInstall.addon.name,
+                                               aInstall.addon.version,
+                                               Services.appinfo.name,
+                                               Services.appinfo.version], 4);
+      Services.prompt.alert(this.window, title, text);
+    }
+    else {
+      this.installs.push(aInstall);
+    }
+
     this.checkAllDownloaded();
     return false;
   },
-
-  onInstallCancelled: function(aInstall) {
-    aInstall.removeListener(this);
-    this.checkAllInstalled();
-  },
-
-  onInstallFailed: function(aInstall) {
-    aInstall.removeListener(this);
-    this.checkAllInstalled();
-  },
-
-  onInstallEnded: function(aInstall) {
-    aInstall.removeListener(this);
-    this.installed.push(aInstall);
-    this.checkAllInstalled();
-  }
 };
 
 function extWebInstallListener() {
 }
 
 extWebInstallListener.prototype = {
   /**
    * @see amIWebInstallListener.idl
--- a/toolkit/mozapps/extensions/test/xpinstall/Makefile.in
+++ b/toolkit/mozapps/extensions/test/xpinstall/Makefile.in
@@ -84,18 +84,16 @@ include $(topsrcdir)/config/rules.mk
                  browser_relative.js \
                  unsigned.xpi \
                  signed.xpi \
                  signed2.xpi \
                  signed-no-o.xpi \
                  signed-no-cn.xpi \
                  signed-untrusted.xpi \
                  signed-tampered.xpi \
-                 restartless.xpi \
-                 incompatible.xpi \
                  empty.xpi \
                  corrupt.xpi \
                  enabled.html \
                  installtrigger.html \
                  startsoftwareupdate.html \
                  installchrome.html \
                  authRedirect.sjs \
                  cookieRedirect.sjs \
--- a/toolkit/mozapps/extensions/test/xpinstall/head.js
+++ b/toolkit/mozapps/extensions/test/xpinstall/head.js
@@ -47,82 +47,66 @@ var Harness = {
   // installation.
   installEndedCallback: null,
   // If set will be called when all triggered items are installed or the install
   // is canceled.
   installsCompletedCallback: null,
 
   pendingCount: null,
   installCount: null,
-  runningInstalls: null,
 
   // Setup and tear down functions
   setup: function() {
     waitForExplicitFinish();
     Services.prefs.setBoolPref(PREF_LOGGING_ENABLED, true);
-    Services.obs.addObserver(this, "addon-install-started", false);
     Services.obs.addObserver(this, "addon-install-blocked", false);
-    Services.obs.addObserver(this, "addon-install-failed", false);
-    Services.obs.addObserver(this, "addon-install-complete", false);
     Services.wm.addListener(this);
 
     AddonManager.addInstallListener(this);
     this.installCount = 0;
     this.pendingCount = 0;
-    this.runningInstalls = [];
 
     var self = this;
     registerCleanupFunction(function() {
       Services.prefs.clearUserPref(PREF_LOGGING_ENABLED);
-      Services.obs.removeObserver(self, "addon-install-started");
       Services.obs.removeObserver(self, "addon-install-blocked");
-      Services.obs.removeObserver(self, "addon-install-failed");
-      Services.obs.removeObserver(self, "addon-install-complete");
       Services.wm.removeListener(self);
 
       AddonManager.removeInstallListener(self);
     });
   },
 
   finish: function() {
     AddonManager.getAllInstalls(function(installs) {
       is(installs.length, 0, "Should be no active installs at the end of the test");
       finish();
     });
   },
 
   endTest: function() {
     // Defer the final notification to allow things like the InstallTrigger
     // callback to complete
-    var self = this;
+    let callback = this.installsCompletedCallback;
+    let count = this.installCount;
     executeSoon(function() {
-      let callback = self.installsCompletedCallback;
-      let count = self.installCount;
-
-      is(self.runningInstalls.length, 0, "Should be no running installs left");
-      self.runningInstalls.forEach(function(aInstall) {
-        info("Install for " + aInstall.sourceURL + " is in state " + aInstall.state);
-      });
-
-      self.installBlockedCallback = null;
-      self.authenticationCallback = null;
-      self.installConfirmCallback = null;
-      self.downloadStartedCallback = null;
-      self.downloadProgressCallback = null;
-      self.downloadCancelledCallback = null;
-      self.downloadFailedCallback = null;
-      self.downloadEndedCallback = null;
-      self.installStartedCallback = null;
-      self.installFailedCallback = null;
-      self.installEndedCallback = null;
-      self.installsCompletedCallback = null;
-      self.runningInstalls = null;
-
       callback(count);
     });
+
+    this.installBlockedCallback = null;
+    this.authenticationCallback = null;
+    this.installConfirmCallback = null;
+    this.downloadStartedCallback = null;
+    this.downloadProgressCallback = null;
+    this.downloadCancelledCallback = null;
+    this.downloadFailedCallback = null;
+    this.downloadEndedCallback = null;
+    this.installStartedCallback = null;
+    this.installFailedCallback = null;
+    this.installEndedCallback = null;
+    this.installsCompletedCallback = null;
   },
 
   // Window open handling
   windowLoad: function(window) {
     // Allow any other load handlers to execute
     var self = this;
     executeSoon(function() { self.windowReady(window); } );
   },
@@ -212,20 +196,16 @@ var Harness = {
     }, false);
   },
 
   onCloseWindow: function(window) {
   },
 
   // Addon Install Listener
 
-  onNewInstall: function(install) {
-    this.runningInstalls.push(install);
-  },
-
   onDownloadStarted: function(install) {
     this.pendingCount++;
     if (this.downloadStartedCallback)
       this.downloadStartedCallback(install);
   },
 
   onDownloadProgress: function(install) {
     if (this.downloadProgressCallback)
@@ -233,20 +213,16 @@ var Harness = {
   },
 
   onDownloadEnded: function(install) {
     if (this.downloadEndedCallback)
       this.downloadEndedCallback(install);
   },
 
   onDownloadCancelled: function(install) {
-    isnot(this.runningInstalls.indexOf(install), -1,
-          "Should only see cancelations for started installs");
-    this.runningInstalls.splice(this.runningInstalls.indexOf(install), 1);
-
     if (this.downloadCancelledCallback)
       this.downloadCancelledCallback(install);
     this.checkTestEnded();
   },
 
   onDownloadFailed: function(install) {
     if (this.downloadFailedCallback)
       this.downloadFailedCallback(install);
@@ -267,61 +243,26 @@ var Harness = {
 
   onInstallFailed: function(install) {
     if (this.installFailedCallback)
       this.installFailedCallback(install);
     this.checkTestEnded();
   },
 
   checkTestEnded: function() {
+    dump("checkTestPending " + this.pendingCount + "\n");
     if (--this.pendingCount == 0)
       this.endTest();
   },
 
   // nsIObserver
 
   observe: function(subject, topic, data) {
     var installInfo = subject.QueryInterface(Components.interfaces.amIWebInstallInfo);
-    switch (topic) {
-    case "addon-install-started":
-      is(this.runningInstalls.length, installInfo.installs.length,
-         "Should have seen the expected number of installs started");
-      break;
-    case "addon-install-blocked":
-      this.installBlocked(installInfo);
-      break;
-    case "addon-install-failed":
-      installInfo.installs.forEach(function(aInstall) {
-        isnot(this.runningInstalls.indexOf(aInstall), -1,
-              "Should only see failures for started installs");
-
-        ok(aInstall.error != 0 || aInstall.addon.appDisabled,
-           "Failed installs should have an error or be appDisabled");
-
-        this.runningInstalls.splice(this.runningInstalls.indexOf(aInstall), 1);
-      }, this);
-      break;
-    case "addon-install-complete":
-      installInfo.installs.forEach(function(aInstall) {
-        isnot(this.runningInstalls.indexOf(aInstall), -1,
-              "Should only see completed events for started installs");
-
-        is(aInstall.error, 0, "Completed installs should have no error");
-        ok(!aInstall.appDisabled, "Completed installs should not be appDisabled");
-
-        // Complete installs are either in the INSTALLED or CANCELLED state
-        // since the test may cancel installs the moment they complete.
-        ok(aInstall.state == AddonManager.STATE_INSTALLED ||
-           aInstall.state == AddonManager.STATE_CANCELLED,
-           "Completed installs should be in the right state");
-
-        this.runningInstalls.splice(this.runningInstalls.indexOf(aInstall), 1);
-      }, this);
-      break;
-    }
+    this.installBlocked(installInfo);
   },
 
   QueryInterface: function(iid) {
     if (iid.equals(Components.interfaces.nsIObserver) ||
         iid.equals(Components.interfaces.nsIWindowMediatorListener) ||
         iid.equals(Components.interfaces.nsISupports))
       return this;