Thu, 22 Jan 2015 13:21:57 +0100
Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6
1 /* Copyright 2012 Mozilla Foundation and Mozilla contributors
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
16 /* Copyright © 2013, Deutsche Telekom, Inc. */
18 "use strict";
20 const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
22 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
23 Cu.import("resource://gre/modules/Services.jsm");
24 Cu.import("resource://gre/modules/DOMRequestHelper.jsm");
26 let NFC = {};
27 Cu.import("resource://gre/modules/nfc_consts.js", NFC);
29 Cu.import("resource://gre/modules/systemlibs.js");
30 const NFC_ENABLED = libcutils.property_get("ro.moz.nfc.enabled", "false") === "true";
32 // set to true to in nfc_consts.js to see debug messages
33 let DEBUG = NFC.DEBUG_CONTENT_HELPER;
35 let debug;
36 if (DEBUG) {
37 debug = function (s) {
38 dump("-*- NfcContentHelper: " + s + "\n");
39 };
40 } else {
41 debug = function (s) {};
42 }
44 const NFCCONTENTHELPER_CID =
45 Components.ID("{4d72c120-da5f-11e1-9b23-0800200c9a66}");
47 const NFC_IPC_MSG_NAMES = [
48 "NFC:ReadNDEFResponse",
49 "NFC:WriteNDEFResponse",
50 "NFC:GetDetailsNDEFResponse",
51 "NFC:MakeReadOnlyNDEFResponse",
52 "NFC:ConnectResponse",
53 "NFC:CloseResponse",
54 "NFC:CheckP2PRegistrationResponse",
55 "NFC:PeerEvent",
56 "NFC:NotifySendFileStatusResponse",
57 "NFC:ConfigResponse"
58 ];
60 XPCOMUtils.defineLazyServiceGetter(this, "cpmm",
61 "@mozilla.org/childprocessmessagemanager;1",
62 "nsISyncMessageSender");
64 function GetDetailsNDEFResponse(details) {
65 this.canBeMadeReadOnly = details.canBeMadeReadOnly;
66 this.isReadOnly = details.isReadOnly;
67 this.maxSupportedLength = details.maxSupportedLength;
68 }
69 GetDetailsNDEFResponse.prototype = {
70 __exposedProps__ : {canBeMadeReadOnly: 'r',
71 isReadOnly: 'r',
72 maxSupportedLength: 'r'}
73 };
75 function NfcContentHelper() {
76 this.initDOMRequestHelper(/* aWindow */ null, NFC_IPC_MSG_NAMES);
77 Services.obs.addObserver(this, "xpcom-shutdown", false);
79 this._requestMap = [];
81 // Maintains an array of PeerEvent related callbacks, mainly
82 // one for 'peerReady' and another for 'peerLost'.
83 this.peerEventsCallbackMap = {};
84 }
86 NfcContentHelper.prototype = {
87 __proto__: DOMRequestIpcHelper.prototype,
89 QueryInterface: XPCOMUtils.generateQI([Ci.nsINfcContentHelper,
90 Ci.nsISupportsWeakReference,
91 Ci.nsIObserver]),
92 classID: NFCCONTENTHELPER_CID,
93 classInfo: XPCOMUtils.generateCI({
94 classID: NFCCONTENTHELPER_CID,
95 classDescription: "NfcContentHelper",
96 interfaces: [Ci.nsINfcContentHelper]
97 }),
99 _requestMap: null,
100 peerEventsCallbackMap: null,
102 encodeNDEFRecords: function encodeNDEFRecords(records) {
103 let encodedRecords = [];
104 for (let i = 0; i < records.length; i++) {
105 let record = records[i];
106 encodedRecords.push({
107 tnf: record.tnf,
108 type: record.type,
109 id: record.id,
110 payload: record.payload,
111 });
112 }
113 return encodedRecords;
114 },
116 // NFC interface:
117 setSessionToken: function setSessionToken(sessionToken) {
118 if (sessionToken == null) {
119 throw Components.Exception("No session token!",
120 Cr.NS_ERROR_UNEXPECTED);
121 return;
122 }
123 // Report session to Nfc.js only.
124 cpmm.sendAsyncMessage("NFC:SetSessionToken", {
125 sessionToken: sessionToken,
126 });
127 },
129 // NFCTag interface
130 getDetailsNDEF: function getDetailsNDEF(window, sessionToken) {
131 if (window == null) {
132 throw Components.Exception("Can't get window object",
133 Cr.NS_ERROR_UNEXPECTED);
134 }
135 let request = Services.DOMRequest.createRequest(window);
136 let requestId = btoa(this.getRequestId(request));
137 this._requestMap[requestId] = window;
139 cpmm.sendAsyncMessage("NFC:GetDetailsNDEF", {
140 requestId: requestId,
141 sessionToken: sessionToken
142 });
143 return request;
144 },
146 readNDEF: function readNDEF(window, sessionToken) {
147 if (window == null) {
148 throw Components.Exception("Can't get window object",
149 Cr.NS_ERROR_UNEXPECTED);
150 }
151 let request = Services.DOMRequest.createRequest(window);
152 let requestId = btoa(this.getRequestId(request));
153 this._requestMap[requestId] = window;
155 cpmm.sendAsyncMessage("NFC:ReadNDEF", {
156 requestId: requestId,
157 sessionToken: sessionToken
158 });
159 return request;
160 },
162 writeNDEF: function writeNDEF(window, records, sessionToken) {
163 if (window == null) {
164 throw Components.Exception("Can't get window object",
165 Cr.NS_ERROR_UNEXPECTED);
166 }
167 let request = Services.DOMRequest.createRequest(window);
168 let requestId = btoa(this.getRequestId(request));
169 this._requestMap[requestId] = window;
171 let encodedRecords = this.encodeNDEFRecords(records);
172 cpmm.sendAsyncMessage("NFC:WriteNDEF", {
173 requestId: requestId,
174 sessionToken: sessionToken,
175 records: encodedRecords
176 });
177 return request;
178 },
180 makeReadOnlyNDEF: function makeReadOnlyNDEF(window, sessionToken) {
181 if (window == null) {
182 throw Components.Exception("Can't get window object",
183 Cr.NS_ERROR_UNEXPECTED);
184 }
186 let request = Services.DOMRequest.createRequest(window);
187 let requestId = btoa(this.getRequestId(request));
188 this._requestMap[requestId] = window;
190 cpmm.sendAsyncMessage("NFC:MakeReadOnlyNDEF", {
191 requestId: requestId,
192 sessionToken: sessionToken
193 });
194 return request;
195 },
197 connect: function connect(window, techType, sessionToken) {
198 if (window == null) {
199 throw Components.Exception("Can't get window object",
200 Cr.NS_ERROR_UNEXPECTED);
201 }
202 let request = Services.DOMRequest.createRequest(window);
203 let requestId = btoa(this.getRequestId(request));
204 this._requestMap[requestId] = window;
206 cpmm.sendAsyncMessage("NFC:Connect", {
207 requestId: requestId,
208 sessionToken: sessionToken,
209 techType: techType
210 });
211 return request;
212 },
214 close: function close(window, sessionToken) {
215 if (window == null) {
216 throw Components.Exception("Can't get window object",
217 Cr.NS_ERROR_UNEXPECTED);
218 }
219 let request = Services.DOMRequest.createRequest(window);
220 let requestId = btoa(this.getRequestId(request));
221 this._requestMap[requestId] = window;
223 cpmm.sendAsyncMessage("NFC:Close", {
224 requestId: requestId,
225 sessionToken: sessionToken
226 });
227 return request;
228 },
230 sendFile: function sendFile(window, data, sessionToken) {
231 if (window == null) {
232 throw Components.Exception("Can't get window object",
233 Cr.NS_ERROR_UNEXPECTED);
234 }
235 let request = Services.DOMRequest.createRequest(window);
236 let requestId = btoa(this.getRequestId(request));
237 this._requestMap[requestId] = window;
239 cpmm.sendAsyncMessage("NFC:SendFile", {
240 requestId: requestId,
241 sessionToken: sessionToken,
242 blob: data.blob
243 });
244 return request;
245 },
247 notifySendFileStatus: function notifySendFileStatus(window, status,
248 requestId) {
249 if (window == null) {
250 throw Components.Exception("Can't get window object",
251 Cr.NS_ERROR_UNEXPECTED);
252 }
254 cpmm.sendAsyncMessage("NFC:NotifySendFileStatus", {
255 status: status,
256 requestId: requestId
257 });
258 },
260 registerTargetForPeerEvent: function registerTargetForPeerEvent(window,
261 appId, event, callback) {
262 if (window == null) {
263 throw Components.Exception("Can't get window object",
264 Cr.NS_ERROR_UNEXPECTED);
265 }
266 this.peerEventsCallbackMap[event] = callback;
267 cpmm.sendAsyncMessage("NFC:RegisterPeerTarget", {
268 appId: appId,
269 event: event
270 });
271 },
273 unregisterTargetForPeerEvent: function unregisterTargetForPeerEvent(window,
274 appId, event) {
275 if (window == null) {
276 throw Components.Exception("Can't get window object",
277 Cr.NS_ERROR_UNEXPECTED);
278 }
279 let callback = this.peerEventsCallbackMap[event];
280 if (callback != null) {
281 delete this.peerEventsCallbackMap[event];
282 }
284 cpmm.sendAsyncMessage("NFC:UnregisterPeerTarget", {
285 appId: appId,
286 event: event
287 });
288 },
290 checkP2PRegistration: function checkP2PRegistration(window, appId) {
291 if (window == null) {
292 throw Components.Exception("Can't get window object",
293 Cr.NS_ERROR_UNEXPECTED);
294 }
295 let request = Services.DOMRequest.createRequest(window);
296 let requestId = btoa(this.getRequestId(request));
297 this._requestMap[requestId] = window;
299 cpmm.sendAsyncMessage("NFC:CheckP2PRegistration", {
300 appId: appId,
301 requestId: requestId
302 });
303 return request;
304 },
306 notifyUserAcceptedP2P: function notifyUserAcceptedP2P(window, appId) {
307 if (window == null) {
308 throw Components.Exception("Can't get window object",
309 Cr.NS_ERROR_UNEXPECTED);
310 }
312 cpmm.sendAsyncMessage("NFC:NotifyUserAcceptedP2P", {
313 appId: appId
314 });
315 },
317 startPoll: function startPoll(window) {
318 if (window == null) {
319 throw Components.Exception("Can't get window object",
320 Cr.NS_ERROR_UNEXPECTED);
321 }
323 let request = Services.DOMRequest.createRequest(window);
324 let requestId = btoa(this.getRequestId(request));
325 this._requestMap[requestId] = window;
327 cpmm.sendAsyncMessage("NFC:StartPoll",
328 {requestId: requestId});
329 return request;
330 },
332 stopPoll: function stopPoll(window) {
333 if (window == null) {
334 throw Components.Exception("Can't get window object",
335 Cr.NS_ERROR_UNEXPECTED);
336 }
338 let request = Services.DOMRequest.createRequest(window);
339 let requestId = btoa(this.getRequestId(request));
340 this._requestMap[requestId] = window;
342 cpmm.sendAsyncMessage("NFC:StopPoll",
343 {requestId: requestId});
344 return request;
345 },
347 powerOff: function powerOff(window) {
348 if (window == null) {
349 throw Components.Exception("Can't get window object",
350 Cr.NS_ERROR_UNEXPECTED);
351 }
353 let request = Services.DOMRequest.createRequest(window);
354 let requestId = btoa(this.getRequestId(request));
355 this._requestMap[requestId] = window;
357 cpmm.sendAsyncMessage("NFC:PowerOff",
358 {requestId: requestId});
359 return request;
360 },
362 // nsIObserver
363 observe: function observe(subject, topic, data) {
364 if (topic == "xpcom-shutdown") {
365 this.destroyDOMRequestHelper();
366 Services.obs.removeObserver(this, "xpcom-shutdown");
367 cpmm = null;
368 }
369 },
371 // nsIMessageListener
373 fireRequestSuccess: function fireRequestSuccess(requestId, result) {
374 let request = this.takeRequest(requestId);
375 if (!request) {
376 debug("not firing success for id: " + requestId +
377 ", result: " + JSON.stringify(result));
378 return;
379 }
381 debug("fire request success, id: " + requestId +
382 ", result: " + JSON.stringify(result));
383 Services.DOMRequest.fireSuccess(request, result);
384 },
386 fireRequestError: function fireRequestError(requestId, error) {
387 let request = this.takeRequest(requestId);
388 if (!request) {
389 debug("not firing error for id: " + requestId +
390 ", error: " + JSON.stringify(error));
391 return;
392 }
394 debug("fire request error, id: " + requestId +
395 ", result: " + JSON.stringify(error));
396 Services.DOMRequest.fireError(request, error);
397 },
399 receiveMessage: function receiveMessage(message) {
400 debug("Message received: " + JSON.stringify(message));
401 let result = message.json;
403 switch (message.name) {
404 case "NFC:ReadNDEFResponse":
405 this.handleReadNDEFResponse(result);
406 break;
407 case "NFC:GetDetailsNDEFResponse":
408 this.handleGetDetailsNDEFResponse(result);
409 break;
410 case "NFC:ConnectResponse": // Fall through.
411 case "NFC:CloseResponse":
412 case "NFC:WriteNDEFResponse":
413 case "NFC:MakeReadOnlyNDEFResponse":
414 case "NFC:CheckP2PRegistrationResponse":
415 case "NFC:NotifySendFileStatusResponse":
416 case "NFC:ConfigResponse":
417 if (result.status !== NFC.GECKO_NFC_ERROR_SUCCESS) {
418 this.fireRequestError(atob(result.requestId), result.status);
419 } else {
420 this.fireRequestSuccess(atob(result.requestId), result);
421 }
422 break;
423 case "NFC:PeerEvent":
424 let callback = this.peerEventsCallbackMap[result.event];
425 if (callback) {
426 callback.peerNotification(result.event, result.sessionToken);
427 } else {
428 debug("PeerEvent: No valid callback registered for the event " +
429 result.event);
430 }
431 break;
432 }
433 },
435 handleReadNDEFResponse: function handleReadNDEFResponse(result) {
436 let requester = this._requestMap[result.requestId];
437 if (!requester) {
438 debug("Response Invalid requestId=" + result.requestId);
439 return;
440 }
441 delete this._requestMap[result.requestId];
443 if (result.status !== NFC.GECKO_NFC_ERROR_SUCCESS) {
444 this.fireRequestError(atob(result.requestId), result.status);
445 return;
446 }
448 let requestId = atob(result.requestId);
449 let ndefMsg = [];
450 let records = result.records;
451 for (let i = 0; i < records.length; i++) {
452 let record = records[i];
453 ndefMsg.push(new requester.MozNDEFRecord(record.tnf,
454 record.type,
455 record.id,
456 record.payload));
457 }
458 this.fireRequestSuccess(requestId, ndefMsg);
459 },
461 handleGetDetailsNDEFResponse: function handleGetDetailsNDEFResponse(result) {
462 if (result.status !== NFC.GECKO_NFC_ERROR_SUCCESS) {
463 this.fireRequestError(atob(result.requestId), result.status);
464 return;
465 }
467 let requestId = atob(result.requestId);
468 let result = new GetDetailsNDEFResponse(result);
469 this.fireRequestSuccess(requestId, result);
470 },
471 };
473 if (NFC_ENABLED) {
474 this.NSGetFactory = XPCOMUtils.generateNSGetFactory([NfcContentHelper]);
475 }