diff options
Diffstat (limited to 'mobile/android/modules/Notifications.jsm')
-rw-r--r-- | mobile/android/modules/Notifications.jsm | 259 |
1 files changed, 259 insertions, 0 deletions
diff --git a/mobile/android/modules/Notifications.jsm b/mobile/android/modules/Notifications.jsm new file mode 100644 index 000000000..a035bb2e3 --- /dev/null +++ b/mobile/android/modules/Notifications.jsm @@ -0,0 +1,259 @@ +/* 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"; + +const { classes: Cc, interfaces: Ci, utils: Cu } = Components; + +Cu.import("resource://gre/modules/Services.jsm"); + +this.EXPORTED_SYMBOLS = ["Notifications"]; + +function log(msg) { + // Services.console.logStringMessage(msg); +} + +var _notificationsMap = {}; +var _handlersMap = {}; + +function Notification(aId, aOptions) { + this._id = aId; + this._when = (new Date()).getTime(); + this.fillWithOptions(aOptions); +} + +Notification.prototype = { + fillWithOptions: function(aOptions) { + if ("icon" in aOptions && aOptions.icon != null) + this._icon = aOptions.icon; + else + throw "Notification icon is mandatory"; + + if ("title" in aOptions && aOptions.title != null) + this._title = aOptions.title; + else + throw "Notification title is mandatory"; + + if ("message" in aOptions && aOptions.message != null) + this._message = aOptions.message; + else + this._message = null; + + if ("priority" in aOptions && aOptions.priority != null) + this._priority = aOptions.priority; + + if ("buttons" in aOptions && aOptions.buttons != null) { + if (aOptions.buttons.length > 3) + throw "Too many buttons provided. The max number is 3"; + + this._buttons = {}; + for (let i = 0; i < aOptions.buttons.length; i++) { + let button_id = aOptions.buttons[i].buttonId; + this._buttons[button_id] = aOptions.buttons[i]; + } + } else { + this._buttons = null; + } + + if ("ongoing" in aOptions && aOptions.ongoing != null) + this._ongoing = aOptions.ongoing; + else + this._ongoing = false; + + if ("progress" in aOptions && aOptions.progress != null) + this._progress = aOptions.progress; + else + this._progress = null; + + if ("onCancel" in aOptions && aOptions.onCancel != null) + this._onCancel = aOptions.onCancel; + else + this._onCancel = null; + + if ("onClick" in aOptions && aOptions.onClick != null) + this._onClick = aOptions.onClick; + else + this._onClick = null; + + if ("cookie" in aOptions && aOptions.cookie != null) + this._cookie = aOptions.cookie; + else + this._cookie = null; + + if ("handlerKey" in aOptions && aOptions.handlerKey != null) + this._handlerKey = aOptions.handlerKey; + + if ("persistent" in aOptions && aOptions.persistent != null) + this._persistent = aOptions.persistent; + else + this._persistent = false; + }, + + show: function() { + let msg = { + type: "Notification:Show", + id: this._id, + title: this._title, + smallIcon: this._icon, + ongoing: this._ongoing, + when: this._when, + persistent: this._persistent, + }; + + if (this._message) + msg.text = this._message; + + if (this._progress) { + msg.progress_value = this._progress; + msg.progress_max = 100; + msg.progress_indeterminate = false; + } else if (Number.isNaN(this._progress)) { + msg.progress_value = 0; + msg.progress_max = 0; + msg.progress_indeterminate = true; + } + + if (this._cookie) + msg.cookie = JSON.stringify(this._cookie); + + if (this._priority) + msg.priority = this._priority; + + if (this._buttons) { + msg.actions = []; + let buttonName; + for (buttonName in this._buttons) { + let button = this._buttons[buttonName]; + let obj = { + buttonId: button.buttonId, + title : button.title, + icon : button.icon + }; + msg.actions.push(obj); + } + } + + if (this._light) + msg.light = this._light; + + if (this._handlerKey) + msg.handlerKey = this._handlerKey; + + Services.androidBridge.handleGeckoMessage(msg); + return this; + }, + + cancel: function() { + let msg = { + type: "Notification:Hide", + id: this._id, + handlerKey: this._handlerKey, + cookie: JSON.stringify(this._cookie), + }; + Services.androidBridge.handleGeckoMessage(msg); + } +} + +var Notifications = { + get idService() { + delete this.idService; + return this.idService = Cc["@mozilla.org/uuid-generator;1"].getService(Ci.nsIUUIDGenerator); + }, + + registerHandler: function(key, handler) { + if (!_handlersMap[key]) { + _handlersMap[key] = []; + } + _handlersMap[key].push(handler); + }, + + unregisterHandler: function(key, handler) { + let h = _handlersMap[key]; + if (!h) { + return; + } + let i = h.indexOf(handler); + if (i > -1) { + h.splice(i, 1); + } + }, + + create: function notif_notify(aOptions) { + let id = this.idService.generateUUID().toString(); + + let notification = new Notification(id, aOptions); + _notificationsMap[id] = notification; + notification.show(); + + return id; + }, + + update: function notif_update(aId, aOptions) { + let notification = _notificationsMap[aId]; + if (!notification) + throw "Unknown notification id"; + notification.fillWithOptions(aOptions); + notification.show(); + }, + + cancel: function notif_cancel(aId) { + let notification = _notificationsMap[aId]; + if (notification) + notification.cancel(); + }, + + observe: function notif_observe(aSubject, aTopic, aData) { + Services.console.logStringMessage(aTopic + " " + aData); + + let data = JSON.parse(aData); + let id = data.id; + let handlerKey = data.handlerKey; + let cookie = data.cookie ? JSON.parse(data.cookie) : undefined; + let notification = _notificationsMap[id]; + + switch (data.eventType) { + case "notification-clicked": + if (notification && notification._onClick) + notification._onClick(id, notification._cookie); + + if (handlerKey) { + _handlersMap[handlerKey].forEach(function(handler) { + handler.onClick(cookie); + }); + } + + break; + case "notification-button-clicked": + if (handlerKey) { + _handlersMap[handlerKey].forEach(function(handler) { + handler.onButtonClick(data.buttonId, cookie); + }); + } + + break; + case "notification-cleared": + case "notification-closed": + if (handlerKey) { + _handlersMap[handlerKey].forEach(function(handler) { + handler.onCancel(cookie); + }); + } + + if (notification && notification._onCancel) + notification._onCancel(id, notification._cookie); + delete _notificationsMap[id]; // since the notification was dismissed, we no longer need to hold a reference. + break; + } + }, + + QueryInterface: function (aIID) { + if (!aIID.equals(Ci.nsISupports) && + !aIID.equals(Ci.nsIObserver) && + !aIID.equals(Ci.nsISupportsWeakReference)) + throw Components.results.NS_ERROR_NO_INTERFACE; + return this; + } +}; + +Services.obs.addObserver(Notifications, "Notification:Event", false); |