Bug 562495 - Support the new add-ons manager [r=dtownsend]
authorMark Finkle <mfinkle@mozilla.com>
Wed, 19 May 2010 22:43:02 -0400
changeset 66234 6ef91dfc79915ebb05ac11b36a949be7084feb0d
parent 66233 468fb2edd3e97ed4642fd3a0e76d6c570e1c45f4
child 66235 1e697b88f098af8bfabc2b80137e21371d398c15
push id1
push userroot
push dateTue, 26 Apr 2011 22:38:44 +0000
treeherdermozilla-beta@bfdb6e623a36 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdtownsend
bugs562495
Bug 562495 - Support the new add-ons manager [r=dtownsend]
mobile/app/mobile.js
mobile/chrome/content/bindings/extensions.xml
mobile/chrome/content/browser.js
mobile/chrome/content/extensions.js
mobile/components/AddonUpdateService.js
mobile/components/XPIDialogService.js
mobile/themes/hildon/browser.css
--- a/mobile/app/mobile.js
+++ b/mobile/app/mobile.js
@@ -143,21 +143,16 @@ pref("browser.formfill.enable", true);
 #ifdef WINCE
 pref("layout.css.devPixelsPerPx", "1");
 #endif
 
 /* spellcheck */
 pref("layout.spellcheckDefault", 1);
 
 /* extension manager and xpinstall */
-pref("xpinstall.dialog.confirm", "chrome://mozapps/content/xpinstall/xpinstallConfirm.xul");
-pref("xpinstall.dialog.progress.skin", "chrome://browser/content/browser.xul");
-pref("xpinstall.dialog.progress.chrome", "chrome://browser/content/browser.xul");
-pref("xpinstall.dialog.progress.type.skin", "navigator:browser");
-pref("xpinstall.dialog.progress.type.chrome", "navigator:browser");
 pref("xpinstall.whitelist.add", "addons.mozilla.org");
 
 pref("extensions.autoupdate.enabled", true);
 pref("extensions.autoupdate.interval", 86400);
 pref("extensions.update.enabled", false);
 pref("extensions.update.interval", 86400);
 pref("extensions.dss.enabled", false);
 pref("extensions.dss.switchPending", false);
--- a/mobile/chrome/content/bindings/extensions.xml
+++ b/mobile/chrome/content/bindings/extensions.xml
@@ -10,17 +10,17 @@
 <bindings
     xmlns="http://www.mozilla.org/xbl"
     xmlns:xbl="http://www.mozilla.org/xbl"
     xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
 
   <binding id="extension-local" extends="chrome://browser/content/bindings.xml#richlistitem">
     <content orient="vertical">
       <xul:hbox align="start">
-        <xul:image xbl:inherits="src=iconURL"/>
+        <xul:image class="addon-image" xbl:inherits="src=iconURL"/>
         <xul:vbox flex="1">
           <xul:hbox align="center">
             <xul:label class="title" xbl:inherits="value=name" crop="end" flex="1"/>
             <xul:label class="normal" xbl:inherits="value=version"/>
             <xul:spacer flex="1000"/>
             <xul:label class="normal" xbl:inherits="value=typeLabel"/>
           </xul:hbox>
           <xul:vbox>
--- a/mobile/chrome/content/browser.js
+++ b/mobile/chrome/content/browser.js
@@ -469,17 +469,17 @@ var Browser = {
     ih = new InputHandler(container);
 
     BrowserUI.init();
 
     window.controllers.appendController(this);
     window.controllers.appendController(BrowserUI);
 
     var os = Cc["@mozilla.org/observer-service;1"].getService(Ci.nsIObserverService);
-    os.addObserver(gXPInstallObserver, "xpinstall-install-blocked", false);
+    os.addObserver(gXPInstallObserver, "addon-install-blocked", false);
     os.addObserver(gSessionHistoryObserver, "browser:purge-session-history", false);
 
     // clear out tabs the user hasn't touched lately on memory crunch
     os.addObserver(MemoryObserver, "memory-pressure", false);
 
     // search engine changes
     os.addObserver(BrowserSearch, "browser-search-engine-modified", false);
 
@@ -618,17 +618,17 @@ var Browser = {
   },
 
   shutdown: function shutdown() {
     this._browserView.uninit();
     BrowserUI.uninit();
     this._pluginObserver.stop();
 
     var os = Cc["@mozilla.org/observer-service;1"].getService(Ci.nsIObserverService);
-    os.removeObserver(gXPInstallObserver, "xpinstall-install-blocked");
+    os.removeObserver(gXPInstallObserver, "addon-install-blocked");
     os.removeObserver(gSessionHistoryObserver, "browser:purge-session-history");
     os.removeObserver(MemoryObserver, "memory-pressure");
     os.removeObserver(BrowserSearch, "browser-search-engine-modified");
 
     window.controllers.removeController(this);
     window.controllers.removeController(BrowserUI);
   },
 
@@ -2480,23 +2480,28 @@ const gPopupBlockerObserver = {
   }
 };
 
 const gXPInstallObserver = {
   observe: function xpi_observer(aSubject, aTopic, aData)
   {
     var brandBundle = document.getElementById("bundle_brand");
     switch (aTopic) {
-      case "xpinstall-install-blocked":
-        var installInfo = aSubject.QueryInterface(Ci.nsIXPIInstallInfo);
+      case "addon-install-blocked":
+        var installInfo = aSubject.QueryInterface(Ci.amIWebInstallInfo);
         var host = installInfo.originatingURI.host;
         var brandShortName = brandBundle.getString("brandShortName");
         var notificationName, messageString, buttons;
         var strings = Elements.browserBundle;
-        if (!gPrefService.getBoolPref("xpinstall.enabled")) {
+        var enabled = true;
+        try {
+          enabled = gPrefService.getBoolPref("xpinstall.enabled");
+        }
+        catch (e) {}
+        if (!enabled) {
           notificationName = "xpinstall-disabled";
           if (gPrefService.prefIsLocked("xpinstall.enabled")) {
             messageString = strings.getString("xpinstallDisabledMessageLocked");
             buttons = [];
           }
           else {
             messageString = strings.getFormattedString("xpinstallDisabledMessage",
                                                              [brandShortName, host]);
@@ -2516,19 +2521,18 @@ const gXPInstallObserver = {
           messageString = strings.getFormattedString("xpinstallPromptWarning",
                                                            [brandShortName, host]);
 
           buttons = [{
             label: strings.getString("xpinstallPromptAllowButton"),
             accessKey: null,
             popup: null,
             callback: function() {
-              // Kick off the xpinstall
-              var mgr = Cc["@mozilla.org/xpinstall/install-manager;1"].createInstance(Ci.nsIXPInstallManager);
-              mgr.initManagerWithInstallInfo(installInfo);
+              // Kick off the install
+              installInfo.install();
               return false;
             }
           }];
         }
 
         var nBox = Browser.getNotificationBox();
         if (!nBox.getNotificationWithValue(notificationName)) {
           const priority = nBox.PRIORITY_WARNING_MEDIUM;
--- a/mobile/chrome/content/extensions.js
+++ b/mobile/chrome/content/extensions.js
@@ -38,64 +38,45 @@
 const PREFIX_ITEM_URI = "urn:mozilla:item:";
 const PREFIX_NS_EM = "http://www.mozilla.org/2004/em-rdf#";
 
 const PREF_GETADDONS_REPOSITORY = "extensions.getAddons.repository";
 const PREF_GETADDONS_MAXRESULTS = "extensions.getAddons.maxResults";
 
 const URI_GENERIC_ICON_XPINSTALL = "chrome://browser/skin/images/alert-addons-30.png";
 
+XPCOMUtils.defineLazyGetter(this, "AddonManager", function() {
+  Cu.import("resource://gre/modules/AddonManager.jsm");
+  return AddonManager;
+});
+
 var ExtensionsView = {
-  _extmgr: null,
   _pref: null,
-  _rdf: null,
   _ios: null,
   _strings: {},
   _repo: null,
   _list: null,
   _localItem: null,
   _repoItem: null,
   _msg: null,
   _dloadmgr: null,
   _search: null,
   _restartCount: 0,
   _observerIndex: -1,
 
-  _isXPInstallEnabled: function ev__isXPInstallEnabled() {
-    let enabled = false;
-    let locked = false;
-    try {
-      enabled = this._pref.getBoolPref("xpinstall.enabled");
-      if (enabled)
-        return true;
-      locked = this._pref.prefIsLocked("xpinstall.enabled");
-    }
-    catch (e) { }
-
-    return false;
+  _getOpTypeForOperations: function ev__getOpTypeForOperations(aOperations) {
+    if (aOperations & AddonManager.PENDING_UNINSTALL)
+      return "needs-uninstall";
+    if (aOperations & AddonManager.PENDING_ENABLE)
+      return "needs-enable";
+    if (aOperations & AddonManager.PENDING_DISABLE)
+      return "needs-disable";
+    return "";
   },
-
-  _getIDFromURI: function ev__getIDFromURI(aURI) {
-    if (aURI.substring(0, PREFIX_ITEM_URI.length) == PREFIX_ITEM_URI)
-      return aURI.substring(PREFIX_ITEM_URI.length);
-    return aURI;
-  },
-
-  _getRDFProperty: function ev__getRDFProperty(aID, aName) {
-    let resource = this._rdf.GetResource(PREFIX_ITEM_URI + aID);
-    if (resource) {
-      let ds = this._extmgr.datasource;
-
-      let target = ds.GetTarget(resource, this._rdf.GetResource(PREFIX_NS_EM + aName), true);
-      if (target && target instanceof Ci.nsIRDFLiteral)
-        return target.Value;
-    }
-    return null;
-  },
-
+  
   _createItem: function ev__createItem(aAddon, aTypeName) {
     let item = document.createElement("richlistitem");
     item.setAttribute("id", PREFIX_ITEM_URI + aAddon.id);
     item.setAttribute("addonID", aAddon.id);
     item.setAttribute("typeName", aTypeName);
     item.setAttribute("type", aAddon.type);
     item.setAttribute("typeLabel", this._strings["addonType." + aAddon.type]);
     item.setAttribute("name", aAddon.name);
@@ -130,20 +111,20 @@ var ExtensionsView = {
       // If nothing aborted, quit the app
       if (cancelQuit.data == false) {
         let appStartup = Cc["@mozilla.org/toolkit/app-startup;1"].getService(Ci.nsIAppStartup);
         appStartup.quit(Ci.nsIAppStartup.eRestart | Ci.nsIAppStartup.eAttemptQuit);
       }
     }
   },
 
-  getElementForAddon: function ev_getElementForAddon(aID) {
-    let element = document.getElementById(PREFIX_ITEM_URI + aID);
+  getElementForAddon: function ev_getElementForAddon(aKey) {
+    let element = document.getElementById(PREFIX_ITEM_URI + aKey);
     if (!element && this._list)
-      element = this._list.getElementsByAttribute("xpiURL", aID)[0];
+      element = this._list.getElementsByAttribute("xpiURL", aKey)[0];
     return element;
   },
 
   showMessage: function ev_showMessage(aMsg, aValue, aButtonLabel, aShowCloseButton, aNotifyData) {
     let notification = this._msg.getNotificationWithValue(aValue);
     if (notification)
       return;
 
@@ -218,29 +199,25 @@ var ExtensionsView = {
   get visible() {
     let items = document.getElementById("panel-items");
     if (BrowserUI.isPanelVisible() && items.selectedPanel.id == "addons-container")
       return true;
     return false;
   },
 
   init: function ev_init() {
-    if (this._extmgr)
+    if (this._ios)
       return;
 
-    this._extmgr = Cc["@mozilla.org/extensions/manager;1"].getService(Ci.nsIExtensionManager);
     this._ios = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService);
-    this._dloadmgr = new XPInstallDownloadManager();
-    this._observerIndex = this._extmgr.addInstallListener(this._dloadmgr);
-
-    // Now look and see if we're being opened by XPInstall
-    var os = Cc["@mozilla.org/observer-service;1"].getService(Ci.nsIObserverService);
-    os.addObserver(this._dloadmgr, "xpinstall-download-started", false);
+    this._dloadmgr = new AddonInstallListener();
+    AddonManager.addInstallListener(this._dloadmgr);
 
     // Watch for add-on update notifications
+    let os = Cc["@mozilla.org/observer-service;1"].getService(Ci.nsIObserverService);
     os.addObserver(this, "addon-update-started", false);
     os.addObserver(this, "addon-update-ended", false);
 
     if (!gPrefService.getBoolPref("extensions.hideUpdateButton"))
       document.getElementById("addons-update-all").hidden = false;
 
     let self = this;
     let panels = document.getElementById("panel-items");
@@ -252,17 +229,16 @@ var ExtensionsView = {
                             false);
   },
 
   _delayedInit: function ev__delayedInit() {
     if (this._list)
       return;
 
     this._pref = Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefBranch2);
-    this._rdf = Cc["@mozilla.org/rdf/rdf-service;1"].getService(Ci.nsIRDFService);
     this._search = Cc["@mozilla.org/browser/search-service;1"].getService(Ci.nsIBrowserSearchService);
 
     let repository = "@mozilla.org/extensions/addon-repository;1";
     try {
       var repo = pref.getCharPref(PREF_GETADDONS_REPOSITORY);
       if (repo in Components.classes)
         repository = repo;
     } catch (e) { }
@@ -277,240 +253,178 @@ var ExtensionsView = {
     // was not visible at the time
     let notification = this._msg.getNotificationWithValue("restart-app");
     if (this._restartCount > 0 && !notification) {
       this.showRestart();
       this._restartCount--; // showRestart() always increments
     }
 
     let strings = Elements.browserBundle;
-    this._strings["addonType.2"] = strings.getString("addonType.2");
-    this._strings["addonType.4"] = strings.getString("addonType.4");
-    this._strings["addonType.8"] = strings.getString("addonType.8");
-    this._strings["addonType.1024"] = strings.getString("addonType.1024");
+    this._strings["addonType.extension"] = strings.getString("addonType.2");
+    this._strings["addonType.theme"] = strings.getString("addonType.4");
+    this._strings["addonType.locale"] = strings.getString("addonType.8");
+    this._strings["addonType.search"] = strings.getString("addonType.1024");
 
     let self = this;
     setTimeout(function() {
       self.getAddonsFromLocal();
       self.getAddonsFromRepo("");
     }, 0);
   },
 
   uninit: function ev_uninit() {
-    var os = Cc["@mozilla.org/observer-service;1"].getService(Ci.nsIObserverService);
-    os.removeObserver(this._dloadmgr, "xpinstall-download-started");
+    let os = Cc["@mozilla.org/observer-service;1"].getService(Ci.nsIObserverService);
     os.removeObserver(this, "addon-update-started");
     os.removeObserver(this, "addon-update-ended");
 
-    this._extmgr.removeInstallListenerAt(this._observerIndex);
+    AddonManager.removeInstallListener(this._dloadmgr);
   },
 
   hideOnSelect: function ev_handleEvent(aEvent) {
     // When list selection changes, be sure to close up any open options sections
     if (aEvent.target == this._list)
       this.hideOptions();
   },
 
   getAddonsFromLocal: function ev_getAddonsFromLocal() {
     this.clearSection("local");
 
-    let items = this._extmgr.getItemList(Ci.nsIUpdateItem.TYPE_ANY, {});
-
-    for (let i = 0; i < items.length; i++) {
-      let addon = items[i];
-
-      // Some information is not directly accessible from the extmgr
-      let isDisabled = this._getRDFProperty(addon.id, "isDisabled") == "true";
-      let appDisabled = this._getRDFProperty(addon.id, "appDisabled");
-      let appManaged = this._getRDFProperty(addon.id, "appManaged");
-      let desc = this._getRDFProperty(addon.id, "description");
-      let optionsURL = this._getRDFProperty(addon.id, "optionsURL");
-      let opType = this._getRDFProperty(addon.id, "opType");
-      let updateable = this._getRDFProperty(addon.id, "updateable");
+    let self = this;
+    AddonManager.getAddonsByTypes(["extension", "theme", "locale"], function(items) {
+      for (let i = 0; i < items.length; i++) {
+        let addon = items[i];
+        let appManaged = (addon.scope == AddonManager.SCOPE_APPLICATION);
+        let opType = self._getOpTypeForOperations(addon.pendingOperations);
+        let updateable = (addon.permissions & AddonManager.PERM_CAN_UPDATE) > 0;
 
-      let listitem = this._createItem(addon, "local");
-      listitem.setAttribute("isDisabled", isDisabled);
-      listitem.setAttribute("appDisabled", appDisabled);
-      listitem.setAttribute("appManaged", appManaged);
-      listitem.setAttribute("description", desc);
-      listitem.setAttribute("optionsURL", optionsURL);
-      listitem.setAttribute("opType", opType);
-      listitem.setAttribute("updateable", updateable);
-      this._list.insertBefore(listitem, this._repoItem);
-    }
+        let listitem = self._createItem(addon, "local");
+        listitem.setAttribute("isDisabled", !addon.isActive);
+        listitem.setAttribute("appDisabled", addon.appDisabled);
+        listitem.setAttribute("appManaged", appManaged);
+        listitem.setAttribute("description", addon.description);
+        listitem.setAttribute("optionsURL", addon.optionsURL);
+        listitem.setAttribute("opType", opType);
+        listitem.setAttribute("updateable", updateable);
+        listitem.addon = addon;
+        self._list.insertBefore(listitem, self._repoItem);
+      }
 
-    // Load the search engines
-    let defaults = this._search.getDefaultEngines({ }).map(function (e) e.name);
-    function isDefault(aEngine)
-      defaults.indexOf(aEngine.name) != -1
+      // Load the search engines
+      let defaults = self._search.getDefaultEngines({ }).map(function (e) e.name);
+      function isDefault(aEngine)
+        defaults.indexOf(aEngine.name) != -1
+
+      let strings = Elements.browserBundle;
+      let defaultDescription = strings.getString("addonsSearchEngine.description");
 
-    let strings = Elements.browserBundle;
-    let defaultDescription = strings.getString("addonsSearchEngine.description");
-
-    let engines = this._search.getEngines({ });
-    for (let e = 0; e < engines.length; e++) {
-      let engine = engines[e];
-      let addon = {};
-      addon.id = engine.name;
-      addon.type = 1024;
-      addon.name = engine.name;
-      addon.version = "";
-      addon.iconURL = engine.iconURI ? engine.iconURI.spec : "";
+      let engines = self._search.getEngines({ });
+      for (let e = 0; e < engines.length; e++) {
+        let engine = engines[e];
+        let addon = {};
+        addon.id = engine.name;
+        addon.type = "search";
+        addon.name = engine.name;
+        addon.version = "";
+        addon.iconURL = engine.iconURI ? engine.iconURI.spec : "";
 
-      let listitem = this._createItem(addon, "searchplugin");
-      listitem._engine = engine;
-      listitem.setAttribute("isDisabled", engine.hidden ? "true" : "false");
-      listitem.setAttribute("appDisabled", "false");
-      listitem.setAttribute("appManaged", isDefault(engine));
-      listitem.setAttribute("description", engine.description || defaultDescription);
-      listitem.setAttribute("optionsURL", "");
-      listitem.setAttribute("opType", engine.hidden ? "needs-disable" : "");
-      listitem.setAttribute("updateable", "false");
-      this._list.insertBefore(listitem, this._repoItem);
-    }
+        let listitem = self._createItem(addon, "searchplugin");
+        listitem._engine = engine;
+        listitem.setAttribute("isDisabled", engine.hidden ? "true" : "false");
+        listitem.setAttribute("appDisabled", "false");
+        listitem.setAttribute("appManaged", isDefault(engine));
+        listitem.setAttribute("description", engine.description || defaultDescription);
+        listitem.setAttribute("optionsURL", "");
+        listitem.setAttribute("opType", engine.hidden ? "needs-disable" : "");
+        listitem.setAttribute("updateable", "false");
+        self._list.insertBefore(listitem, self._repoItem);
+      }
 
-    if (engines.length + items.length == 0) {
-      this.displaySectionMessage("local", strings.getString("addonsLocalNone.label"), null, true);
-      document.getElementById("addons-update-all").disabled = true;
-    }
+      if (engines.length + items.length == 0) {
+        self.displaySectionMessage("local", strings.getString("addonsLocalNone.label"), null, true);
+        document.getElementById("addons-update-all").disabled = true;
+      }
+    });
   },
 
   enable: function ev_enable(aItem) {
     let opType;
-    if (aItem.getAttribute("type") == "1024") {
+    if (aItem.getAttribute("type") == "search") {
       aItem._engine.hidden = false;
       opType = "needs-enable";
     } else {
-      let id = this._getIDFromURI(aItem.id);
-      this._extmgr.enableItem(id);
-      opType = this._getRDFProperty(id, "opType");
+      aItem.addon.userDisabled = false;
+      opType = this._getOpTypeForOperations(aItem.addon.pendingOperations);
 
       if (opType == "needs-enable")
         this.showRestart();
       else
         this.hideRestart();
     }
 
     aItem.setAttribute("opType", opType);
   },
 
   disable: function ev_disable(aItem) {
     let opType;
-    if (aItem.getAttribute("type") == "1024") {
+    if (aItem.getAttribute("type") == "search") {
       aItem._engine.hidden = true;
       opType = "needs-disable";
     } else {
-      let id = this._getIDFromURI(aItem.id);
-      this._extmgr.disableItem(id);
-      opType = this._getRDFProperty(id, "opType");
+      aItem.addon.userDisabled = true;
+      opType = this._getOpTypeForOperations(aItem.addon.pendingOperations);
 
       if (opType == "needs-disable")
         this.showRestart();
       else
         this.hideRestart();
     }
 
     aItem.setAttribute("opType", opType);
   },
 
   uninstall: function ev_uninstall(aItem) {
     let opType;
-    if (aItem.getAttribute("type") == "1024") {
+    if (aItem.getAttribute("type") == "search") {
       // Make sure the engine isn't hidden before removing it, to make sure it's
       // visible if the user later re-adds it (works around bug 341833)
       aItem._engine.hidden = false;
       this._search.removeEngine(aItem._engine);
       // the search-engine-modified observer in browser.js will take care of
       // updating the list
     } else {
-      let id = this._getIDFromURI(aItem.id);
-      this._extmgr.uninstallItem(id);
-      opType = this._getRDFProperty(id, "opType");
+      aItem.addon.uninstall();
+      opType = this._getOpTypeForOperations(aItem.addon.pendingOperations);
 
       if (opType == "needs-uninstall")
         this.showRestart();
       aItem.setAttribute("opType", opType);
     }
   },
 
   cancelUninstall: function ev_cancelUninstall(aItem) {
-    let id = this._getIDFromURI(aItem.id);
-    this._extmgr.cancelUninstallItem(id);
+    aItem.addon.cancelUninstall();
 
     this.hideRestart();
 
-    let opType = this._getRDFProperty(id, "opType");
+    let opType = this._getOpTypeForOperations(aItem.addon.pendingOperations);
     aItem.setAttribute("opType", opType);
   },
 
-  _installCallback: function ev__installCallback(aItem, aStatus) {
-    if (aStatus == -210) {
-      // User cancelled
-      aItem.removeAttribute("opType");
-    }
-    else if (aStatus < 0) {
-      // Some other error
-      aItem.removeAttribute("opType");
-      let bundles = Cc["@mozilla.org/intl/stringbundle;1"].getService(Ci.nsIStringBundleService);
-      let strings = bundles.createBundle("chrome://global/locale/xpinstall/xpinstall.properties");
-
-      try {
-        var msg = strings.GetStringFromName("error" + aStatus);
-      } catch (ex) {
-        msg = strings.formatStringFromName("unknown.error", [aStatus]);
-      }
-      aItem.setAttribute("error", msg);
-    }
-    else {
-      // Success
-      aItem.setAttribute("opType", "needs-restart");
-    }
-  },
-
   installFromRepo: function ev_installFromRepo(aItem) {
-    if (!this._isXPInstallEnabled())
-      return;
-
-    if (aItem.hasAttribute("eula")) {
-      var eula = {
-        name: aSelectedItem.getAttribute("name"),
-        text: aSelectedItem.getAttribute("eula"),
-        accepted: false
-      };
-
-      // TODO: eula
-      //window.openDialog("chrome://mozapps/content/extensions/eula.xul", "_blank",
-      //                  "chrome,dialog,modal,centerscreen,resizable=no", eula);
-      //if (!eula.accepted)
-      //  return;
-    }
-
-    var details = {
-      URL: aItem.getAttribute("xpiURL"),
-      Hash: aItem.getAttribute("xpiHash"),
-      IconURL: aItem.getAttribute("iconURL"),
-      toString: function () { return this.URL; }
-    };
-
-    var params = [];
-    params[aItem.getAttribute("name")] = details;
-
-    let self = this;
-    InstallTrigger.install(params, function(aURL, aStatus) { self._installCallback(aItem, aStatus); });
+    AddonManager.getInstallForURL(aItem.getAttribute("xpiURL"),
+                                  function(aInstall) { aInstall.install(); },
+                                  "application/x-xpinstall",
+                                  aItem.getAttribute("xpiHash"));
 
     // display the progress bar early
     let opType = aItem.getAttribute("opType");
     if (!opType)
       aItem.setAttribute("opType", "needs-install");
   },
 
-  installFromXPI: function ev_installAddons(aItems, aManager) {
-    this._extmgr.addDownloads(aItems, aItems.length, aManager);
-  },
-
   _isSafeURI: function ev_isSafeURI(aURL) {
     try {
       var uri = this._ios.newURI(aURL, null, null);
       var scheme = uri.scheme;
     } catch (ex) {}
     return (uri && (scheme == "http" || scheme == "https" || scheme == "ftp"));
   },
 
@@ -589,16 +503,20 @@ var ExtensionsView = {
     var foundItem = false;
     for (let i = 0; i < aAddons.length; i++) {
       let addon = aAddons[i];
 
       // Check for any items with potentially unsafe urls
       if (urlproperties.some(function (p) !this._isSafeURI(addon[p]), this))
         continue;
 
+      // Convert the numeric type to a string
+      let types = {"2":"extension", "4":"theme", "8":"locale"};
+      addon.type = types[addon.type];
+
       let listitem = this._createItem(addon, "search");
       listitem.setAttribute("description", addon.summary);
       listitem.setAttribute("homepageURL", addon.homepageURL);
       listitem.setAttribute("xpiURL", addon.xpiURL);
       listitem.setAttribute("xpiHash", addon.xpiHash);
       if (!aIsRecommended)
         listitem.setAttribute("rating", addon.rating);
       let item = this._list.appendChild(listitem);
@@ -663,81 +581,68 @@ var ExtensionsView = {
 
   showMoreResults: function ev_showMoreResults(aItem) {
     let uri = aItem.getAttribute("url");
     if (uri)
       BrowserUI.newTab(uri);
   },
 
   updateAll: function ev_updateAll() {
-    if (!this._isXPInstallEnabled())
-      return;
- 
     let aus = Cc["@mozilla.org/browser/addon-update-service;1"].getService(Ci.nsITimerCallback);
     aus.notify(null);
  
     if (this._list.selectedItem)
       this._list.selectedItem.focus();
   },
 
   observe: function ev_observe(aSubject, aTopic, aData) {
     if (!document)
       return;
 
-    let addon = aSubject.QueryInterface(Ci.nsIUpdateItem);
+    let json = aSubject.QueryInterface(Ci.nsISupportsString).data;
+    let addon = JSON.parse(json);
+
     let strings = Elements.browserBundle;
-    let element = document.getElementById(PREFIX_ITEM_URI + addon.id);
+    let element = this.getElementForAddon(addon.id);
     if (!element)
       return;
 
     switch (aTopic) {
       case "addon-update-started":
         element.setAttribute("updateStatus", strings.getString("addonUpdate.checking"));
         break;
       case "addon-update-ended":
-        let status = parseInt(aData);
         let updateable = false;
         let statusMsg = null;
-        const nsIAUCL = Ci.nsIAddonUpdateCheckListener;
-        switch (status) {
-          case nsIAUCL.STATUS_UPDATE:
+        switch (aData) {
+          case "update":
             statusMsg = strings.getFormattedString("addonUpdate.updating", [addon.version]);
             updateable = true;
             break;
-          case nsIAUCL.STATUS_VERSIONINFO:
+          case "compatibility":
             statusMsg = strings.getString("addonUpdate.compatibility");
             break;
-          case nsIAUCL.STATUS_FAILURE:
+          case "error":
             statusMsg = strings.getString("addonUpdate.error");
             break;
-          case nsIAUCL.STATUS_DISABLED:
-            statusMsg = strings.getString("addonUpdate.disabled");
-            break;
-          case nsIAUCL.STATUS_APP_MANAGED:
-          case nsIAUCL.STATUS_NO_UPDATE:
+          case "no-update":
             // Ignore if no updated was found. Just let the message go blank.
             //statusMsg = strings.getString("addonUpdate.noupdate");
             break;
-          case nsIAUCL.STATUS_NOT_MANAGED:
-            statusMsg = strings.getString("addonUpdate.notsupported");
-            break;
-          case nsIAUCL.STATUS_READ_ONLY:
-            statusMsg = strings.getString("addonUpdate.notsupported");
-            break;
           default:
             // Ignore if no updated was found. Just let the message go blank.
             //statusMsg = strings.getString("addonUpdate.noupdate");
         }
 
         if (statusMsg)
           element.setAttribute("updateStatus", statusMsg);
         else
           element.removeAttribute("updateStatus");
 
-        // Tag the add-on so the XPInstallDownloadManager knows it's an update
+        // Tag the add-on so the AddonInstallListener knows it's an update
         if (updateable)
           element.setAttribute("updating", "true");
         break;
     }
   }
 };
 
 
@@ -777,149 +682,112 @@ var AddonSearchResults = {
     ExtensionsView.displaySearchResults(aAddons, aTotalResults, false, this.selectFirstResult);
   },
 
   searchFailed: searchFailed
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 // XPInstall download helper
-function XPInstallDownloadManager() {
+function AddonInstallListener() {
 }
 
-XPInstallDownloadManager.prototype = {
-  observe: function (aSubject, aTopic, aData) {
-    switch (aTopic) {
-      case "xpinstall-download-started":
-        var params = aSubject.QueryInterface(Components.interfaces.nsISupportsArray);
-        var paramBlock = params.GetElementAt(0).QueryInterface(Components.interfaces.nsISupportsInterfacePointer);
-        paramBlock = paramBlock.data.QueryInterface(Components.interfaces.nsIDialogParamBlock);
-        var manager = params.GetElementAt(1).QueryInterface(Components.interfaces.nsISupportsInterfacePointer);
-        manager = manager.data.QueryInterface(Components.interfaces.nsIObserver);
-        this.addDownloads(paramBlock, manager);
-        break;
-    }
-  },
-
-  addDownloads: function (aParams, aManager) {
-    let count = aParams.GetInt(1);
-    let items = [];
-    for (var i = 0; i < count;) {
-      let displayName = aParams.GetString(i++);
-      let url = aParams.GetString(i++);
-      let iconURL = aParams.GetString(i++);
-      let uri = ExtensionsView._ios.newURI(url, null, null);
-      let isTheme = uri.QueryInterface(Ci.nsIURL).fileExtension.toLowerCase() == "jar";
-      let type = isTheme ? Ci.nsIUpdateItem.TYPE_THEME : Ci.nsIUpdateItem.TYPE_EXTENSION;
-      if (!iconURL) {
-        iconURL = isTheme ? "chrome://mozapps/skin/extensions/themeGeneric.png" :
-                            "chrome://mozapps/skin/xpinstall/xpinstallItemGeneric.png";
-      }
-
-      let item = Cc["@mozilla.org/updates/item;1"].createInstance(Ci.nsIUpdateItem);
-      item.init(url, " ", "app-profile", "", "", displayName, url, "", iconURL, "", "", type, "");
-      items.push(item);
+AddonInstallListener.prototype = {
+  _updating: false,
+  onInstallEnded: function(aInstall, aAddon) {
+    // XXX fix updating stuff
+    if (aAddon.pendingOperations & AddonManager.PENDING_INSTALL)
+      ExtensionsView.showRestart(this._updating ? "update" : "normal");
 
-      // Advance the enumerator
-      let certName = aParams.GetString(i++);
-    }
-
-    this._failed = [];
-    this._succeeded = [];
-    this._updating = false;
-
-    ExtensionsView.installFromXPI(items, aManager);
-
-    if (ExtensionsView.visible)
-      return;
-
-    let strings = Elements.browserBundle;
-    let alerts = Cc["@mozilla.org/alerts-service;1"].getService(Ci.nsIAlertsService);
-    alerts.showAlertNotification(URI_GENERIC_ICON_XPINSTALL, strings.getString("alertAddons"),
-                                 strings.getString("alertAddonsInstalling"), false, "", null);
-  },
-
-  /////////////////////////////////////////////////////////////////////////////
-  // nsIAddonInstallListener
-  onDownloadStarted: function(aAddon) { },
-  onDownloadEnded: function(aAddon) { },
-  onInstallStarted: function(aAddon) { },
-  onCompatibilityCheckStarted: function(aAddon) { },
-  onCompatibilityCheckEnded: function(aAddon, aStatus) { },
-
-  _failed: [],
-  _succeeded: [],
-  _updating: false,
-  onInstallEnded: function(aAddon, aStatus) {
-    // Track success/failure for each addon
-    if (Components.isSuccessCode(aStatus))
-      this._succeeded.push(aAddon.id);
-    else
-      this._failed.push(aAddon.id);
+    this._showAlert(true);
 
     if (!ExtensionsView.visible)
       return;
 
-    var element = ExtensionsView.getElementForAddon(aAddon.id);
+    let element = ExtensionsView.getElementForAddon(aInstall.sourceURL);
     if (!element)
       return;
 
-    element.setAttribute("status", (Components.isSuccessCode(aStatus) ? "success" : "fail"));
+    element.setAttribute("opType", "needs-restart");
+    element.setAttribute("status", "success");
 
     // If we are updating an add-on, change the status
     if (element.hasAttribute("updating")) {
       let strings = Elements.browserBundle;
       element.setAttribute("updateStatus", strings.getFormattedString("addonUpdate.updated", [aAddon.version]));
       element.removeAttribute("updating");
 
       // Remember that we are updating so we can customize the restart message
       this._updating = true;
     }
   },
 
-  onInstallsCompleted: function() {
-    let strings = Elements.browserBundle;
+  onInstallFailed: function(aInstall, aError) {
+    this._showAlert(false);
+
+    if (ExtensionsView.visible) {
+      let element = ExtensionsView.getElementForAddon(aInstall.sourceURL);
+      if (!element)
+        return;
+  
+      element.removeAttribute("opType");
+      let bundles = Cc["@mozilla.org/intl/stringbundle;1"].getService(Ci.nsIStringBundleService);
+      let strings = bundles.createBundle("chrome://global/locale/xpinstall/xpinstall.properties");
+
+      let error = null;
+      switch (aError) {
+      case AddonManager.ERROR_NETWORK_FAILURE:
+        error = "error-228";
+        break;
+      case AddonManager.ERROR_INCORRECT_HASH:
+        error = "error-261";
+        break;
+      case AddonManager.ERROR_CORRUPT_FILE:
+        error = "error-207";
+        break;
+      }
 
-    // If even one add-on succeeded, display the restart notif
-    if (this._succeeded.length > 0)
-      ExtensionsView.showRestart(this._updating ? "update" : "normal");
+      try {
+        var msg = strings.GetStringFromName(error);
+      } catch (ex) {
+        msg = strings.formatStringFromName("unknown.error", [aError]);
+      }
+      element.setAttribute("error", msg);
+    }
+  },
+
+  onDownloadProgress: function xpidm_onDownloadProgress(aInstall) {
+    var element = ExtensionsView.getElementForAddon(aInstall.sourceURL);
+    if (!element)
+      return;
 
+    let opType = element.getAttribute("opType");
+    if (!opType)
+      element.setAttribute("opType", "needs-install");
+
+    let progress = Math.round((aInstall.progress / aInstall.maxProgress) * 100);
+    element.setAttribute("progress", progress);
+  },
+
+  onDownloadFailed: function(aInstall, aError) {
+    this.onInstallFailed(aInstall, aError);
+  },
+
+  _showAlert: function xpidm_showAlert(aSucceeded) {
     if (ExtensionsView.visible)
       return;
 
-    let message = strings.getString("alertAddonsInstalled");
-    if (this._succeeded.length == 0 && this._failed.length > 0)
-      message = strings.getString("alertAddonsFail");
+    let strings = Elements.browserBundle;
+    let message = aSucceeded ? strings.getString("alertAddonsInstalled") :
+                               strings.getString("alertAddonsFail");
 
     let observer = {
       observe: function (aSubject, aTopic, aData) {
         if (aTopic == "alertclickcallback")
           BrowserUI.showPanel("addons-container");
       }
     };
 
     let alerts = Cc["@mozilla.org/alerts-service;1"].getService(Ci.nsIAlertsService);
     alerts.showAlertNotification(URI_GENERIC_ICON_XPINSTALL, strings.getString("alertAddons"),
                                  message, true, "", observer);
-  },
-
-  onDownloadProgress: function xpidm_onDownloadProgress(aAddon, aValue, aMaxValue) {
-    var element = ExtensionsView.getElementForAddon(aAddon.id);
-    if (!element)
-      return;
-
-    let opType = element.getAttribute("opType");
-    if (!opType) {
-      element.setAttribute("opType", "needs-install");
-    }
-    var progress = Math.round((aValue / aMaxValue) * 100);
-    element.setAttribute("progress", progress);
-  },
-
-  /////////////////////////////////////////////////////////////////////////////
-  // nsISupports
-  QueryInterface: function(aIID) {
-    if (!aIID.equals(Ci.nsIAddonInstallListener) &&
-        !aIID.equals(Ci.nsISupports))
-      throw Components.results.NS_ERROR_NO_INTERFACE;
-    return this;
   }
 };
--- a/mobile/components/AddonUpdateService.js
+++ b/mobile/components/AddonUpdateService.js
@@ -38,19 +38,20 @@ const Cc = Components.classes;
 const Ci = Components.interfaces;
 
 Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
 
 XPCOMUtils.defineLazyServiceGetter(this, "gObs",
                                    "@mozilla.org/observer-service;1",
                                    "nsIObserverService");
 
-XPCOMUtils.defineLazyServiceGetter(this, "gExtMgr",
-                                   "@mozilla.org/extensions/manager;1",
-                                   "nsIExtensionManager");
+XPCOMUtils.defineLazyGetter(this, "AddonManager", function() {
+  Components.utils.import("resource://gre/modules/AddonManager.jsm");
+  return AddonManager;
+});
 
 XPCOMUtils.defineLazyServiceGetter(this, "gIO",
                                    "@mozilla.org/network/io-service;1",
                                    "nsIIOService");
 
 XPCOMUtils.defineLazyServiceGetter(this, "gPref",
                                    "@mozilla.org/preferences-service;1",
                                    "nsIPrefBranch2");
@@ -91,70 +92,67 @@ AddonUpdateService.prototype = {
       return;
 
     // If we already auto-upgraded and installed new versions, ignore this check
     if (gNeedsRestart)
       return;
 
     gIO.offline = false;
 
-    // Extension Manager will check for empty list and auto-check all add-ons
-    let items = [];
-    let listener = new UpdateCheckListener();
-    gExtMgr.update(items, items.length, Ci.nsIExtensionManager.UPDATE_CHECK_NEWVERSION, listener);
+    AddonManager.getAddonsByTypes(null, function(aAddonList) {
+      aAddonList.forEach(function(aAddon) {
+        if (aAddon.permissions & AddonManager.PERM_CAN_UPGRADE) {
+          let data = Cc["@mozilla.org/supports-string;1"].createInstance(Ci.nsISupportsString);
+          data.data = JSON.stringify({ id: aAddon.id, name: aAddon.name });
+          gObs.notifyObservers(data, "addon-update-started", null);
+
+          let listener = new UpdateCheckListener();
+          aAddon.findUpdates(listener, AddonManager.UPDATE_WHEN_USER_REQUESTED);
+        }
+      });
+    });
   }
 };
 
 // -----------------------------------------------------------------------
 // Add-on update listener. Starts a download for any add-on with a viable
 // update waiting
 // -----------------------------------------------------------------------
 
 function UpdateCheckListener() {
-  this._addons = [];
+  this._status = null;
+  this._version = null;
 }
 
 UpdateCheckListener.prototype = {
-  /////////////////////////////////////////////////////////////////////////////
-  // nsIAddonUpdateCheckListener
-  onUpdateStarted: function ucl_onUpdateStarted() {
+  onCompatibilityUpdateAvailable: function(aAddon) {
+    this._status = "compatibility";
+  },
+
+  onUpdateAvailable: function(aAddon, aInstall) {
+    this._status = "update";
+    this._version = aInstall.version;
+    aInstall.install();
   },
 
-  onUpdateEnded: function ucl_onUpdateEnded() {
-    if (!this._addons.length)
-      return;
-
-    // If we have some updateable add-ons, let's download them
-    let items = [];
-    for (let i = 0; i < this._addons.length; i++)
-      items.push(gExtMgr.getItemForID(this._addons[i]));
-
-    // Start the actual downloads
-    gExtMgr.addDownloads(items, items.length, null);
-
-    // Remember that we downloaded new updates so we don't check again
-    gNeedsRestart = true;
+  onNoUpdateAvailable: function(aAddon) {
+    if (!this._status)
+      this._status = "no-update";
   },
 
-  onAddonUpdateStarted: function ucl_onAddonUpdateStarted(aAddon) {
-    gObs.notifyObservers(aAddon, "addon-update-started", null);
-  },
+  onUpdateFinished: function(aAddon, aError) {
+    let data = Cc["@mozilla.org/supports-string;1"].createInstance(Ci.nsISupportsString);
+    if (this._version)
+      data.data = JSON.stringify({ id: aAddon.id, name: aAddon.name, version: this._version });
+    else
+      data.data = JSON.stringify({ id: aAddon.id, name: aAddon.name });
 
-  onAddonUpdateEnded: function ucl_onAddonUpdateEnded(aAddon, aStatus) {
-    gObs.notifyObservers(aAddon, "addon-update-ended", aStatus);
-    
-    // Save the add-on id if we can download an update
-    if (aStatus == Ci.nsIAddonUpdateCheckListener.STATUS_UPDATE)
-      this._addons.push(aAddon.id);
-  },
+    if (aError)
+      this._status = "error";
 
-  QueryInterface: function ucl_QueryInterface(aIID) {
-    if (!aIID.equals(Ci.nsIAddonUpdateCheckListener) &&
-        !aIID.equals(Ci.nsISupports))
-      throw Components.results.NS_ERROR_NO_INTERFACE;
-    return this;
+    gObs.notifyObservers(data, "addon-update-ended", this._status);
   }
 };
 
 function NSGetModule(aCompMgr, aFileSpec) {
   return XPCOMUtils.generateModule([AddonUpdateService]);
 }
 
--- a/mobile/components/XPIDialogService.js
+++ b/mobile/components/XPIDialogService.js
@@ -35,72 +35,51 @@
  * ***** END LICENSE BLOCK ***** */
 
 const Cc = Components.classes;
 const Ci = Components.interfaces;
 
 Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
 
 // -----------------------------------------------------------------------
-// XPInstall Dialog Service
+// Web Install Prompt service
 // -----------------------------------------------------------------------
 
-function XPInstallDialogService() { }
+function WebInstallPrompt() { }
 
-XPInstallDialogService.prototype = {
+WebInstallPrompt.prototype = {
   classDescription: "XPInstall Dialog Service",
-  contractID: "@mozilla.org/embedui/xpinstall-dialog-service;1",
+  contractID: "@mozilla.org/addons/web-install-confirm;1",
   classID: Components.ID("{c1242012-27d8-477e-a0f1-0b098ffc329b}"),
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIXPIDialogService, Ci.nsIXPIProgressDialog]),
+  QueryInterface: XPCOMUtils.generateQI([Ci.amIWebInstallPrompt]),
 
-  confirmInstall: function(aParent, aPackages, aCount) {
+  confirm: function(aWindow, aURL, aInstalls) {
     // first check if the extensions panel is open : fast path to return true
     let wm = Cc["@mozilla.org/appshell/window-mediator;1"].getService(Ci.nsIWindowMediator);
     let browser = wm.getMostRecentWindow("navigator:browser");
-    if (browser.ExtensionsView.visible)
-      return true;
+    if (browser.ExtensionsView.visible) {
+      aInstalls.forEach(function(install) {
+        install.install();
+      });
+      return;
+    }
     
     let bundleService = Cc["@mozilla.org/intl/stringbundle;1"].getService(Ci.nsIStringBundleService);
     let bundle = bundleService.createBundle("chrome://browser/locale/browser.properties");
     let prompt = Cc["@mozilla.org/embedcomp/prompt-service;1"].getService(Ci.nsIPromptService);
 
     let flags = prompt.BUTTON_POS_0 * prompt.BUTTON_TITLE_IS_STRING + prompt.BUTTON_POS_1 * prompt.BUTTON_TITLE_CANCEL;
     let title = bundle.GetStringFromName("addonsConfirmInstall.title");
     let button = bundle.GetStringFromName("addonsConfirmInstall.install");
 
-    return prompt.confirmEx(null, title, aPackages[0], flags, button, null, null, null, {value: false}) == 0;
-  },
-
-  openProgressDialog: function(aPackages, aCount, aManager) {
-    // Create a param block with the packages
-    let dpb = Cc["@mozilla.org/embedcomp/dialogparam;1"].createInstance(Ci.nsIDialogParamBlock);
-    dpb.SetInt(0, 2);                       // OK and Cancel buttons
-    dpb.SetInt(1, aPackages.length);        // Number of strings
-    dpb.SetNumberStrings(aPackages.length); // Add strings
-    for (let i = 0; i < aPackages.length; ++i)
-      dpb.SetString(i, aPackages[i]);
-
-    let dpbWrap = Cc["@mozilla.org/supports-interface-pointer;1"].createInstance(Ci.nsISupportsInterfacePointer);
-    dpbWrap.data = dpb;
-    dpbWrap.dataIID = Ci.nsIDialogParamBlock;
-
-    let obsWrap = Cc["@mozilla.org/supports-interface-pointer;1"].createInstance(Ci.nsISupportsInterfacePointer);
-    obsWrap.data = aManager;
-    obsWrap.dataIID = Ci.nsIObserver;
-
-    let params = Cc["@mozilla.org/supports-array;1"].createInstance(Ci.nsISupportsArray);
-    params.AppendElement(dpbWrap);
-    params.AppendElement(obsWrap);
-
-    let os = Cc["@mozilla.org/observer-service;1"].getService(Ci.nsIObserverService);
-    os.notifyObservers(params, "xpinstall-download-started", null);
-
-    // Give the nsXPInstallManager a progress dialog
-    aManager.observe(this, "xpinstall-progress", "open");
-  },
-
-  onStateChange: function(aIndex, aState, aError) { },
-  onProgress: function(aIndex, aValue, aMax) { }
+    aInstalls.forEach(function(install) {
+      let result = (prompt.confirmEx(aWindow, title, install.name, flags, button, null, null, null, {value: false}) == 0);
+      if (result)
+        install.install();
+      else
+        install.cancel();
+    });
+  }
 };
 
 function NSGetModule(aCompMgr, aFileSpec) {
-  return XPCOMUtils.generateModule([XPInstallDialogService]);
+  return XPCOMUtils.generateModule([WebInstallPrompt]);
 }
--- a/mobile/themes/hildon/browser.css
+++ b/mobile/themes/hildon/browser.css
@@ -386,16 +386,20 @@ toolbarbutton.page-button {
 
 @media (max-width: 499px) {
   #addons-repo {
     -moz-box-orient: vertical;
     -moz-box-pack: center;
   }
 }
 
+.addon-image {
+  list-style-image: url("chrome://mozapps/skin/xpinstall/xpinstallItemGeneric.png");  
+}
+
 .addon-rating[rating] {
   width: 78px;
   height: 18px;
   list-style-image: url("chrome://browser/skin/images/ratings-18.png");
 }
 
 .addon-rating[rating="0"] {
   -moz-image-region: rect(0px 78px 18px 0px);