Bug 899322 - Convert the mozApps API to use webidl r=marco,bholley
authorFabrice Desré <fabrice@mozilla.com>
Tue, 19 Aug 2014 09:30:54 -0700
changeset 200335 de62aa662be452e17a2a005fb84413e22d635676
parent 200334 c12cd52746f0c61731b46aa42ebd220171851129
child 200336 0a827d3c63ebe22c9b0ba1f89e6e7e0ca2ca85da
push id27340
push userryanvm@gmail.com
push dateTue, 19 Aug 2014 19:54:03 +0000
treeherdermozilla-central@f49acde26893 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmarco, bholley
bugs899322
milestone34.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 899322 - Convert the mozApps API to use webidl r=marco,bholley
content/base/src/nsFrameLoader.cpp
dom/apps/src/AppsServiceChild.jsm
dom/apps/src/Webapps.js
dom/apps/src/Webapps.manifest
dom/apps/tests/test_install_receipts.html
dom/apps/tests/test_receipt_operations.html
dom/bindings/Bindings.conf
dom/interfaces/apps/moz.build
dom/interfaces/apps/nsIAppsService.idl
dom/interfaces/apps/nsIDOMApplicationRegistry.idl
dom/permission/tests/test_webapps-manage.html
dom/tests/mochitest/general/test_interfaces.html
dom/tests/mochitest/webapps/test_install_errors.xul
dom/tests/mochitest/webapps/test_list_api.xul
dom/webidl/Apps.webidl
dom/webidl/MozApplicationEvent.webidl
dom/webidl/moz.build
--- a/content/base/src/nsFrameLoader.cpp
+++ b/content/base/src/nsFrameLoader.cpp
@@ -25,17 +25,16 @@
 #include "nsIDOMDocument.h"
 #include "nsIDOMFile.h"
 #include "nsPIDOMWindow.h"
 #include "nsIWebNavigation.h"
 #include "nsIWebProgress.h"
 #include "nsIDocShell.h"
 #include "nsIDocShellTreeOwner.h"
 #include "nsIDocShellLoadInfo.h"
-#include "nsIDOMApplicationRegistry.h"
 #include "nsIBaseWindow.h"
 #include "nsContentUtils.h"
 #include "nsIXPConnect.h"
 #include "nsUnicharUtils.h"
 #include "nsIScriptGlobalObject.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsIScrollable.h"
 #include "nsFrameLoader.h"
--- a/dom/apps/src/AppsServiceChild.jsm
+++ b/dom/apps/src/AppsServiceChild.jsm
@@ -244,17 +244,21 @@ this.DOMApplicationRegistry = {
     // Each DOM app contains a proxy object used to build their state. We
     // return the handler for this proxy object with traps to get and set
     // app properties kept in the DOMApplicationRegistry app cache.
     return {
       get: function(target, prop) {
         if (!DOMApplicationRegistry.webapps[aId]) {
           return;
         }
-        return DOMApplicationRegistry.webapps[aId][prop];
+
+        if (prop in DOMApplicationRegistry.webapps[aId]) {
+          return DOMApplicationRegistry.webapps[aId][prop];
+        }
+        return null;
       },
       set: function(target, prop, val) {
         if (!DOMApplicationRegistry.webapps[aId]) {
           return;
         }
         DOMApplicationRegistry.webapps[aId][prop] = val;
         return;
       },
--- a/dom/apps/src/Webapps.js
+++ b/dom/apps/src/Webapps.js
@@ -13,30 +13,26 @@ Cu.import("resource://gre/modules/DOMReq
 Cu.import("resource://gre/modules/AppsUtils.jsm");
 Cu.import("resource://gre/modules/BrowserElementPromptService.jsm");
 Cu.import("resource://gre/modules/AppsServiceChild.jsm");
 
 XPCOMUtils.defineLazyServiceGetter(this, "cpmm",
                                    "@mozilla.org/childprocessmessagemanager;1",
                                    "nsIMessageSender");
 
+function debug(aMsg) {
+  dump("-*- Webapps.js " + aMsg + "\n");
+}
+
 function convertAppsArray(aApps, aWindow) {
   let apps = new aWindow.Array();
-  for (let i = 0; i < aApps.length; i++) {
-    let app = aApps[i];
-    // Our application objects are JS-implemented XPCOM objects with DOM_OBJECT
-    // set in classinfo. These objects are reflector-per-scope, so as soon as we
-    // pass them to content, we'll end up with a new object in content. But from
-    // this code, they _appear_ to be chrome objects, and so the Array Xray code
-    // vetos the attempt to define a chrome-privileged object on a content Array.
-    // Very carefully waive Xrays so that this can keep working until we convert
-    // mozApps to WebIDL in bug 899322.
-    Cu.waiveXrays(apps)[i] = createApplicationObject(aWindow, app);
-  }
-
+  aApps.forEach((aApp) => {
+    let obj = createContentApplicationObject(aWindow, aApp);
+    apps.push(obj);
+  });
   return apps;
 }
 
 function WebappsRegistry() {
 }
 
 WebappsRegistry.prototype = {
   __proto__: DOMRequestIpcHelper.prototype,
@@ -47,29 +43,29 @@ WebappsRegistry.prototype = {
       return
     let req = this.getRequest(msg.requestID);
     if (!req)
       return;
     let app = msg.app;
     switch (aMessage.name) {
       case "Webapps:Install:Return:OK":
         this.removeMessageListeners("Webapps:Install:Return:KO");
-        Services.DOMRequest.fireSuccess(req, createApplicationObject(this._window, app));
+        Services.DOMRequest.fireSuccess(req, createContentApplicationObject(this._window, app));
         cpmm.sendAsyncMessage("Webapps:Install:Return:Ack",
                               { manifestURL : app.manifestURL });
         break;
       case "Webapps:Install:Return:KO":
         this.removeMessageListeners(aMessage.name);
         Services.DOMRequest.fireError(req, msg.error || "DENIED");
         break;
       case "Webapps:GetSelf:Return:OK":
         this.removeMessageListeners(aMessage.name);
         if (msg.apps.length) {
           app = msg.apps[0];
-          Services.DOMRequest.fireSuccess(req, createApplicationObject(this._window, app));
+          Services.DOMRequest.fireSuccess(req, createContentApplicationObject(this._window, app));
         } else {
           Services.DOMRequest.fireSuccess(req, null);
         }
         break;
       case "Webapps:CheckInstalled:Return:OK":
         this.removeMessageListeners(aMessage.name);
         Services.DOMRequest.fireSuccess(req, msg.app);
         break;
@@ -210,18 +206,24 @@ WebappsRegistry.prototype = {
     return request;
   },
 
   get mgmt() {
     if (!this.hasMgmtPrivilege) {
       return null;
     }
 
-    if (!this._mgmt)
-      this._mgmt = new WebappsApplicationMgmt(this._window);
+    if (!this._mgmt) {
+      let mgmt = Cc["@mozilla.org/webapps/manager;1"]
+                   .createInstance(Ci.nsISupports);
+      mgmt.wrappedJSObject.init(this._window);
+      this._mgmt = mgmt.__DOM_IMPL__
+        ? mgmt.__DOM_IMPL__
+        : this._window.DOMApplicationsManager._create(this._window, mgmt.wrappedJSObject);
+    }
     return this._mgmt;
   },
 
   uninit: function() {
     this._mgmt = null;
     cpmm.sendAsyncMessage("Webapps:UnregisterForMessages",
                           ["Webapps:Install:Return:OK"]);
   },
@@ -257,61 +259,52 @@ WebappsRegistry.prototype = {
     // Only pages with the webapps-manage permission set can get access to
     // the mgmt object.
     this.hasMgmtPrivilege = perm == Ci.nsIPermissionManager.ALLOW_ACTION;
   },
 
   classID: Components.ID("{fff440b3-fae2-45c1-bf03-3b5a2e432270}"),
 
   QueryInterface: XPCOMUtils.generateQI([Ci.nsISupportsWeakReference,
+                                         Ci.nsISupports,
                                          Ci.nsIObserver,
-                                         Ci.mozIDOMApplicationRegistry,
-                                         Ci.mozIDOMApplicationRegistry2,
-                                         Ci.nsIDOMGlobalPropertyInitializer]),
-
-  classInfo: XPCOMUtils.generateCI({classID: Components.ID("{fff440b3-fae2-45c1-bf03-3b5a2e432270}"),
-                                    contractID: "@mozilla.org/webapps;1",
-                                    interfaces: [Ci.mozIDOMApplicationRegistry,
-                                                 Ci.mozIDOMApplicationRegistry2],
-                                    flags: Ci.nsIClassInfo.DOM_OBJECT,
-                                    classDescription: "Webapps Registry"})
+                                         Ci.nsIDOMGlobalPropertyInitializer])
 }
 
 /**
-  * mozIDOMApplication object
+  * DOMApplication object
   */
 
 function createApplicationObject(aWindow, aApp) {
   let app = Cc["@mozilla.org/webapps/application;1"]
-              .createInstance(Ci.mozIDOMApplication);
+              .createInstance(Ci.nsISupports);
   app.wrappedJSObject.init(aWindow, aApp);
   return app;
 }
 
+function createContentApplicationObject(aWindow, aApp) {
+  return createApplicationObject(aWindow, aApp).wrappedJSObject
+         ._prepareForContent();
+}
+
 function WebappsApplication() {
   this.wrappedJSObject = this;
 }
 
 WebappsApplication.prototype = {
   __proto__: DOMRequestIpcHelper.prototype,
 
   init: function(aWindow, aApp) {
     let proxyHandler = DOMApplicationRegistry.addDOMApp(this,
                                                         aApp.manifestURL,
                                                         aApp.id);
     this._proxy = new Proxy(this, proxyHandler);
 
     this._window = aWindow;
 
-    this._onprogress = null;
-    this._ondownloadsuccess = null;
-    this._ondownloaderror = null;
-    this._ondownloadavailable = null;
-    this._ondownloadapplied = null;
-
     this.initDOMRequestHelper(aWindow);
   },
 
   get _appStatus() {
     return this._proxy.appStatus;
   },
 
   get downloadAvailable() {
@@ -353,24 +346,16 @@ WebappsApplication.prototype = {
   get progress() {
     return this._proxy.progress;
   },
 
   get readyToApplyDownload() {
     return this._proxy.readyToApplyDownload;
   },
 
-  get receipts() {
-    return this._proxy.receipts;
-  },
-
-  set receipts(aReceipts) {
-    this._proxy.receipts = aReceipts;
-  },
-
   get removable() {
     return this._proxy.removable;
   },
 
   get updateTime() {
     return this._proxy.updateTime;
   },
 
@@ -382,53 +367,57 @@ WebappsApplication.prototype = {
   },
 
   get updateManifest() {
     return this._proxy.updateManifest ?
       Cu.cloneInto(this._proxy.updateManifest, this._window) : null;
   },
 
   set onprogress(aCallback) {
-    this._onprogress = aCallback;
+    this.__DOM_IMPL__.setEventHandler("onprogress", aCallback);
   },
 
   get onprogress() {
-    return this._onprogress;
+    return this.__DOM_IMPL__.getEventHandler("onprogress");
   },
 
   set ondownloadsuccess(aCallback) {
-    this._ondownloadsuccess = aCallback;
+    this.__DOM_IMPL__.setEventHandler("ondownloadsuccess", aCallback);
   },
 
   get ondownloadsuccess() {
-    return this._ondownloadsuccess;
+    return this.__DOM_IMPL__.getEventHandler("ondownloadsuccess");
   },
 
   set ondownloaderror(aCallback) {
-    this._ondownloaderror = aCallback;
+    this.__DOM_IMPL__.setEventHandler("ondownloaderror", aCallback);
   },
 
   get ondownloaderror() {
-    return this._ondownloaderror;
+    return this.__DOM_IMPL__.getEventHandler("ondownloaderror");
   },
 
   set ondownloadavailable(aCallback) {
-    this._ondownloadavailable = aCallback;
+    this.__DOM_IMPL__.setEventHandler("ondownloadavailable", aCallback);
   },
 
   get ondownloadavailable() {
-    return this._ondownloadavailable;
+    return this.__DOM_IMPL__.getEventHandler("ondownloadavailable");
   },
 
   set ondownloadapplied(aCallback) {
-    this._ondownloadapplied = aCallback;
+    this.__DOM_IMPL__.setEventHandler("ondownloadapplied", aCallback);
   },
 
   get ondownloadapplied() {
-    return this._ondownloadapplied;
+    return this.__DOM_IMPL__.getEventHandler("ondownloadapplied");
+  },
+
+  get receipts() {
+    return this._proxy.receipts;
   },
 
   get downloadError() {
     // Only return DOMError when we have an error.
     if (!this._proxy.downloadError) {
       return null;
     }
     return new this._window.DOMError(this._proxy.downloadError);
@@ -553,33 +542,33 @@ WebappsApplication.prototype = {
                                                       newReceipt: newReceipt,
                                                       oldReceipt: oldReceipt,
                                                       oid: this._id,
                                                       requestID: this.getRequestId(request) });
 
     return request;
   },
 
+  _prepareForContent: function() {
+    if (this.__DOM_IMPL__) {
+      return this.__DOM_IMPL__;
+    }
+    return this._window.DOMApplication._create(this._window, this.wrappedJSObject);
+  },
+
   uninit: function() {
-    this._onprogress = null;
     WrappedManifestCache.evict(this.manifestURL, this.innerWindowID);
   },
 
   _fireEvent: function(aName) {
-    let handler = this["_on" + aName];
-    if (handler) {
-      let event = new this._window.MozApplicationEvent(aName, {
-        application: this
-      });
-      try {
-        handler.handleEvent(event);
-      } catch (ex) {
-        dump("Event handler expection " + ex + "\n");
-      }
-    }
+    let obj = this._prepareForContent();
+    let event = new this._window.MozApplicationEvent(aName, {
+      application: obj
+    });
+    obj.dispatchEvent(event);
   },
 
   _fireRequestResult: function(aMessage, aIsError) {
     let req;
     let msg = aMessage.data;
     req = this.takeRequest(msg.requestID);
     if (!req) {
       return;
@@ -644,97 +633,82 @@ WebappsApplication.prototype = {
                                                    aConnection.subAppManifestURL);
           connections.push(connection);
         });
         req.resolve(connections);
         break;
       case "Webapps:AddReceipt:Return:OK":
         this.removeMessageListeners(["Webapps:AddReceipt:Return:OK",
                                      "Webapps:AddReceipt:Return:KO"]);
-        this.receipts = msg.receipts;
+        this._proxy.receipts = msg.receipts;
         Services.DOMRequest.fireSuccess(req, null);
         break;
       case "Webapps:AddReceipt:Return:KO":
         this.removeMessageListeners(["Webapps:AddReceipt:Return:OK",
                                      "Webapps:AddReceipt:Return:KO"]);
         Services.DOMRequest.fireError(req, msg.error);
         break;
       case "Webapps:RemoveReceipt:Return:OK":
         this.removeMessageListeners(["Webapps:RemoveReceipt:Return:OK",
                                      "Webapps:RemoveReceipt:Return:KO"]);
-        this.receipts = msg.receipts;
+        this._proxy.receipts = msg.receipts;
         Services.DOMRequest.fireSuccess(req, null);
         break;
       case "Webapps:RemoveReceipt:Return:KO":
         this.removeMessageListeners(["Webapps:RemoveReceipt:Return:OK",
                                      "Webapps:RemoveReceipt:Return:KO"]);
         Services.DOMRequest.fireError(req, msg.error);
         break;
       case "Webapps:ReplaceReceipt:Return:OK":
         this.removeMessageListeners(["Webapps:ReplaceReceipt:Return:OK",
                                      "Webapps:ReplaceReceipt:Return:KO"]);
-        this.receipts = msg.receipts;
+        this._proxy.receipts = msg.receipts;
         Services.DOMRequest.fireSuccess(req, null);
         break;
       case "Webapps:ReplaceReceipt:Return:KO":
         this.removeMessageListeners(["Webapps:ReplaceReceipt:Return:OK",
                                      "Webapps:ReplaceReceipt:Return:KO"]);
         Services.DOMRequest.fireError(req, msg.error);
         break;
     }
   },
 
   classID: Components.ID("{723ed303-7757-4fb0-b261-4f78b1f6bd22}"),
 
-  QueryInterface: XPCOMUtils.generateQI([Ci.mozIDOMApplication,
-                                         Ci.nsISupportsWeakReference,
-                                         Ci.nsIObserver]),
-
-  classInfo: XPCOMUtils.generateCI({classID: Components.ID("{723ed303-7757-4fb0-b261-4f78b1f6bd22}"),
-                                    contractID: "@mozilla.org/webapps/application;1",
-                                    interfaces: [Ci.mozIDOMApplication],
-                                    flags: Ci.nsIClassInfo.DOM_OBJECT,
-                                    classDescription: "Webapps Application"})
+  QueryInterface: XPCOMUtils.generateQI([Ci.nsISupports,
+                                         Ci.nsIObserver,
+                                         Ci.nsISupportsWeakReference])
 }
 
 /**
-  * mozIDOMApplicationMgmt object
+  * DOMApplicationsManager object
   */
-function WebappsApplicationMgmt(aWindow) {
-  this.initDOMRequestHelper(aWindow, ["Webapps:Uninstall:Return:OK",
-                                      "Webapps:Uninstall:Broadcast:Return:OK",
-                                      "Webapps:Uninstall:Return:KO",
-                                      "Webapps:Install:Return:OK",
-                                      "Webapps:GetNotInstalled:Return:OK"]);
-
-  cpmm.sendAsyncMessage("Webapps:RegisterForMessages",
-                        {
-                          messages: ["Webapps:Install:Return:OK",
-                                     "Webapps:Uninstall:Return:OK",
-                                     "Webapps:Uninstall:Broadcast:Return:OK"]
-                        }
-                       );
-
-  this._oninstall = null;
-  this._onuninstall = null;
+function WebappsApplicationMgmt() {
+  this.wrappedJSObject = this;
 }
 
 WebappsApplicationMgmt.prototype = {
   __proto__: DOMRequestIpcHelper.prototype,
-  __exposedProps__: {
-                      applyDownload: "r",
-                      getAll: "r",
-                      getNotInstalled: "r",
-                      oninstall: "rw",
-                      onuninstall: "rw"
-                     },
+
+  init: function(aWindow) {
+    this.initDOMRequestHelper(aWindow, ["Webapps:Uninstall:Return:OK",
+                                        "Webapps:Uninstall:Broadcast:Return:OK",
+                                        "Webapps:Uninstall:Return:KO",
+                                        "Webapps:Install:Return:OK",
+                                        "Webapps:GetNotInstalled:Return:OK"]);
+    cpmm.sendAsyncMessage("Webapps:RegisterForMessages",
+                          {
+                            messages: ["Webapps:Install:Return:OK",
+                                       "Webapps:Uninstall:Return:OK",
+                                       "Webapps:Uninstall:Broadcast:Return:OK"]
+                          }
+                         );
+  },
 
   uninit: function() {
-    this._oninstall = null;
-    this._onuninstall = null;
     cpmm.sendAsyncMessage("Webapps:UnregisterForMessages",
                           ["Webapps:Install:Return:OK",
                            "Webapps:Uninstall:Return:OK",
                            "Webapps:Uninstall:Broadcast:Return:OK"]);
   },
 
   applyDownload: function(aApp) {
     if (!aApp.readyToApplyDownload) {
@@ -768,29 +742,29 @@ WebappsApplicationMgmt.prototype = {
   getNotInstalled: function() {
     let request = this.createRequest();
     cpmm.sendAsyncMessage("Webapps:GetNotInstalled", { oid: this._id,
                                                        requestID: this.getRequestId(request) });
     return request;
   },
 
   get oninstall() {
-    return this._oninstall;
+    return this.__DOM_IMPL__.getEventHandler("oninstall");
   },
 
   get onuninstall() {
-    return this._onuninstall;
+    return this.__DOM_IMPL__.getEventHandler("onuninstall");
   },
 
   set oninstall(aCallback) {
-    this._oninstall = aCallback;
+    this.__DOM_IMPL__.setEventHandler("oninstall", aCallback);
   },
 
   set onuninstall(aCallback) {
-    this._onuninstall = aCallback;
+    this.__DOM_IMPL__.setEventHandler("onuninstall", aCallback);
   },
 
   receiveMessage: function(aMessage) {
     var msg = aMessage.json;
     let req = this.getRequest(msg.requestID);
     // We want Webapps:Install:Return:OK and Webapps:Uninstall:Broadcast:Return:OK
     // to be broadcasted to all instances of mozApps.mgmt.
     if (!((msg.oid == this._id && req) ||
@@ -798,49 +772,49 @@ WebappsApplicationMgmt.prototype = {
           aMessage.name == "Webapps:Uninstall:Broadcast:Return:OK")) {
       return;
     }
     switch (aMessage.name) {
       case "Webapps:GetNotInstalled:Return:OK":
         Services.DOMRequest.fireSuccess(req, convertAppsArray(msg.apps, this._window));
         break;
       case "Webapps:Install:Return:OK":
-        if (this._oninstall) {
-          let app = msg.app;
-          let event = new this._window.MozApplicationEvent("applicationinstall",
-                           { application : createApplicationObject(this._window, app) });
-          this._oninstall.handleEvent(event);
+        {
+          let app = createContentApplicationObject(this._window, msg.app);
+          let event =
+            new this._window.MozApplicationEvent("install", { application: app });
+          this.__DOM_IMPL__.dispatchEvent(event);
         }
         break;
       case "Webapps:Uninstall:Broadcast:Return:OK":
-        if (this._onuninstall) {
-          let event = new this._window.MozApplicationEvent("applicationuninstall",
-                           { application : createApplicationObject(this._window, msg) });
-          this._onuninstall.handleEvent(event);
+        {
+          let detail = {
+            manifestURL: msg.manifestURL,
+            origin: msg.origin
+          };
+          let app = createContentApplicationObject(this._window, detail);
+          let event =
+            new this._window.MozApplicationEvent("uninstall", { application : app });
+          this.__DOM_IMPL__.dispatchEvent(event);
         }
         break;
       case "Webapps:Uninstall:Return:OK":
         Services.DOMRequest.fireSuccess(req, msg.manifestURL);
         break;
       case "Webapps:Uninstall:Return:KO":
         Services.DOMRequest.fireError(req, "NOT_INSTALLED");
         break;
     }
     if (aMessage.name !== "Webapps:Uninstall:Broadcast:Return:OK") {
       this.removeRequest(msg.requestID);
     }
   },
 
   classID: Components.ID("{8c1bca96-266f-493a-8d57-ec7a95098c15}"),
 
-  QueryInterface: XPCOMUtils.generateQI([Ci.mozIDOMApplicationMgmt,
-                                         Ci.nsISupportsWeakReference,
-                                         Ci.nsIObserver]),
-
-  classInfo: XPCOMUtils.generateCI({classID: Components.ID("{8c1bca96-266f-493a-8d57-ec7a95098c15}"),
-                                    contractID: "@mozilla.org/webapps/application-mgmt;1",
-                                    interfaces: [Ci.mozIDOMApplicationMgmt],
-                                    flags: Ci.nsIClassInfo.DOM_OBJECT,
-                                    classDescription: "Webapps Application Mgmt"})
+  QueryInterface: XPCOMUtils.generateQI([Ci.nsISupports,
+                                         Ci.nsIObserver,
+                                         Ci.nsISupportsWeakReference])
 }
 
 this.NSGetFactory = XPCOMUtils.generateNSGetFactory([WebappsRegistry,
+                                                     WebappsApplicationMgmt,
                                                      WebappsApplication]);
--- a/dom/apps/src/Webapps.manifest
+++ b/dom/apps/src/Webapps.manifest
@@ -1,10 +1,9 @@
 # Webapps.js
 component {fff440b3-fae2-45c1-bf03-3b5a2e432270} Webapps.js
 contract @mozilla.org/webapps;1 {fff440b3-fae2-45c1-bf03-3b5a2e432270}
-category JavaScript-navigator-property mozApps @mozilla.org/webapps;1
+
+component {8c1bca96-266f-493a-8d57-ec7a95098c15} Webapps.js
+contract @mozilla.org/webapps/manager;1 {8c1bca96-266f-493a-8d57-ec7a95098c15}
 
 component {723ed303-7757-4fb0-b261-4f78b1f6bd22} Webapps.js
 contract @mozilla.org/webapps/application;1 {723ed303-7757-4fb0-b261-4f78b1f6bd22}
-
-component {dcc1d5b7-43d8-4740-9244-b3d8db0f503d} Webapps.js
-contract @mozilla.org/dom-error;1 {dcc1d5b7-43d8-4740-9244-b3d8db0f503d}
--- a/dom/apps/tests/test_install_receipts.html
+++ b/dom/apps/tests/test_install_receipts.html
@@ -203,9 +203,9 @@ function runTest() {
   yield undefined;
 }
 
 addLoadEvent(go);
 
 </script>
 </pre>
 </body>
-</html>
\ No newline at end of file
+</html>
--- a/dom/apps/tests/test_receipt_operations.html
+++ b/dom/apps/tests/test_receipt_operations.html
@@ -39,18 +39,18 @@ function continueTest() {
     finish();
   }
 }
 
 function finish() {
   SimpleTest.finish();
 }
 
-function cbError(aError) {
-  ok(false, "Error callback invoked " + aError);
+function cbError(aEvent) {
+  ok(false, "Error callback invoked " + aEvent.target.error.name);
   finish();
 }
 
 SimpleTest.waitForExplicitFinish();
 
 function runTest() {
   SpecialPowers.setAllAppsLaunchable(true);
 
@@ -59,16 +59,17 @@ function runTest() {
 
   var request = navigator.mozApps.install(gManifestURL);
   request.onerror = cbError;
   request.onsuccess = continueTest;
   yield undefined;
 
   var app = request.result;
   ok(app, "App is non-null");
+  info("receipts are " + app.receipts);
   ok(app.receipts.length == 0, "No receipts");
 
   let receipt1 = 'eyJhbGciOiAiSFMyNTYiLCAidHlwIjogIkpXVCJ9.eyJwcm9kdWN0IjogeyJ1cmwiOiAiaHR0cHM6Ly93d3cubW96aWxsYS5vcmciLCAic3RvcmVkYXRhIjogIjUxNjkzMTQzNTYifSwgInJlaXNzdWUiOiAiaHR0cDovL21vY2hpLnRlc3Q6ODg4OC9yZWlzc3VlLzUxNjkzMTQzNTYiLCAidXNlciI6IHsidHlwZSI6ICJkaXJlY3RlZC1pZGVudGlmaWVyIiwgInZhbHVlIjogIjRmYjM1MTUxLTJiOWItNGJhMi04MjgzLWM0OWQzODE2NDBiZCJ9LCAidmVyaWZ5IjogImh0dHA6Ly9tb2NoaS50ZXN0Ojg4ODgvdmVyaWZ5LzUxNjkzMTQzNTYiLCAiaXNzIjogImh0dHA6Ly9tb2NoaS50ZXN0Ojg4ODgiLCAiaWF0IjogMTMxMzYwMTg4LCAidHlwIjogInB1cmNoYXNlLXJlY2VpcHQiLCAibmJmIjogMTMxMzYwMTg1LCAiZGV0YWlsIjogImh0dHA6Ly9tb2NoaS50ZXN0Ojg4ODgvcmVjZWlwdC81MTY5MzE0MzU2In0.eZpTEnCLUR3iP3rm9WyJOqx1k66mQaAxqcrvX11r5E0';
 
   let receipt2 = 'eyJhbGciOiAiSFMyNTYiLCAidHlwIjogIkpXVCJ9.eyJwcm9kdWN0IjogeyJ1cmwiOiAiaHR0cHM6Ly93d3cubW96aWxsYS5vcmciLCAic3RvcmVkYXRhIjogIjUxNjkzMTQzNTcifSwgInJlaXNzdWUiOiAiaHR0cDovL21vY2hpLnRlc3Q6ODg4OC9yZWlzc3VlLzUxNjkzMTQzNTYiLCAidXNlciI6IHsidHlwZSI6ICJkaXJlY3RlZC1pZGVudGlmaWVyIiwgInZhbHVlIjogIjRmYjM1MTUxLTJiOWItNGJhMi04MjgzLWM0OWQzODE2NDBiZCJ9LCAidmVyaWZ5IjogImh0dHA6Ly9tb2NoaS50ZXN0Ojg4ODgvdmVyaWZ5LzUxNjkzMTQzNTYiLCAiaXNzIjogImh0dHA6Ly9tb2NoaS50ZXN0Ojg4ODgiLCAiaWF0IjogMTMxMzYwMTg4LCAidHlwIjogInB1cmNoYXNlLXJlY2VpcHQiLCAibmJmIjogMTMxMzYwMTg1LCAiZGV0YWlsIjogImh0dHA6Ly9tb2NoaS50ZXN0Ojg4ODgvcmVjZWlwdC81MTY5MzE0MzU2In0.k7tI0PTaMJf0w0keAHJR6couypGY-EtA38q2xOtSv6k';
 
   let receipt3 = 'eyJhbGciOiAiUlMyNTYiLCAidHlwIjogIkpXVCIsICJqa3UiOiAiaHR0cHM6Ly9tYXJrZXRwbGFjZS5jZG4ubW96aWxsYS5uZXQvcHVibGljX2tleXMvbWFya2V0cGxhY2Utcm9vdC1wdWIta2V5Lmp3ayJ9.eyJpc3MiOiAiaHR0cHM6Ly9tYXJrZXRwbGFjZS5jZG4ubW96aWxsYS5uZXQvcHVibGljX2tleXMvbWFya2V0cGxhY2Utcm9vdC1wdWIta2V5Lmp3ayIsICJwcmljZV9saW1pdCI6IDEwMCwgImp3ayI6IFt7ImFsZyI6ICJSU0EiLCAibW9kIjogIkFMYkszek5VQ0lFTEJRZ1QycGUzTEkwdC1sR0w5OElFTnBWOUtuX0F4VGxjLXZzX0ZFMlVyNzU2Z012bHA3a3BWVmFEWVNCdnVCQjgtZEZpU3VJbHdCUFB2bWFIaTFhd0xJMjRRY2JOMVJrN3pZS01SclVfSzdkVEN6MEh6VHoza01YVXp1ci1ySTIxS3BKb0NSZFNxeUl4bHpnUWFna1dUUWxIYUI2VzkzUjBacUxlQk9lUzhjbzNOUlczdjFfY0h4VTE1d0k4T0JHY0tRSXB3VHpONUVfRFdNZ0F1MGFQMHlWY3EzT0FwXy1fa1pjYXBtQnpSTmVMOHBxMjZXN01jMUpJZVBnZVZ5SXExcFBLMU9ldGhmdF9KeTk5R19EWWxQNW15YjFEY1VpbHE3RVNKc1UyeUZPUjJhWmkyYU1lTkRZekwyUmdZSGt2RWxyNDRMM2NZM0UiLCAiZXhwIjogIkFRQUIiLCAia2lkIjogImFwcHN0b3JlLm1vemlsbGEuY29tLTIwMTMtMTEtMjcifV0sICJleHAiOiAxMzg2Nzg4NDAxLCAiaWF0IjogMTM4NTU3ODgwMSwgInR5cCI6ICJjZXJ0aWZpZWQta2V5IiwgIm5iZiI6IDEzODU1Nzg4MDF9.Ne5AffwNIjbQmwY_dSKVXR0R0wdB92sW_BWQWbN2WKa_Ep6V0Fwr2pfcv0KenZcYKdxhhSPBrs5R38EcIqTYYrgIeeJyM_gGzv-ESsUsqbFejAbVH2xfwATZ1lXNPh0VSt33Drf2RY5jeU5PD3usXgOPr8RYAGkMxz_0SUay5WCBVRLkrgtrCUNyIKBwuHlxKK1JkncVXsN0mr_gwbm0EpBgIOEZQj75TE0KcviMUvYn8uhVYEwYMLzMQmUbI5quxH2z5mcK2DDNQGgT6ABJljKWCY-PPuMo9tsgXe6L7MTafulBuSIjs1ztAl4ZnwZjKmxWmhdeiaT41tCFlr4K8Q~eyJqa3UiOiAiaHR0cHM6Ly9tYXJrZXRwbGFjZS5jZG4ubW96aWxsYS5uZXQvcHVibGljX2tleXMvbWFya2V0cGxhY2Utcm9vdC1wdWIta2V5Lmp3ayIsICJ0eXAiOiAiSldUIiwgImFsZyI6ICJSUzI1NiJ9.eyJwcm9kdWN0IjogeyJ1cmwiOiAiaHR0cHM6Ly9tYXJrZXRwbGFjZS5maXJlZm94LmNvbSIsICJzdG9yZWRhdGEiOiAiaWQ9NDM4OTc4In0sICJpc3MiOiAiaHR0cHM6Ly9tYXJrZXRwbGFjZS5maXJlZm94LmNvbSIsICJ2ZXJpZnkiOiAiaHR0cHM6Ly9yZWNlaXB0Y2hlY2subWFya2V0cGxhY2UuZmlyZWZveC5jb20vdmVyaWZ5LyIsICJkZXRhaWwiOiAiaHR0cHM6Ly9tYXJrZXRwbGFjZS5maXJlZm94LmNvbS9hcGkvdjEvcmVjZWlwdHMvcmVpc3N1ZS8iLCAicmVpc3N1ZSI6ICJodHRwczovL21hcmtldHBsYWNlLmZpcmVmb3guY29tL2FwaS92MS9yZWNlaXB0cy9yZWlzc3VlLyIsICJ1c2VyIjogeyJ0eXBlIjogImRpcmVjdGVkLWlkZW50aWZpZXIiLCAidmFsdWUiOiAiMTkzMzI2LTVjMTUzNmQ1LWUxMDQtNDAzYy04NDBlLTQ5YjMyMmQ5Yjg4NSJ9LCAiZXhwIjogMTQwMTgyNTEyOCwgImlhdCI6IDEzODYxMDAzMjgsICJ0eXAiOiAicHVyY2hhc2UtcmVjZWlwdCIsICJuYmYiOiAxMzg2MTAwMzI4fQ.r2DVUpouRDJYqZe61LJBcIwmeF2mI8FmbGMRlfNFcinKAIs8nMVVNX8xSWJ6jXXgZ62VfHJCLHapADX8rCg6NgxFV_FdP7j2H_2Ufo0E0TREifTN6V4v1dCnzDulNhZmO8G-nQJUVOAtNfNC95PY7tVa8WC7dYXnKZsD6NhIxxVEtBGuiiySpWArI-g3pcl41rXNHHpJbRfrOD4QgVNrsV83TWILYRr6PWr3aqOM2XT_x2SzEfhBNvdG8AJmR0MKQytvfcgz3Vt1hMak88nFrzTLiKkuuPAXpwB5q83LZIl4EYG3UAnte4-XWlLb-NJ78vgXa64myy-3fPr7EO6LaQ';
 
@@ -91,32 +92,32 @@ function runTest() {
   request.onerror = function() {
     ok(this.error.name == "NO_SUCH_RECEIPT",
        "Request failed because there isn't any receipt");
     continueTest();
   }
   yield undefined;
 
   // Test addReceipt
-  request = app.addReceipt(null);
+  request = app.addReceipt();
   request.onsuccess = function() {
     ok(false, "Call with missing parameter should've failed");
   }
   request.onerror = function() {
-    ok(this.error.name == "INVALID_PARAMETERS",
+    is(this.error.name, "INVALID_PARAMETERS",
        "Request failed because of a missing parameter");
     continueTest();
   }
   yield undefined;
 
   request = app.addReceipt(receipt1);
   request.onerror = cbError;
   request.onsuccess = function() {
-    ok(app.receipts.length == 1, "One receipt");
-    ok(app.receipts[0] == receipt1, "Receipt correctly added");
+    is(app.receipts.length, 1, "One receipt");
+    is(app.receipts[0], receipt1, "Receipt correctly added");
     continueTest();
   };
   yield undefined;
 
   request = app.addReceipt(receipt1);
   request.onerror = function() {
     ok(this.error.name == "RECEIPT_ALREADY_EXISTS",
         "Request failed because the receipt already exists");
@@ -133,39 +134,28 @@ function runTest() {
     ok(app.receipts.length == 2, "Two receipts");
     ok(app.receipts[0] == receipt1, "First receipt is still there");
     ok(app.receipts[1] == receipt2, "Second receipt correctly added");
     continueTest();
   }
   yield undefined;
 
   // Test replace receipts
-  request = app.replaceReceipt(null, null);
+  request = app.replaceReceipt();
   request.onsuccess = function() {
     ok(false, "Call with missing parameters should've failed");
   }
   request.onerror = function() {
     ok(this.error.name == "INVALID_PARAMETERS",
        "Request failed because of missing parameters");
     continueTest();
   }
   yield undefined;
 
-  request = app.replaceReceipt(null, receipt1);
-  request.onsuccess = function() {
-    ok(false, "Call with missing parameter should've failed");
-  }
-  request.onerror = function() {
-    ok(this.error.name == "INVALID_PARAMETERS",
-       "Request failed because of a missing parameter");
-    continueTest();
-  }
-  yield undefined;
-
-  request = app.replaceReceipt(receipt1, null);
+  request = app.replaceReceipt(receipt1);
   request.onsuccess = function() {
     ok(false, "Call with missing parameter should've failed");
   }
   request.onerror = function() {
     ok(this.error.name == "INVALID_PARAMETERS",
        "Request failed because of a missing parameter");
     continueTest();
   }
@@ -191,17 +181,17 @@ function runTest() {
     ok(app.receipts.length == 2, "Two receipts");
     ok(app.receipts[0] == receipt3, "First receipt was replaced");
     ok(app.receipts[1] == receipt2, "Second receipt wasn't replaced");
     continueTest();
   }
   yield undefined;
 
   // Test remove receipt
-  request = app.removeReceipt(null);
+  request = app.removeReceipt();
   request.onsuccess = function() {
     ok(false, "Call with missing parameter should've failed");
   }
   request.onerror = function() {
     ok(this.error.name == "INVALID_PARAMETERS",
        "Request failed because of a missing parameter");
     continueTest();
   }
--- a/dom/bindings/Bindings.conf
+++ b/dom/bindings/Bindings.conf
@@ -1973,17 +1973,16 @@ def addExternalIface(iface, nativeType=N
     if not headerFile is None:
         domInterface['headerFile'] = headerFile
     domInterface['notflattened'] = notflattened
     DOMInterfaces[iface] = domInterface
 
 addExternalIface('ApplicationCache', nativeType='nsIDOMOfflineResourceList')
 addExternalIface('Counter')
 addExternalIface('CSSRule')
-addExternalIface('mozIDOMApplication', nativeType='mozIDOMApplication', headerFile='nsIDOMApplicationRegistry.h')
 addExternalIface('RTCDataChannel', nativeType='nsIDOMDataChannel')
 addExternalIface('File')
 addExternalIface('HitRegionOptions', nativeType='nsISupports')
 addExternalIface('imgINotificationObserver', nativeType='imgINotificationObserver')
 addExternalIface('imgIRequest', nativeType='imgIRequest', notflattened=True)
 addExternalIface('MenuBuilder', nativeType='nsIMenuBuilder', notflattened=True)
 addExternalIface('MozBoxObject', nativeType='nsIBoxObject')
 addExternalIface('MozControllers', nativeType='nsIControllers')
--- a/dom/interfaces/apps/moz.build
+++ b/dom/interfaces/apps/moz.build
@@ -3,15 +3,14 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 XPIDL_SOURCES += [
     'mozIApplication.idl',
     'mozIApplicationClearPrivateDataParams.idl',
     'nsIAppsService.idl',
-    'nsIDOMApplicationRegistry.idl',
     'nsIInterAppCommService.idl',
     'nsIInterAppCommUIGlue.idl'
 ]
 
 XPIDL_MODULE = 'dom_apps'
 
--- a/dom/interfaces/apps/nsIAppsService.idl
+++ b/dom/interfaces/apps/nsIAppsService.idl
@@ -1,15 +1,14 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "domstubs.idl"
 
-interface mozIDOMApplication;
 interface mozIApplication;
 interface nsIURI;
 
 %{C++
 #define APPS_SERVICE_CID { 0x05072afa, 0x92fe, 0x45bf, { 0xae, 0x22, 0x39, 0xb6, 0x9c, 0x11, 0x70, 0x58 } }
 #define APPS_SERVICE_CONTRACTID "@mozilla.org/AppsService;1"
 %}
 
deleted file mode 100644
--- a/dom/interfaces/apps/nsIDOMApplicationRegistry.idl
+++ /dev/null
@@ -1,201 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "domstubs.idl"
-#include "nsIDOMEventTarget.idl"
-
-interface nsIDOMDOMRequest;
-
-[scriptable, uuid(f8cb08ed-588e-465f-b2b3-a4b0afde711a)]
-interface mozIDOMApplication  : nsISupports
-{
-  readonly attribute jsval manifest;
-  readonly attribute jsval updateManifest;
-  readonly attribute DOMString manifestURL;
-  readonly attribute jsval receipts; /* an array of strings */
-  readonly attribute DOMString origin;
-  readonly attribute DOMString installOrigin;
-  readonly attribute unsigned long long installTime;
-  readonly attribute boolean removable;
-
-  /**
-   * The current progress when downloading an offline cache.
-   */
-  readonly attribute double progress;
-
-  /**
-   * The application installation state :
-   * "pending"   : The application is being installed (eg, we're downloading the
-   *               offline cache or the package).
-   * "installed" : The application is installed and ready to be launched.
-   * "updating"  : We are updating the offline-cache or the package.
-   */
-  readonly attribute DOMString installState;
-
-  /**
-   * fires a nsIDOMApplicationEvent when a change in appcache download or
-   * package download happens.
-   */
-  attribute nsIDOMEventListener onprogress;
-
-  /**
-   * The date of the last update check.
-   */
-  readonly attribute unsigned long long lastUpdateCheck;
-
-  /**
-   * The date of the last updated manifest.
-   */
-  readonly attribute unsigned long long updateTime;
-
-  /**
-   * Starts the process of looking for an update.
-   */
-  nsIDOMDOMRequest checkForUpdate();
-
-  readonly attribute boolean downloadAvailable;
-  readonly attribute boolean downloading;
-  readonly attribute boolean readyToApplyDownload;
-  readonly attribute long downloadSize;
-
-  // This is a DOMError
-  readonly attribute nsISupports downloadError;
-
-  attribute nsIDOMEventListener ondownloadsuccess;
-  attribute nsIDOMEventListener ondownloaderror;
-  attribute nsIDOMEventListener ondownloadavailable;
-
-  /**
-   * Will fire once the mgmt.applyDownload() call succeeds.
-   */
-  attribute nsIDOMEventListener ondownloadapplied;
-
-  /**
-   * Starts to download an update. If |downloading| is true, this
-   * is a no-op.
-   */
-  void download();
-
-  /**
-   * Cancels an ongoing update download.
-   */
-  void cancelDownload();
-
-  /* startPoint will be used when several launch_path exists for an app */
-  nsIDOMDOMRequest launch([optional] in DOMString startPoint);
-
-  /**
-   * Clear data that has been collected through mozbrowser elements.
-   * onsuccess will be called once data is actually cleared.
-   */
-  nsIDOMDOMRequest clearBrowserData();
-
-  /**
-   * Inter-App Communication APIs.
-   *
-   * https://wiki.mozilla.org/WebAPI/Inter_App_Communication_Alt_proposal
-   */
-  nsISupports connect(in DOMString keyword,
-                      [optional] in jsval rules); // nsISupports is a Promise.
-
-  nsISupports getConnections(); // nsISupports is a Promise.
-
-  /* Receipts handling functions */
-  nsIDOMDOMRequest addReceipt(in DOMString receipt);
-  nsIDOMDOMRequest removeReceipt(in DOMString receipt);
-  nsIDOMDOMRequest replaceReceipt(in DOMString oldReceipt, in DOMString newReceipt);
-};
-
-[scriptable, uuid(cf742022-5ba3-11e2-868f-03310341b006)]
-interface mozIDOMApplicationMgmt : nsISupports
-{
-  /**
-   * the request will return the all the applications installed. Only accessible
-   * to privileged callers.
-   */
-  nsIDOMDOMRequest getAll();
-
-  /**
-   * the request will return the applications acquired from all origins but
-   * which are not launchable (e.g. by not being natively installed), or null.
-   */
-  nsIDOMDOMRequest getNotInstalled();
-
-  /**
-   * event listener to get notified of application installs. Only settable by
-   * privileged callers.
-   * the event will be a mozIDOMApplicationEvent
-   */
-  attribute nsIDOMEventListener oninstall;
-
-  /**
-   * event listener to get notified of application uninstalls. Only settable by
-   * privileged callers.
-   * the event will be a mozIDOMApplicationEvent
-   */
-  attribute nsIDOMEventListener onuninstall;
-
-  /**
-   * Applies a downloaded update.
-   * This function is a no-op if it's passed an app object which doesn't have
-   * |readyToApplyDownload| set to true.
-   */
-  void applyDownload(in mozIDOMApplication app);
-
-  /**
-   * Uninstall a web app.
-   *
-   * @param app : the app object of the web app to be uninstalled.
-   * @returns   : A DOMRequest object, returning the app's origin in |result|
-   *              if uninstall succeeds; returning "NOT_INSTALLED" error otherwise.
-   */
-  nsIDOMDOMRequest uninstall(in mozIDOMApplication app);
-};
-
-[scriptable, uuid(52710c5f-b2a2-4b27-b5b9-f679a1bcc79b)]
-interface mozIDOMApplicationRegistry : nsISupports
-{
-  /**
-   * Install a web app.
-   *
-   * @param manifestUrl : the URL of the webapps manifest.
-   * @param parameters  : A structure with optional information.
-   *                      {
-   *                       receipts: ...    Will be used to specify the payment receipts for this installation.
-   *                       categories: ...  Will be used to specify the categories of the webapp.
-   *                      }
-   * @returns           : A DOMRequest object, returning the app object in |result| if install succeeds.
-   */
-  nsIDOMDOMRequest install(in DOMString manifestUrl, [optional] in jsval parameters);
-
-  /**
-   * the request will return the application currently installed, or null.
-   */
-  nsIDOMDOMRequest getSelf();
-
-  /**
-   * the request will return the application if the app from that origin is installed
-   */
-  nsIDOMDOMRequest checkInstalled(in DOMString manifestUrl);
-
-  /**
-   * the request will return the applications installed from this origin, or null.
-   */
-  nsIDOMDOMRequest getInstalled();
-
-  /**
-   * Install a packaged web app.
-   *
-   * @param packageUrl : the URL of the webapps manifest.
-   * @param parameters : A structure with optional information.
-   *                      {
-   *                       receipts: ...    Will be used to specify the payment receipts for this installation.
-   *                       categories: ...  Will be used to specify the categories of the webapp.
-   *                      }
-   * @returns          : A DOMRequest object, returning the app object in |result| if install succeeds.
-   */
-  nsIDOMDOMRequest installPackage(in DOMString packageUrl, [optional] in jsval parameters);
-
-  readonly attribute mozIDOMApplicationMgmt mgmt;
-};
--- a/dom/permission/tests/test_webapps-manage.html
+++ b/dom/permission/tests/test_webapps-manage.html
@@ -11,20 +11,26 @@ https://bugzilla.mozilla.org/show_bug.cg
 </head>
 <body>
 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=815105">Mozilla Bug 815105 </a>
 <p id="display"></p>
 <div id="content" style="display: none"></div>
 <pre id="test">
 <script type="application/javascript;version=1.8" src="file_framework.js"></script>
 <script type="application/javascript;version=1.8">
+function verifier(success, failure) {
+  if (window.navigator.mozApps.mgmt) {
+    success("Got mozApps.mgmt object!");
+  } else {
+    failure("Failed to get mozApps.mgmt object!");
+  }
+}
 var gData = [
   {
     perm: ["webapps-manage"],
-    obj: "mozApps.mgmt",
-    idl: "mozIDOMApplicationMgmt",
+    verifier: verifier.toSource(),
   }
 ]
 </script>
 </pre>
 </body>
 </html>
 
--- a/dom/tests/mochitest/general/test_interfaces.html
+++ b/dom/tests/mochitest/general/test_interfaces.html
@@ -635,18 +635,16 @@ var interfaceNamesInGlobalScope =
     "ModalContentWindow",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "MouseEvent",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "MouseScrollEvent",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "MozActivity", b2g: true},
 // IMPORTANT: Do not change this list without review from a DOM peer!
-    "MozApplicationEvent",
-// IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "MozCellBroadcast", b2g: true, pref: "dom.cellbroadcast.enabled"},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "MozCellBroadcastEvent", b2g: true, pref: "dom.cellbroadcast.enabled"},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "MozClirModeEvent", b2g: true, pref: "dom.mobileconnection.enabled"},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "mozContact",
 // IMPORTANT: Do not change this list without review from a DOM peer!
--- a/dom/tests/mochitest/webapps/test_install_errors.xul
+++ b/dom/tests/mochitest/webapps/test_install_errors.xul
@@ -37,17 +37,17 @@ var steps = [
 ];
 
 runAll(steps);
 
 function noArgs(next) {
   try {
     navigator.mozApps.install();
   } catch (e) {
-    is(e.message, "Not enough arguments \[mozIDOMApplicationRegistry.install\]",
+    is(e.message, "Not enough arguments to DOMApplicationsRegistry.install.",
        "install without arguments throws exception");
     next();
   }
 }
 
 function parseError(next) {
   var url = "http://test/chrome/dom/tests/mochitest/webapps/apps/json_syntax_error.webapp";
 
--- a/dom/tests/mochitest/webapps/test_list_api.xul
+++ b/dom/tests/mochitest/webapps/test_list_api.xul
@@ -14,40 +14,44 @@
   <body xmlns="http://www.w3.org/1999/xhtml">
   <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=741549"
      target="_blank">Mozilla Bug 741549</a>
   </body>
 
 <script>
 
 var props = {
-  QueryInterface: "function",
   checkInstalled: "function",
   getInstalled: "function",
   getSelf: "function",
   install: "function",
   installPackage: "function",
   mgmt: "object",
 };
 
 isDeeply([p for (p in navigator.mozApps)].sort(), Object.keys(props).sort(),
          "navigator.mozApps has only the expected properties");
 
 for (var p in props) {
   is(typeof navigator.mozApps[p], props[p], "typeof " + p);
 }
 
 var mgmtProps = {
-  QueryInterface: "function",
+  addEventListener: "function",
   applyDownload: "function",
+  dispatchEvent: "function",
+  getEventHandler: "function",
   getAll: "function",
   getNotInstalled: "function",
   uninstall: "function",
   oninstall: "object",
   onuninstall: "object",
+  ownerGlobal: "object",
+  removeEventListener: "function",
+  setEventHandler: "function",
 };
 
 isDeeply([p for (p in navigator.mozApps.mgmt)].sort(),
          Object.keys(mgmtProps).sort(),
          "navigator.mozApps.mgmt has only the expected properties");
 
 for (var p in mgmtProps) {
   is(typeof navigator.mozApps.mgmt[p], mgmtProps[p], "typeof mgmt." + p);
new file mode 100644
--- /dev/null
+++ b/dom/webidl/Apps.webidl
@@ -0,0 +1,96 @@
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+dictionary InstallParameters {
+  sequence<DOMString> receipts = [];
+  sequence<DOMString> categories = [];
+};
+
+[NoInterfaceObject, NavigatorProperty="mozApps",
+ JSImplementation="@mozilla.org/webapps;1"]
+interface DOMApplicationsRegistry {
+  [CheckPermissions="webapps-manage"]
+  readonly attribute DOMApplicationsManager mgmt;
+  DOMRequest install(DOMString url, optional InstallParameters params);
+  DOMRequest installPackage(DOMString url, optional InstallParameters params);
+  DOMRequest getSelf();
+  DOMRequest getInstalled();
+  DOMRequest checkInstalled(DOMString manifestUrl);
+};
+
+[JSImplementation="@mozilla.org/webapps/application;1", ChromeOnly]
+interface DOMApplication : EventTarget {
+  // manifest and updateManifest will be turned into dictionaries once
+  // in bug 1053033 once bug 963382 is fixed.
+  readonly attribute any manifest;
+  readonly attribute any updateManifest;
+  readonly attribute DOMString manifestURL;
+  readonly attribute DOMString origin;
+  readonly attribute DOMString installOrigin;
+  readonly attribute DOMTimeStamp installTime;
+  readonly attribute boolean removable;
+
+  // That's actually a [Cached, Pure] sequence<DOMString>.
+  // Will update once bug 963382 is fixed.
+  readonly attribute any receipts;
+
+  readonly attribute double progress;
+
+  readonly attribute DOMString installState;
+
+  readonly attribute DOMTimeStamp lastUpdateCheck;
+  readonly attribute DOMTimeStamp updateTime;
+
+  readonly attribute boolean downloadAvailable;
+  readonly attribute boolean downloading;
+  readonly attribute boolean readyToApplyDownload;
+  readonly attribute long downloadSize;
+
+  readonly attribute DOMError? downloadError;
+
+  attribute EventHandler onprogress;
+  attribute EventHandler ondownloadsuccess;
+  attribute EventHandler ondownloaderror;
+  attribute EventHandler ondownloadavailable;
+  attribute EventHandler ondownloadapplied;
+
+  void download();
+  void cancelDownload();
+
+  DOMRequest launch(optional DOMString? url);
+
+  DOMRequest clearBrowserData();
+  DOMRequest checkForUpdate();
+
+  /**
+   * Inter-App Communication APIs.
+   *
+   * https://wiki.mozilla.org/WebAPI/Inter_App_Communication_Alt_proposal
+   *
+   */
+   Promise<MozInterAppConnection> connect(DOMString keyword, optional any rules);
+
+   Promise<sequence<MozInterAppMessagePort>> getConnections();
+
+    // Receipts handling functions.
+    DOMRequest addReceipt(optional DOMString receipt);
+    DOMRequest removeReceipt(optional DOMString receipt);
+    DOMRequest replaceReceipt(optional DOMString oldReceipt,
+                              optional DOMString newReceipt);
+};
+
+[JSImplementation="@mozilla.org/webapps/manager;1",
+ ChromeOnly,
+ CheckPermissions="webapps-manage"]
+interface DOMApplicationsManager : EventTarget {
+  DOMRequest getAll();
+  DOMRequest getNotInstalled();
+  void applyDownload(DOMApplication app);
+  DOMRequest uninstall(DOMApplication app);
+
+  attribute EventHandler oninstall;
+  attribute EventHandler onuninstall;
+};
--- a/dom/webidl/MozApplicationEvent.webidl
+++ b/dom/webidl/MozApplicationEvent.webidl
@@ -1,17 +1,16 @@
 /* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/.
  */
-interface mozIDOMApplication;
 
-[Constructor(DOMString type, optional MozApplicationEventInit eventInitDict)]
+[Constructor(DOMString type, optional MozApplicationEventInit eventInitDict), ChromeOnly]
 interface MozApplicationEvent : Event
 {
-  readonly attribute mozIDOMApplication? application;
+  readonly attribute DOMApplication? application;
 };
 
 dictionary MozApplicationEventInit : EventInit
 {
-  mozIDOMApplication? application = null;
+  DOMApplication? application = null;
 };
--- a/dom/webidl/moz.build
+++ b/dom/webidl/moz.build
@@ -22,16 +22,17 @@ WEBIDL_FILES = [
     'AnalyserNode.webidl',
     'Animatable.webidl',
     'Animation.webidl',
     'AnimationEvent.webidl',
     'AnimationPlayer.webidl',
     'AnimationTimeline.webidl',
     'AppInfo.webidl',
     'AppNotificationServiceOptions.webidl',
+    'Apps.webidl',
     'APZTestData.webidl',
     'ArchiveReader.webidl',
     'ArchiveRequest.webidl',
     'Attr.webidl',
     'AudioBuffer.webidl',
     'AudioBufferSourceNode.webidl',
     'AudioChannel.webidl',
     'AudioContext.webidl',