|
1 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
2 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
4 "use strict" |
|
5 |
|
6 let Cc = Components.classes; |
|
7 let Ci = Components.interfaces; |
|
8 |
|
9 Components.utils.import("resource://gre/modules/Services.jsm"); |
|
10 |
|
11 this.EXPORTED_SYMBOLS = ["Notifications"]; |
|
12 |
|
13 function log(msg) { |
|
14 // Services.console.logStringMessage(msg); |
|
15 } |
|
16 |
|
17 var _notificationsMap = {}; |
|
18 |
|
19 function Notification(aId, aOptions) { |
|
20 this._id = aId; |
|
21 this._when = (new Date).getTime(); |
|
22 this.fillWithOptions(aOptions); |
|
23 } |
|
24 |
|
25 Notification.prototype = { |
|
26 fillWithOptions: function(aOptions) { |
|
27 if ("icon" in aOptions && aOptions.icon != null) |
|
28 this._icon = aOptions.icon; |
|
29 else |
|
30 throw "Notification icon is mandatory"; |
|
31 |
|
32 if ("title" in aOptions && aOptions.title != null) |
|
33 this._title = aOptions.title; |
|
34 else |
|
35 throw "Notification title is mandatory"; |
|
36 |
|
37 if ("message" in aOptions && aOptions.message != null) |
|
38 this._message = aOptions.message; |
|
39 else |
|
40 this._message = null; |
|
41 |
|
42 if ("priority" in aOptions && aOptions.priority != null) |
|
43 this._priority = aOptions.priority; |
|
44 |
|
45 if ("buttons" in aOptions && aOptions.buttons != null) { |
|
46 if (aOptions.buttons.length > 3) |
|
47 throw "Too many buttons provided. The max number is 3"; |
|
48 |
|
49 this._buttons = {}; |
|
50 for (let i = 0; i < aOptions.buttons.length; i++) { |
|
51 let button_id = aOptions.buttons[i].buttonId; |
|
52 this._buttons[button_id] = aOptions.buttons[i]; |
|
53 } |
|
54 } else { |
|
55 this._buttons = null; |
|
56 } |
|
57 |
|
58 if ("ongoing" in aOptions && aOptions.ongoing != null) |
|
59 this._ongoing = aOptions.ongoing; |
|
60 else |
|
61 this._ongoing = false; |
|
62 |
|
63 if ("progress" in aOptions && aOptions.progress != null) |
|
64 this._progress = aOptions.progress; |
|
65 else |
|
66 this._progress = null; |
|
67 |
|
68 if ("onCancel" in aOptions && aOptions.onCancel != null) |
|
69 this._onCancel = aOptions.onCancel; |
|
70 else |
|
71 this._onCancel = null; |
|
72 |
|
73 if ("onClick" in aOptions && aOptions.onClick != null) |
|
74 this._onClick = aOptions.onClick; |
|
75 else |
|
76 this._onClick = null; |
|
77 |
|
78 if ("cookie" in aOptions && aOptions.cookie != null) |
|
79 this._cookie = aOptions.cookie; |
|
80 else |
|
81 this._cookie = null; |
|
82 |
|
83 if ("persistent" in aOptions && aOptions.persistent != null) |
|
84 this._persistent = aOptions.persistent; |
|
85 else |
|
86 this._persistent = false; |
|
87 }, |
|
88 |
|
89 show: function() { |
|
90 let msg = { |
|
91 type: "Notification:Show", |
|
92 id: this._id, |
|
93 title: this._title, |
|
94 smallIcon: this._icon, |
|
95 ongoing: this._ongoing, |
|
96 when: this._when, |
|
97 persistent: this._persistent |
|
98 }; |
|
99 |
|
100 if (this._message) |
|
101 msg.text = this._message; |
|
102 |
|
103 if (this._progress) { |
|
104 msg.progress_value = this._progress; |
|
105 msg.progress_max = 100; |
|
106 msg.progress_indeterminate = false; |
|
107 } else if (Number.isNaN(this._progress)) { |
|
108 msg.progress_value = 0; |
|
109 msg.progress_max = 0; |
|
110 msg.progress_indeterminate = true; |
|
111 } |
|
112 |
|
113 if (this._priority) |
|
114 msg.priority = this._priority; |
|
115 |
|
116 if (this._buttons) { |
|
117 msg.actions = []; |
|
118 let buttonName; |
|
119 for (buttonName in this._buttons) { |
|
120 let button = this._buttons[buttonName]; |
|
121 let obj = { |
|
122 buttonId: button.buttonId, |
|
123 title : button.title, |
|
124 icon : button.icon |
|
125 }; |
|
126 msg.actions.push(obj); |
|
127 } |
|
128 } |
|
129 |
|
130 if (this._light) |
|
131 msg.light = this._light; |
|
132 |
|
133 Services.androidBridge.handleGeckoMessage(msg); |
|
134 return this; |
|
135 }, |
|
136 |
|
137 cancel: function() { |
|
138 let msg = { |
|
139 type: "Notification:Hide", |
|
140 id: this._id |
|
141 }; |
|
142 Services.androidBridge.handleGeckoMessage(msg); |
|
143 } |
|
144 } |
|
145 |
|
146 var Notifications = { |
|
147 _initObserver: function() { |
|
148 if (!this._observerAdded) { |
|
149 Services.obs.addObserver(this, "Notification:Event", true); |
|
150 this._observerAdded = true; |
|
151 } |
|
152 }, |
|
153 |
|
154 get idService() { |
|
155 delete this.idService; |
|
156 return this.idService = Cc["@mozilla.org/uuid-generator;1"].getService(Ci.nsIUUIDGenerator); |
|
157 }, |
|
158 |
|
159 create: function notif_notify(aOptions) { |
|
160 this._initObserver(); |
|
161 let id = this.idService.generateUUID().toString(); |
|
162 let notification = new Notification(id, aOptions); |
|
163 _notificationsMap[id] = notification; |
|
164 notification.show(); |
|
165 return id; |
|
166 }, |
|
167 |
|
168 update: function notif_update(aId, aOptions) { |
|
169 let notification = _notificationsMap[aId]; |
|
170 if (!notification) |
|
171 throw "Unknown notification id"; |
|
172 notification.fillWithOptions(aOptions); |
|
173 notification.show(); |
|
174 }, |
|
175 |
|
176 cancel: function notif_cancel(aId) { |
|
177 let notification = _notificationsMap[aId]; |
|
178 if (notification) |
|
179 notification.cancel(); |
|
180 }, |
|
181 |
|
182 observe: function notif_observe(aSubject, aTopic, aData) { |
|
183 let data = JSON.parse(aData); |
|
184 let id = data.id; |
|
185 let notification = _notificationsMap[id]; |
|
186 if (!notification) { |
|
187 Services.console.logStringMessage("Notifications.jsm observe: received unknown event id " + id); |
|
188 return; |
|
189 } |
|
190 |
|
191 switch (data.eventType) { |
|
192 case "notification-clicked": |
|
193 if (notification._onClick) |
|
194 notification._onClick(id, notification._cookie); |
|
195 break; |
|
196 case "notification-button-clicked": { |
|
197 if (!notification._buttons) { |
|
198 Services.console.logStringMessage("Notifications.jsm: received button clicked event but no buttons are available"); |
|
199 break; |
|
200 } |
|
201 |
|
202 let button = notification._buttons[data.buttonId]; |
|
203 if (button) |
|
204 button.onClicked(id, notification._cookie); |
|
205 } |
|
206 break; |
|
207 case "notification-cleared": |
|
208 case "notification-closed": |
|
209 if (notification._onCancel) |
|
210 notification._onCancel(id, notification._cookie); |
|
211 delete _notificationsMap[id]; // since the notification was dismissed, we no longer need to hold a reference. |
|
212 break; |
|
213 } |
|
214 }, |
|
215 |
|
216 QueryInterface: function (aIID) { |
|
217 if (!aIID.equals(Ci.nsISupports) && |
|
218 !aIID.equals(Ci.nsIObserver) && |
|
219 !aIID.equals(Ci.nsISupportsWeakReference)) |
|
220 throw Components.results.NS_ERROR_NO_INTERFACE; |
|
221 return this; |
|
222 } |
|
223 } |