☠☠ backed out by c86aa20289a4 ☠ ☠ | |
author | Gene Lian <clian@mozilla.com> |
Fri, 22 Jun 2012 15:39:07 +0800 | |
changeset 102981 | 1dba66cfad9ab1aac43a7a1dec8f219192f9566b |
parent 102980 | ed768b821da17bed5d0f932fa3b81b43f29ed9fb |
child 102982 | dbd41e244549492fbc354c7c1667c406db6fd781 |
push id | 1316 |
push user | akeybl@mozilla.com |
push date | Mon, 27 Aug 2012 22:37:00 +0000 |
treeherder | mozilla-beta@db4b09302ee2 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | vivien |
bugs | 749551 |
milestone | 16.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
|
--- a/b2g/chrome/content/shell.js +++ b/b2g/chrome/content/shell.js @@ -9,16 +9,17 @@ const Ci = Components.interfaces; const Cu = Components.utils; const Cr = Components.results; Cu.import('resource://gre/modules/XPCOMUtils.jsm'); Cu.import('resource://gre/modules/Services.jsm'); Cu.import('resource://gre/modules/ContactService.jsm'); Cu.import('resource://gre/modules/SettingsChangeNotifier.jsm'); Cu.import('resource://gre/modules/Webapps.jsm'); +Cu.import('resource://gre/modules/AlarmService.jsm'); XPCOMUtils.defineLazyServiceGetter(Services, 'env', '@mozilla.org/process/environment;1', 'nsIEnvironment'); XPCOMUtils.defineLazyServiceGetter(Services, 'ss', '@mozilla.org/content/style-sheet-service;1', 'nsIStyleSheetService');
new file mode 100644 --- /dev/null +++ b/dom/alarm/AlarmService.jsm @@ -0,0 +1,299 @@ +/* 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"; + +/* static functions */ +const DEBUG = false; + +function debug(aStr) { + if (DEBUG) + dump("AlarmService: " + aStr + "\n"); +} + +const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components; + +Cu.import("resource://gre/modules/XPCOMUtils.jsm"); +Cu.import("resource://gre/modules/Services.jsm"); +Cu.import("resource://gre/modules/AlarmDB.jsm"); + +let EXPORTED_SYMBOLS = ["AlarmService"]; + +XPCOMUtils.defineLazyGetter(this, "ppmm", function() { + return Cc["@mozilla.org/parentprocessmessagemanager;1"].getService(Ci.nsIFrameMessageManager); +}); + +let myGlobal = this; + +let AlarmService = { + init: function init() { + debug("init()"); + + this._currentTimezoneOffset = (new Date()).getTimezoneOffset(); + + let alarmHalService = this._alarmHalService = Cc["@mozilla.org/alarmHalService;1"].getService(Ci.nsIAlarmHalService); + alarmHalService.setAlarmFiredCb(this._onAlarmFired.bind(this)); + alarmHalService.setTimezoneChangedCb(this._onTimezoneChanged.bind(this)); + + // add the messages to be listened + const messages = ["AlarmsManager:GetAll", "AlarmsManager:Add", "AlarmsManager:Remove"]; + messages.forEach(function addMessage(msgName) { + ppmm.addMessageListener(msgName, this); + }.bind(this)); + + // set the indexeddb database + let idbManager = Components.classes["@mozilla.org/dom/indexeddb/manager;1"].getService(Ci.nsIIndexedDatabaseManager); + idbManager.initWindowless(myGlobal); + this._db = new AlarmDB(myGlobal); + this._db.init(myGlobal); + + // variable to save alarms waiting to be set + this._alarmQueue = []; + + this._restoreAlarmsFromDb(); + }, + + // getter/setter to access the current alarm set in system + _alarm: null, + get _currentAlarm() { + return this._alarm; + }, + set _currentAlarm(aAlarm) { + this._alarm = aAlarm; + if (!aAlarm) + return; + + if (!this._alarmHalService.setAlarm(this._getAlarmTime(aAlarm) / 1000, 0)) + throw Components.results.NS_ERROR_FAILURE; + }, + + receiveMessage: function receiveMessage(aMessage) { + debug("receiveMessage(): " + aMessage.name); + + let json = aMessage.json; + switch (aMessage.name) { + case "AlarmsManager:GetAll": + this._db.getAll( + function getAllSuccessCb(aAlarms) { + debug("Callback after getting alarms from database: " + JSON.stringify(aAlarms)); + ppmm.sendAsyncMessage( + "AlarmsManager:GetAll:Return:OK", + { requestID: json.requestID, alarms: aAlarms } + ); + }.bind(this), + function getAllErrorCb(aErrorMsg) { + ppmm.sendAsyncMessage( + "AlarmsManager:GetAll:Return:KO", + { requestID: json.requestID, errorMsg: aErrorMsg } + ); + }.bind(this) + ); + break; + + case "AlarmsManager:Add": + // prepare a record for the new alarm to be added + let newAlarm = { + date: json.date, + ignoreTimezone: json.ignoreTimezone, + timezoneOffset: this._currentTimezoneOffset, + data: json.data + }; + + this._db.add( + newAlarm, + function addSuccessCb(aNewId) { + debug("Callback after adding alarm in database."); + + newAlarm['id'] = aNewId; + let newAlarmTime = this._getAlarmTime(newAlarm); + + if (newAlarmTime <= Date.now()) { + debug("Adding a alarm that has past time. Don't set it in system."); + this._debugCurrentAlarm(); + return; + } + + // if there is no alarm being set in system, set the new alarm + if (this._currentAlarm == null) { + this._currentAlarm = newAlarm; + this._debugCurrentAlarm(); + return; + } + + // if the new alarm is earlier than the current alarm + // swap them and push the previous alarm back to queue + let alarmQueue = this._alarmQueue; + let currentAlarmTime = this._getAlarmTime(this._currentAlarm); + if (newAlarmTime < currentAlarmTime) { + alarmQueue.unshift(this._currentAlarm); + this._currentAlarm = newAlarm; + this._debugCurrentAlarm(); + return; + } + + //push the new alarm in the queue + alarmQueue.push(newAlarm); + alarmQueue.sort(this._sortAlarmByTimeStamps.bind(this)); + this._debugCurrentAlarm(); + + ppmm.sendAsyncMessage( + "AlarmsManager:Add:Return:OK", + { requestID: json.requestID, id: aNewId } + ); + }.bind(this), + function addErrorCb(aErrorMsg) { + ppmm.sendAsyncMessage( + "AlarmsManager:Add:Return:KO", + { requestID: json.requestID, errorMsg: aErrorMsg } + ); + }.bind(this) + ); + break; + + case "AlarmsManager:Remove": + this._db.remove( + json.id, + function removeSuccessCb() { + debug("Callback after removing alarm from database."); + + // if there is no alarm being set + if (!this._currentAlarm) { + this._debugCurrentAlarm(); + return; + } + + // check if the alarm to be removed is in the queue + let alarmQueue = this._alarmQueue; + if (this._currentAlarm.id != json.id) { + for (let i = 0; i < alarmQueue.length; i++) { + if (alarmQueue[i].id == json.id) { + alarmQueue.splice(i, 1); + break; + } + } + this._debugCurrentAlarm(); + return; + } + + // the alarm to be removed is the current alarm + // reset the next alarm from queue if any + if (alarmQueue.length) { + this._currentAlarm = alarmQueue.shift(); + this._debugCurrentAlarm(); + return; + } + + // no alarm waiting to be set in the queue + this._currentAlarm = null; + this._debugCurrentAlarm(); + }.bind(this), + function removeErrorCb(aErrorMsg) { + throw Components.results.NS_ERROR_NOT_IMPLEMENTED; + } + ); + break; + + default: + throw Components.results.NS_ERROR_NOT_IMPLEMENTED; + break; + } + }, + + _onAlarmFired: function _onAlarmFired() { + debug("_onAlarmFired()"); + + if (this._currentAlarm) { + debug("Fire system intent: " + JSON.stringify(this._currentAlarm)); + // TODO Fire a system message, see bug 755245 + this._currentAlarm = null; + } + + // reset the next alarm from the queue + let nowTime = Date.now(); + let alarmQueue = this._alarmQueue; + while (alarmQueue.length > 0) { + let nextAlarm = alarmQueue.shift(); + let nextAlarmTime = this._getAlarmTime(nextAlarm); + + // if the next alarm has been expired, directly + // fire system intent for it instead of setting it + if (nextAlarmTime <= nowTime) { + debug("Fire system intent: " + JSON.stringify(nextAlarm)); + // TODO Fire a system message, see bug 755245 + } else { + this._currentAlarm = nextAlarm; + break; + } + } + this._debugCurrentAlarm(); + }, + + _onTimezoneChanged: function _onTimezoneChanged(aTimezoneOffset) { + debug("_onTimezoneChanged()"); + + this._currentTimezoneOffset = aTimezoneOffset; + this._restoreAlarmsFromDb(); + }, + + _restoreAlarmsFromDb: function _restoreAlarmsFromDb() { + debug("_restoreAlarmsFromDb()"); + + this._db.getAll( + function getAllSuccessCb(aAlarms) { + debug("Callback after getting alarms from database: " + JSON.stringify(aAlarms)); + + // clear any alarms set or queued in the cache + let alarmQueue = this._alarmQueue; + alarmQueue.length = 0; + this._currentAlarm = null; + + // only add the alarm that is valid + let nowTime = Date.now(); + aAlarms.forEach(function addAlarm(aAlarm) { + if (this._getAlarmTime(aAlarm) > nowTime) + alarmQueue.push(aAlarm); + }.bind(this)); + + // set the next alarm from queue + if (alarmQueue.length) { + alarmQueue.sort(this._sortAlarmByTimeStamps.bind(this)); + this._currentAlarm = alarmQueue.shift(); + } + + this._debugCurrentAlarm(); + }.bind(this), + function getAllErrorCb(aErrorMsg) { + throw Components.results.NS_ERROR_NOT_IMPLEMENTED; + } + ); + }, + + _getAlarmTime: function _getAlarmTime(aAlarm) { + let alarmTime = (new Date(aAlarm.date)).getTime(); + + // For an alarm specified with "ignoreTimezone", + // it must be fired respect to the user's timezone. + // Supposing an alarm was set at 7:00pm at Tokyo, + // it must be gone off at 7:00pm respect to Paris' + // local time when the user is located at Paris. + // We can adjust the alarm UTC time by calculating + // the difference of the orginal timezone and the + // current timezone. + if (aAlarm.ignoreTimezone) + alarmTime += (this._currentTimezoneOffset - aAlarm.timezoneOffset) * 60000; + + return alarmTime; + }, + + _sortAlarmByTimeStamps: function _sortAlarmByTimeStamps(aAlarm1, aAlarm2) { + return this._getAlarmTime(aAlarm1) - this._getAlarmTime(aAlarm2); + }, + + _debugCurrentAlarm: function _debugCurrentAlarm() { + debug("Current alarm: " + JSON.stringify(this._currentAlarm)); + debug("Alarm queue: " + JSON.stringify(this._alarmQueue)); + }, +} + +AlarmService.init();
--- a/dom/alarm/AlarmsManager.js +++ b/dom/alarm/AlarmsManager.js @@ -1,27 +1,36 @@ /* 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"; +/* static functions */ +const DEBUG = false; + +function debug(aStr) { + if (DEBUG) + dump("AlarmsManager: " + aStr + "\n"); +} + const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components; Cu.import("resource://gre/modules/XPCOMUtils.jsm"); Cu.import("resource://gre/modules/Services.jsm"); Cu.import("resource://gre/modules/DOMRequestHelper.jsm"); const ALARMSMANAGER_CONTRACTID = "@mozilla.org/alarmsManager;1"; const ALARMSMANAGER_CID = Components.ID("{fea1e884-9b05-11e1-9b64-87a7016c3860}"); const nsIDOMMozAlarmsManager = Ci.nsIDOMMozAlarmsManager; const nsIClassInfo = Ci.nsIClassInfo; function AlarmsManager() { + debug("Constructor"); } AlarmsManager.prototype = { __proto__: DOMRequestIpcHelper.prototype, classID : ALARMSMANAGER_CID, @@ -29,47 +38,122 @@ AlarmsManager.prototype = { classInfo : XPCOMUtils.generateCI({ classID: ALARMSMANAGER_CID, contractID: ALARMSMANAGER_CONTRACTID, classDescription: "AlarmsManager", interfaces: [nsIDOMMozAlarmsManager], flags: nsIClassInfo.DOM_OBJECT }), add: function add(aDate, aRespectTimezone, aData) { - return null; + debug("add()"); + + let isIgnoreTimezone = true; + switch (aRespectTimezone) { + case "honorTimezone": + isIgnoreTimezone = false; + break; + + case "ignoreTimezone": + isIgnoreTimezone = true; + break; + + default: + throw Components.results.NS_ERROR_NOT_IMPLEMENTED; + break; + } + + let request = this.createRequest(); + this._cpmm.sendAsyncMessage( + "AlarmsManager:Add", + { requestID: this.getRequestId(request), date: aDate, ignoreTimezone: isIgnoreTimezone, data: aData } + ); + return request; }, remove: function remove(aId) { - return; + debug("remove()"); + + return this._cpmm.sendSyncMessage( + "AlarmsManager:Remove", + { id: aId } + ); }, getAll: function getAll() { - return null; + debug("getAll()"); + + let request = this.createRequest(); + this._cpmm.sendAsyncMessage( + "AlarmsManager:GetAll", + { requestID: this.getRequestId(request) } + ); + return request; }, + receiveMessage: function receiveMessage(aMessage) { + debug("receiveMessage(): " + aMessage.name); + + let json = aMessage.json; + let request = this.getRequest(json.requestID); + + if (!request) { + debug("No request stored! " + json.requestID); + return; + } + + switch (aMessage.name) { + case "AlarmsManager:Add:Return:OK": + Services.DOMRequest.fireSuccess(request, json.id); + break; + + case "AlarmsManager:GetAll:Return:OK": + Services.DOMRequest.fireSuccess(request, json.alarms); + break; + + case "AlarmsManager:Add:Return:KO": + Services.DOMRequest.fireError(request, json.errorMsg); + break; + + case "AlarmsManager:GetAll:Return:KO": + Services.DOMRequest.fireError(request, json.errorMsg); + break; + + default: + debug("Wrong message: " + aMessage.name); + break; + } + this.removeRequest(json.requestID); + }, + // nsIDOMGlobalPropertyInitializer implementation init: function init(aWindow) { + debug("init()"); + // Set navigator.mozAlarms to null. if (!Services.prefs.getBoolPref("dom.mozAlarms.enabled")) return null; let principal = aWindow.document.nodePrincipal; let secMan = Cc["@mozilla.org/scriptsecuritymanager;1"].getService(Ci.nsIScriptSecurityManager); let perm = principal == secMan.getSystemPrincipal() ? Ci.nsIPermissionManager.ALLOW_ACTION : Services.perms.testExactPermission(principal.URI, "alarms"); // Only pages with perm set can use the alarms. this.hasPrivileges = perm == Ci.nsIPermissionManager.ALLOW_ACTION; if (!this.hasPrivileges) return null; + this._cpmm = Cc["@mozilla.org/childprocessmessagemanager;1"].getService(Ci.nsISyncMessageSender); + // Add the valid messages to be listened. - this.initHelper(aWindow, []); + this.initHelper(aWindow, ["AlarmsManager:Add:Return:OK", "AlarmsManager:Add:Return:KO", + "AlarmsManager:GetAll:Return:OK", "AlarmsManager:GetAll:Return:KO"]); }, // Called from DOMRequestIpcHelper. uninit: function uninit() { + debug("uninit()"); }, } const NSGetFactory = XPCOMUtils.generateNSGetFactory([AlarmsManager])
--- a/dom/alarm/Makefile.in +++ b/dom/alarm/Makefile.in @@ -22,16 +22,17 @@ EXPORTS_NAMESPACES = mozilla/dom/alarm EXTRA_COMPONENTS = \ AlarmsManager.js \ AlarmsManager.manifest \ $(NULL) EXTRA_JS_MODULES = \ AlarmDB.jsm \ + AlarmService.jsm \ $(NULL) XPIDLSRCS = \ nsIDOMAlarmsManager.idl \ nsIAlarmHalService.idl \ $(NULL) EXPORTS_mozilla/dom/alarm = \