Bug 1018320 - RequestSync API - Patch 6 - Manager API. r=ehsan, a=bajaj
authorAndrea Marchesini <amarchesini@mozilla.com>
Tue, 13 Jan 2015 09:53:24 +0000
changeset 237140 d283ce0f09967d1c5296c34e135fa8d5a8622596
parent 237139 bfc99f8c73b62e51334c2cfd5e952f34e37e7573
child 237141 addef534a15bc1689ff4b4e7f697531756a7c073
push id213
push userryanvm@gmail.com
push dateTue, 24 Feb 2015 00:59:48 +0000
treeherdermozilla-b2g37_v2_2@b5a532c7f606 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersehsan, bajaj
bugs1018320
milestone37.0
Bug 1018320 - RequestSync API - Patch 6 - Manager API. r=ehsan, a=bajaj
dom/requestsync/RequestSyncApp.jsm
dom/requestsync/RequestSyncManager.js
dom/requestsync/RequestSyncService.jsm
dom/requestsync/RequestSyncTask.jsm
dom/requestsync/moz.build
dom/requestsync/tests/common_basic.js
dom/requestsync/tests/test_basic.html
dom/tests/mochitest/general/test_interfaces.html
dom/webidl/RequestSyncManager.webidl
dom/webidl/RequestSyncScheduler.webidl
new file mode 100644
--- /dev/null
+++ b/dom/requestsync/RequestSyncApp.jsm
@@ -0,0 +1,48 @@
+/* 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/. */
+
+'use strict';
+
+this.EXPORTED_SYMBOLS = ['RequestSyncApp'];
+
+function debug(s) {
+  //dump('DEBUG RequestSyncApp: ' + s + '\n');
+}
+
+const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
+
+Cu.import('resource://gre/modules/XPCOMUtils.jsm');
+
+this.RequestSyncApp = function(aData) {
+  debug('created');
+
+  let keys = [ 'origin', 'manifestURL', 'isInBrowserElement' ];
+  for (let i = 0; i < keys.length; ++i) {
+    if (!(keys[i] in aData)) {
+      dump("ERROR - RequestSyncApp must receive a full app object: " + keys[i] + " missing.");
+      throw "ERROR!";
+    }
+
+    this["_" + keys[i]] = aData[keys[i]];
+  }
+}
+
+this.RequestSyncApp.prototype = {
+  classDescription: 'RequestSyncApp XPCOM Component',
+  classID: Components.ID('{5a0b64db-a2be-4f08-a6c5-8bf2e3ae0c57}'),
+  contractID: '@mozilla.org/dom/request-sync-manager;1',
+  QueryInterface: XPCOMUtils.generateQI([]),
+
+  get origin() {
+    return this._origin;
+  },
+
+  get manifestURL() {
+    return this._manifestURL;
+  },
+
+  get isInBrowserElement() {
+    return this._isInBrowserElement;
+  }
+};
--- a/dom/requestsync/RequestSyncManager.js
+++ b/dom/requestsync/RequestSyncManager.js
@@ -7,16 +7,18 @@
 function debug(s) {
   //dump('DEBUG RequestSyncManager: ' + s + '\n');
 }
 
 const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
 
 Cu.import("resource://gre/modules/DOMRequestHelper.jsm");
 Cu.import('resource://gre/modules/XPCOMUtils.jsm');
+Cu.import('resource://gre/modules/RequestSyncApp.jsm');
+Cu.import('resource://gre/modules/RequestSyncTask.jsm');
 
 XPCOMUtils.defineLazyServiceGetter(this, "cpmm",
                                    "@mozilla.org/childprocessmessagemanager;1",
                                    "nsIMessageSender");
 
 function RequestSyncManager() {
   debug('created');
 }
@@ -26,17 +28,18 @@ RequestSyncManager.prototype = {
 
   classDescription: 'RequestSyncManager XPCOM Component',
   classID: Components.ID('{e6f55080-e549-4e30-9d00-15f240fb763c}'),
   contractID: '@mozilla.org/dom/request-sync-manager;1',
   QueryInterface: XPCOMUtils.generateQI([Ci.nsISupportsWeakReference,
                                          Ci.nsIObserver,
                                          Ci.nsIDOMGlobalPropertyInitializer]),
 
-  _messages: [ "RequestSyncManager:Registrations:Return" ],
+  _messages: [ "RequestSyncManager:Registrations:Return",
+               "RequestSyncManager:SetPolicy:Return" ],
 
   init: function(aWindow) {
     debug("init");
 
     // DOMRequestIpcHelper.initHelper sets this._window
     this.initDOMRequestHelper(aWindow, this._messages);
   },
 
@@ -50,29 +53,70 @@ RequestSyncManager.prototype = {
     });
   },
 
   registrations: function() {
     debug('registrations');
     return this.sendMessage("RequestSyncManager:Registrations", {});
   },
 
+  setPolicy: function(aTask, aOrigin, aManifestURL, aIsInBrowserElement,
+                      aState, aOverwrittenMinInterval) {
+    debug('setPolicy');
+
+    return this.sendMessage("RequestSyncManager:SetPolicy",
+      { task: aTask,
+        origin: aOrigin,
+        manifestURL: aManifestURL,
+        isInBrowserElement: aIsInBrowserElement,
+        state: aState,
+        overwrittenMinInterval: aOverwrittenMinInterval });
+  },
+
+  registrationsResult: function(aData) {
+    debug("registrationsResult");
+
+    let results = new this._window.Array();
+    for (let i = 0; i < aData.length; ++i) {
+      if (!("app" in aData[i])) {
+        dump("ERROR - Serialization error in RequestSyncManager.\n");
+        continue;
+      }
+
+      let app = new RequestSyncApp(aData[i].app);
+      let exposedApp =
+        this._window.RequestSyncApp._create(this._window, app);
+
+      let task = new RequestSyncTask(this, this._window, exposedApp, aData[i]);
+      let exposedTask =
+        this._window.RequestSyncTask._create(this._window, task);
+
+      results.push(exposedTask);
+    }
+    return results;
+  },
+
   receiveMessage: function(aMessage) {
     debug('receiveMessage');
 
     let req = this.getPromiseResolver(aMessage.data.requestID);
     if (!req) {
       return;
     }
 
     if ('error' in aMessage.data) {
       req.reject(Cu.cloneInto(aMessage.data.error, this._window));
       return;
     }
 
+    if (aMessage.name == 'RequestSyncManager:Registrations:Return') {
+      req.resolve(this.registrationsResult(aMessage.data.results));
+      return;
+    }
+
     if ('results' in aMessage.data) {
       req.resolve(Cu.cloneInto(aMessage.data.results, this._window));
       return;
     }
 
     req.resolve();
   }
 };
--- a/dom/requestsync/RequestSyncService.jsm
+++ b/dom/requestsync/RequestSyncService.jsm
@@ -11,16 +11,20 @@ function debug(s) {
 }
 
 const RSYNCDB_VERSION = 1;
 const RSYNCDB_NAME = "requestSync";
 const RSYNC_MIN_INTERVAL = 100;
 
 const RSYNC_OPERATION_TIMEOUT = 120000 // 2 minutes
 
+const RSYNC_STATE_ENABLED = "enabled";
+const RSYNC_STATE_DISABLED = "disabled";
+const RSYNC_STATE_WIFIONLY = "wifiOnly";
+
 Cu.import('resource://gre/modules/IndexedDBHelper.jsm');
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.importGlobalProperties(["indexedDB"]);
 
 
 XPCOMUtils.defineLazyServiceGetter(this, "appsService",
                                    "@mozilla.org/AppsService;1",
@@ -42,19 +46,22 @@ XPCOMUtils.defineLazyServiceGetter(this,
                                    "@mozilla.org/scriptsecuritymanager;1",
                                    "nsIScriptSecurityManager");
 
 this.RequestSyncService = {
   __proto__: IndexedDBHelper.prototype,
 
   children: [],
 
-  _messages: [ "RequestSync:Register", "RequestSync:Unregister",
-               "RequestSync:Registrations", "RequestSync:Registration",
-               "RequestSyncManager:Registrations" ],
+  _messages: [ "RequestSync:Register",
+               "RequestSync:Unregister",
+               "RequestSync:Registrations",
+               "RequestSync:Registration",
+               "RequestSyncManager:Registrations",
+               "RequestSyncManager:SetPolicy" ],
 
   _pendingOperation: false,
   _pendingMessages: [],
 
   _registrations: {},
 
   _wifi: false,
 
@@ -311,16 +318,20 @@ this.RequestSyncService = {
       case "RequestSync:Registration":
         this.registration(aMessage.target, aMessage.data, principal);
         break;
 
       case "RequestSyncManager:Registrations":
         this.managerRegistrations(aMessage.target, aMessage.data, principal);
         break;
 
+      case "RequestSyncManager:SetPolicy":
+        this.managerSetPolicy(aMessage.target, aMessage.data, principal);
+        break;
+
       default:
         debug("Wrong message: " + aMessage.name);
         break;
     }
   },
 
   // Basic validation.
   validateRegistrationParams: function(aParams) {
@@ -365,16 +376,23 @@ this.RequestSyncService = {
       this.removeRegistrationInternal(aData.task, key);
     }
 
     // This creates a RequestTaskFull object.
     aData.params.task = aData.task;
     aData.params.lastSync = 0;
     aData.params.principal = aPrincipal;
 
+    aData.params.state = RSYNC_STATE_ENABLED;
+    if (aData.params.wifiOnly) {
+      aData.params.state = RSYNC_STATE_WIFIONLY;
+    }
+
+    aData.params.overwrittenMinInterval = 0;
+
     let dbKey = aData.task + "|" +
                 aPrincipal.appId + '|' +
                 aPrincipal.isInBrowserElement + '|' +
                 aPrincipal.origin;
 
     let data = { principal: aPrincipal,
                  dbKey: dbKey,
                  data: aData.params,
@@ -473,16 +491,61 @@ this.RequestSyncService = {
       results.push(self.createFullTaskObject(aObj.data));
     });
 
     aTarget.sendAsyncMessage("RequestSyncManager:Registrations:Return",
                              { requestID: aData.requestID,
                                results: results });
   },
 
+  // Set a policy to a task.
+  managerSetPolicy: function(aTarget, aData, aPrincipal) {
+    debug("managerSetPolicy");
+
+    let toSave = null;
+    let self = this;
+    this.forEachRegistration(function(aObj) {
+      if (aObj.principal.isInBrowserElement != aData.isInBrowserElement ||
+          aObj.principal.origin != aData.origin) {
+        return;
+      }
+
+      let app = appsService.getAppByLocalId(aObj.principal.appId);
+      if (app && app.manifestURL != aData.manifestURL ||
+          (!app && aData.manifestURL != "")) {
+        return;
+      }
+
+      if ("overwrittenMinInterval" in aData) {
+        aObj.data.overwrittenMinInterval = aData.overwrittenMinInterval;
+      }
+
+      aObj.data.state = aData.state;
+
+      if (toSave) {
+        dump("ERROR!! RequestSyncService - SetPolicy matches more than 1 task.\n");
+        return;
+      }
+
+      toSave = aObj;
+    });
+
+    if (!toSave) {
+      aTarget.sendAsyncMessage("RequestSyncManager:SetPolicy:Return",
+                               { requestID: aData.requestID, error: "UnknownTaskError" });
+      return;
+    }
+
+    this.updateObjectInDB(toSave, function() {
+      self.scheduleTimer(toSave);
+      aTarget.sendAsyncMessage("RequestSyncManager:SetPolicy:Return",
+                               { requestID: aData.requestID });
+    });
+  },
+
   // We cannot expose the full internal object to content but just a subset.
   // This method creates this subset.
   createPartialTaskObject: function(aObj) {
     return { task: aObj.task,
              lastSync: aObj.lastSync,
              oneShot: aObj.oneShot,
              minInterval: aObj.minInterval,
              wakeUpPage: aObj.wakeUpPage,
@@ -497,38 +560,54 @@ this.RequestSyncService = {
                 origin: aObj.principal.origin,
                 isInBrowserElement: aObj.principal.isInBrowserElement };
 
     let app = appsService.getAppByLocalId(aObj.principal.appId);
     if (app) {
       obj.app.manifestURL = app.manifestURL;
     }
 
+    obj.state = aObj.state;
+    obj.overwrittenMinInterval = aObj.overwrittenMinInterval;
     return obj;
   },
 
   // Creation of the timer for a particular task object.
   scheduleTimer: function(aObj) {
     debug("scheduleTimer");
 
+    if (aObj.timer) {
+      aObj.timer.cancel();
+      aObj.timer = null;
+    }
+
     // A  registration can be already inactive if it was 1 shot.
     if (!aObj.active) {
       return;
     }
 
+    if (aObj.data.state == RSYNC_STATE_DISABLED) {
+      return;
+    }
+
     // WifiOnly check.
-    if (aObj.data.wifiOnly && !this._wifi) {
+    if (aObj.data.state == RSYNC_STATE_WIFIONLY && !this._wifi) {
       return;
     }
 
     aObj.timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
 
+    let interval = aObj.data.minInterval;
+    if (aObj.data.overwrittenMinInterval > 0) {
+      interval = aObj.data.overwrittenMinInterval;
+    }
+
     let self = this;
     aObj.timer.initWithCallback(function() { self.timeout(aObj); },
-                                aObj.data.minInterval * 1000,
+                                interval * 1000,
                                 Ci.nsITimer.TYPE_ONE_SHOT);
   },
 
   timeout: function(aObj) {
     debug("timeout");
 
     if (this._activeTask) {
       debug("queueing tasks");
@@ -734,17 +813,17 @@ this.RequestSyncService = {
   wifiStateChanged: function(aEnabled) {
     debug("onWifiStateChanged");
     this._wifi = aEnabled;
 
     if (!this._wifi) {
       // Disable all the wifiOnly tasks.
       let self = this;
       this.forEachRegistration(function(aObj) {
-        if (aObj.data.wifiOnly && aObj.timer) {
+        if (aObj.data.state == RSYNC_STATE_WIFIONLY && aObj.timer) {
           aObj.timer.cancel();
           aObj.timer = null;
 
           // It can be that this task has been already schedulated.
           self.removeTaskFromQueue(aObj);
         }
       });
       return;
new file mode 100644
--- /dev/null
+++ b/dom/requestsync/RequestSyncTask.jsm
@@ -0,0 +1,101 @@
+/* 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/. */
+
+'use strict';
+
+this.EXPORTED_SYMBOLS = ['RequestSyncTask'];
+
+function debug(s) {
+  //dump('DEBUG RequestSyncTask: ' + s + '\n');
+}
+
+const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
+
+Cu.import('resource://gre/modules/XPCOMUtils.jsm');
+
+this.RequestSyncTask = function(aManager, aWindow, aApp, aData) {
+  debug('created');
+
+  this._manager = aManager;
+  this._window = aWindow;
+  this._app = aApp;
+
+  let keys = [ 'task', 'lastSync', 'oneShot', 'minInterval', 'wakeUpPage',
+               'wifiOnly', 'data', 'state', 'overwrittenMinInterval' ];
+  for (let i = 0; i < keys.length; ++i) {
+    if (!(keys[i] in aData)) {
+      dump("ERROR - RequestSyncTask must receive a fully app object: " + keys[i] + " missing.");
+      throw "ERROR!";
+    }
+
+    this["_" + keys[i]] = aData[keys[i]];
+  }
+}
+
+this.RequestSyncTask.prototype = {
+  classDescription: 'RequestSyncTask XPCOM Component',
+  classID: Components.ID('{a1e1c9c6-ce42-49d4-b8b4-fbd686d8fdd9}'),
+  contractID: '@mozilla.org/dom/request-sync-manager;1',
+  QueryInterface: XPCOMUtils.generateQI([]),
+
+  get app() {
+    return this._app;
+  },
+
+  get state() {
+    return this._state;
+  },
+
+  get overwrittenMinInterval() {
+    return this._overwrittenMinInterval;
+  },
+
+  get task() {
+    return this._task;
+  },
+
+  get lastSync() {
+    return this._lastSync;
+  },
+
+  get wakeUpPage() {
+    return this._wakeUpPage;
+  },
+
+  get oneShot() {
+    return this._oneShot;
+  },
+
+  get minInterval() {
+    return this._minInterval;
+  },
+
+  get wifiOnly() {
+    return this._wifiOnly;
+  },
+
+  get data() {
+    return this._data;
+  },
+
+  setPolicy: function(aState, aOverwrittenMinInterval) {
+    debug("setPolicy");
+    let self = this;
+
+    return new this._window.Promise(function(aResolve, aReject) {
+      let p = self._manager.setPolicy(self._task, self._app.origin,
+                                      self._app.manifestURL,
+                                      self._app.isInBrowserElement,
+                                      aState,
+                                      aOverwrittenMinInterval);
+
+      // Set the new value only when the promise is resolved.
+      p.then(function() {
+        self._state = aState;
+        self._overwrittenMinInterval = aOverwrittenMinInterval;
+        aResolve();
+      }, aReject);
+    });
+  }
+};
--- a/dom/requestsync/moz.build
+++ b/dom/requestsync/moz.build
@@ -12,17 +12,19 @@ EXPORTS.mozilla.dom += [
 
 EXTRA_COMPONENTS += [
     'RequestSync.manifest',
     'RequestSyncManager.js',
     'RequestSyncScheduler.js',
 ]
 
 EXTRA_JS_MODULES += [
+    'RequestSyncApp.jsm',
     'RequestSyncService.jsm',
+    'RequestSyncTask.jsm',
 ]
 
 SOURCES += [
     'RequestSyncWifiService.cpp',
 ]
 
 include('/ipc/chromium/chromium-config.mozbuild')
 
--- a/dom/requestsync/tests/common_basic.js
+++ b/dom/requestsync/tests/common_basic.js
@@ -146,27 +146,42 @@ function test_managerRegistrationsEmpty(
   navigator.syncManager.registrations().then(
   function(results) {
     is(results.length, 0, "navigator.syncManager.registrations() should return an empty array.");
     runTests();
   },
   genericError);
 }
 
-function test_managerRegistrations() {
+function test_managerRegistrations(state, overwrittenMinInterval) {
   navigator.syncManager.registrations().then(
   function(results) {
     is(results.length, 1, "navigator.sync.registrations() should not return an empty array.");
     is(results[0].task, 'foobar', "navigator.sync.registrations()[0].task is correct");
     ok("lastSync" in results[0], "navigator.sync.registrations()[0].lastSync is correct");
     is(results[0].oneShot, true, "navigator.sync.registrations()[0].oneShot is correct");
     is(results[0].minInterval, 5, "navigator.sync.registrations()[0].minInterval is correct");
     ok("wakeUpPage" in results[0], "navigator.sync.registration()[0].wakeUpPage is correct");
     ok("wifiOnly" in results[0], "navigator.sync.registrations()[0].wifiOnly is correct");
     ok("data" in results[0], "navigator.sync.registrations()[0].data is correct");
     ok("app" in results[0], "navigator.sync.registrations()[0].app is correct");
     ok("manifestURL" in results[0].app, "navigator.sync.registrations()[0].app.manifestURL is correct");
     is(results[0].app.origin, 'http://mochi.test:8888', "navigator.sync.registrations()[0].app.origin is correct");
     is(results[0].app.isInBrowserElement, false, "navigator.sync.registrations()[0].app.isInBrowserElement is correct");
+    is(results[0].state, state, "navigator.sync.registrations()[0].state is correct");
+    is(results[0].overwrittenMinInterval, overwrittenMinInterval, "navigator.sync.registrations()[0].overwrittenMinInterval is correct");
+    ok("setPolicy" in results[0], "navigator.sync.registrations()[0].setPolicy is correct");
     runTests();
   },
   genericError);
 }
+
+function test_managerSetPolicy(state, overwrittenMinInterval) {
+  navigator.syncManager.registrations().then(
+  function(results) {
+    results[0].setPolicy(state, overwrittenMinInterval).then(
+    function() {
+      ok(state, results[0].state, "State matches");
+      ok(overwrittenMinInterval, results[0].overwrittenMinInterval, "OverwrittenMinInterval matches");
+      runTests();
+    }, genericError);
+  }).catch(genericError);
+}
--- a/dom/requestsync/tests/test_basic.html
+++ b/dom/requestsync/tests/test_basic.html
@@ -33,22 +33,28 @@
     test_managerRegistrationsEmpty,
     test_registrationsEmpty,
 
     test_registerFailure,
     test_register,
     // overwrite the same registration.
     test_register,
 
-    test_managerRegistrations,
+    function() { test_managerRegistrations('wifiOnly', 0); },
     test_registrations,
 
     test_registrationEmpty,
     test_registration,
 
+    function() { test_managerSetPolicy('disabled', 123); },
+    function() { test_managerRegistrations('disabled', 123); },
+
+    function() { test_managerSetPolicy('enabled', 42); },
+    function() { test_managerRegistrations('enabled', 42); },
+
     test_unregister,
     test_unregisterDuplicate,
 
     test_managerRegistrationsEmpty,
     test_registrationsEmpty,
   ];
 
   function runTests() {
--- a/dom/tests/mochitest/general/test_interfaces.html
+++ b/dom/tests/mochitest/general/test_interfaces.html
@@ -1205,16 +1205,20 @@ var interfaceNamesInGlobalScope =
     "SVGViewElement",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "SVGZoomAndPan",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "SVGZoomEvent",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "RequestSyncManager", b2g: true, pref: "dom.requestSync.enabled", permission: ["requestsync-manager"] },
 // IMPORTANT: Do not change this list without review from a DOM peer!
+    {name: "RequestSyncApp", b2g: true, pref: "dom.requestSync.enabled", permission: ["requestsync-manager"] },
+// IMPORTANT: Do not change this list without review from a DOM peer!
+    {name: "RequestSyncTask", b2g: true, pref: "dom.requestSync.enabled", permission: ["requestsync-manager"] },
+// IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "Telephony", b2g: true, pref: "dom.telephony.enabled"},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "TelephonyCall", b2g: true, pref: "dom.telephony.enabled"},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "TelephonyCallGroup", b2g: true, pref: "dom.telephony.enabled"},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "TelephonyCallId", b2g: true, pref: "dom.telephony.enabled"},
 // IMPORTANT: Do not change this list without review from a DOM peer!
--- a/dom/webidl/RequestSyncManager.webidl
+++ b/dom/webidl/RequestSyncManager.webidl
@@ -1,27 +1,54 @@
 /* -*- 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/.
  */
 
-// Rappresentation of the app in the RequestTaskFull.
-dictionary RequestTaskApp {
-  USVString origin;
-  USVString manifestURL;
-  boolean isInBrowserElement;
+[AvailableIn=CertifiedApps,
+ Pref="dom.requestSync.enabled",
+ CheckPermissions="requestsync-manager",
+ JSImplementation="@mozilla.org/dom/request-sync-task-app;1"]
+interface RequestSyncApp {
+  readonly attribute USVString origin;
+  readonly attribute USVString manifestURL;
+  readonly attribute boolean isInBrowserElement;
 };
 
+enum RequestSyncTaskPolicyState { "enabled", "disabled", "wifiOnly" };
+
 // Like a normal task, but with info about the app.
-dictionary RequestTaskFull : RequestTask {
-  RequestTaskApp app;
+[AvailableIn=CertifiedApps,
+ Pref="dom.requestSync.enabled",
+ CheckPermissions="requestsync-manager",
+ JSImplementation="@mozilla.org/dom/request-sync-task-manager;1"]
+interface RequestSyncTask {
+  // This object describes the app that is owning the task.
+  readonly attribute RequestSyncApp app;
+
+  // Using setPolicy it's possible to owerwrite the state and the minInterval.
+  readonly attribute RequestSyncTaskPolicyState state;
+  readonly attribute long overwrittenMinInterval;
+
+  // These attributes are taken from the configuration of the task:
+
+  readonly attribute USVString task;
+  readonly attribute DOMTimeStamp lastSync;
+  readonly attribute USVString wakeUpPage;
+  readonly attribute boolean oneShot;
+  readonly attribute long minInterval;
+  readonly attribute boolean wifiOnly;
+  readonly attribute any data;
+
+  Promise<void> setPolicy(RequestSyncTaskPolicyState aState,
+                          optional long ovewrittenMinInterval);
 };
 
 [NavigatorProperty="syncManager",
  AvailableIn=CertifiedApps,
  Pref="dom.requestSync.enabled",
  CheckPermissions="requestsync-manager",
  JSImplementation="@mozilla.org/dom/request-sync-manager;1"]
 // This interface will be used only by the B2G SystemApp
 interface RequestSyncManager {
-    Promise<sequence<RequestTaskFull>> registrations();
+    Promise<sequence<RequestSyncTask>> registrations();
 };
--- a/dom/webidl/RequestSyncScheduler.webidl
+++ b/dom/webidl/RequestSyncScheduler.webidl
@@ -10,17 +10,17 @@ dictionary RequestTaskParams {
   boolean oneShot = true;
   required long minInterval; // in seconds >= dom.requestSync.minInterval or 100 secs
   boolean wifiOnly = true;
   any data = null;
 };
 
 
 // This is the dictionary you can have back from registration{s}().
-dictionary RequestTask : RequestTaskParams {
+dictionary RequestTaskFull : RequestTaskParams {
   USVString task = "";
 
   // Last synchonization date.. maybe it's useful to know.
   DOMTimeStamp lastSync;
 };
 
 [NavigatorProperty="sync",
  AvailableIn=CertifiedApps,
@@ -28,11 +28,11 @@ dictionary RequestTask : RequestTaskPara
  JSImplementation="@mozilla.org/dom/request-sync-scheduler;1"]
 interface RequestSyncScheduler {
 
   Promise<void> register(USVString task,
                          optional RequestTaskParams params);
   Promise<void> unregister(USVString task);
 
   // Useful methods to get registrations
-  Promise<sequence<RequestTask>> registrations();
-  Promise<RequestTask> registration(USVString task);
+  Promise<sequence<RequestTaskFull>> registrations();
+  Promise<RequestTaskFull> registration(USVString task);
 };