1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/dom/system/gonk/NfcContentHelper.js Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,475 @@ 1.4 +/* Copyright 2012 Mozilla Foundation and Mozilla contributors 1.5 + * 1.6 + * Licensed under the Apache License, Version 2.0 (the "License"); 1.7 + * you may not use this file except in compliance with the License. 1.8 + * You may obtain a copy of the License at 1.9 + * 1.10 + * http://www.apache.org/licenses/LICENSE-2.0 1.11 + * 1.12 + * Unless required by applicable law or agreed to in writing, software 1.13 + * distributed under the License is distributed on an "AS IS" BASIS, 1.14 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1.15 + * See the License for the specific language governing permissions and 1.16 + * limitations under the License. 1.17 + */ 1.18 + 1.19 +/* Copyright © 2013, Deutsche Telekom, Inc. */ 1.20 + 1.21 +"use strict"; 1.22 + 1.23 +const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; 1.24 + 1.25 +Cu.import("resource://gre/modules/XPCOMUtils.jsm"); 1.26 +Cu.import("resource://gre/modules/Services.jsm"); 1.27 +Cu.import("resource://gre/modules/DOMRequestHelper.jsm"); 1.28 + 1.29 +let NFC = {}; 1.30 +Cu.import("resource://gre/modules/nfc_consts.js", NFC); 1.31 + 1.32 +Cu.import("resource://gre/modules/systemlibs.js"); 1.33 +const NFC_ENABLED = libcutils.property_get("ro.moz.nfc.enabled", "false") === "true"; 1.34 + 1.35 +// set to true to in nfc_consts.js to see debug messages 1.36 +let DEBUG = NFC.DEBUG_CONTENT_HELPER; 1.37 + 1.38 +let debug; 1.39 +if (DEBUG) { 1.40 + debug = function (s) { 1.41 + dump("-*- NfcContentHelper: " + s + "\n"); 1.42 + }; 1.43 +} else { 1.44 + debug = function (s) {}; 1.45 +} 1.46 + 1.47 +const NFCCONTENTHELPER_CID = 1.48 + Components.ID("{4d72c120-da5f-11e1-9b23-0800200c9a66}"); 1.49 + 1.50 +const NFC_IPC_MSG_NAMES = [ 1.51 + "NFC:ReadNDEFResponse", 1.52 + "NFC:WriteNDEFResponse", 1.53 + "NFC:GetDetailsNDEFResponse", 1.54 + "NFC:MakeReadOnlyNDEFResponse", 1.55 + "NFC:ConnectResponse", 1.56 + "NFC:CloseResponse", 1.57 + "NFC:CheckP2PRegistrationResponse", 1.58 + "NFC:PeerEvent", 1.59 + "NFC:NotifySendFileStatusResponse", 1.60 + "NFC:ConfigResponse" 1.61 +]; 1.62 + 1.63 +XPCOMUtils.defineLazyServiceGetter(this, "cpmm", 1.64 + "@mozilla.org/childprocessmessagemanager;1", 1.65 + "nsISyncMessageSender"); 1.66 + 1.67 +function GetDetailsNDEFResponse(details) { 1.68 + this.canBeMadeReadOnly = details.canBeMadeReadOnly; 1.69 + this.isReadOnly = details.isReadOnly; 1.70 + this.maxSupportedLength = details.maxSupportedLength; 1.71 +} 1.72 +GetDetailsNDEFResponse.prototype = { 1.73 + __exposedProps__ : {canBeMadeReadOnly: 'r', 1.74 + isReadOnly: 'r', 1.75 + maxSupportedLength: 'r'} 1.76 +}; 1.77 + 1.78 +function NfcContentHelper() { 1.79 + this.initDOMRequestHelper(/* aWindow */ null, NFC_IPC_MSG_NAMES); 1.80 + Services.obs.addObserver(this, "xpcom-shutdown", false); 1.81 + 1.82 + this._requestMap = []; 1.83 + 1.84 + // Maintains an array of PeerEvent related callbacks, mainly 1.85 + // one for 'peerReady' and another for 'peerLost'. 1.86 + this.peerEventsCallbackMap = {}; 1.87 +} 1.88 + 1.89 +NfcContentHelper.prototype = { 1.90 + __proto__: DOMRequestIpcHelper.prototype, 1.91 + 1.92 + QueryInterface: XPCOMUtils.generateQI([Ci.nsINfcContentHelper, 1.93 + Ci.nsISupportsWeakReference, 1.94 + Ci.nsIObserver]), 1.95 + classID: NFCCONTENTHELPER_CID, 1.96 + classInfo: XPCOMUtils.generateCI({ 1.97 + classID: NFCCONTENTHELPER_CID, 1.98 + classDescription: "NfcContentHelper", 1.99 + interfaces: [Ci.nsINfcContentHelper] 1.100 + }), 1.101 + 1.102 + _requestMap: null, 1.103 + peerEventsCallbackMap: null, 1.104 + 1.105 + encodeNDEFRecords: function encodeNDEFRecords(records) { 1.106 + let encodedRecords = []; 1.107 + for (let i = 0; i < records.length; i++) { 1.108 + let record = records[i]; 1.109 + encodedRecords.push({ 1.110 + tnf: record.tnf, 1.111 + type: record.type, 1.112 + id: record.id, 1.113 + payload: record.payload, 1.114 + }); 1.115 + } 1.116 + return encodedRecords; 1.117 + }, 1.118 + 1.119 + // NFC interface: 1.120 + setSessionToken: function setSessionToken(sessionToken) { 1.121 + if (sessionToken == null) { 1.122 + throw Components.Exception("No session token!", 1.123 + Cr.NS_ERROR_UNEXPECTED); 1.124 + return; 1.125 + } 1.126 + // Report session to Nfc.js only. 1.127 + cpmm.sendAsyncMessage("NFC:SetSessionToken", { 1.128 + sessionToken: sessionToken, 1.129 + }); 1.130 + }, 1.131 + 1.132 + // NFCTag interface 1.133 + getDetailsNDEF: function getDetailsNDEF(window, sessionToken) { 1.134 + if (window == null) { 1.135 + throw Components.Exception("Can't get window object", 1.136 + Cr.NS_ERROR_UNEXPECTED); 1.137 + } 1.138 + let request = Services.DOMRequest.createRequest(window); 1.139 + let requestId = btoa(this.getRequestId(request)); 1.140 + this._requestMap[requestId] = window; 1.141 + 1.142 + cpmm.sendAsyncMessage("NFC:GetDetailsNDEF", { 1.143 + requestId: requestId, 1.144 + sessionToken: sessionToken 1.145 + }); 1.146 + return request; 1.147 + }, 1.148 + 1.149 + readNDEF: function readNDEF(window, sessionToken) { 1.150 + if (window == null) { 1.151 + throw Components.Exception("Can't get window object", 1.152 + Cr.NS_ERROR_UNEXPECTED); 1.153 + } 1.154 + let request = Services.DOMRequest.createRequest(window); 1.155 + let requestId = btoa(this.getRequestId(request)); 1.156 + this._requestMap[requestId] = window; 1.157 + 1.158 + cpmm.sendAsyncMessage("NFC:ReadNDEF", { 1.159 + requestId: requestId, 1.160 + sessionToken: sessionToken 1.161 + }); 1.162 + return request; 1.163 + }, 1.164 + 1.165 + writeNDEF: function writeNDEF(window, records, sessionToken) { 1.166 + if (window == null) { 1.167 + throw Components.Exception("Can't get window object", 1.168 + Cr.NS_ERROR_UNEXPECTED); 1.169 + } 1.170 + let request = Services.DOMRequest.createRequest(window); 1.171 + let requestId = btoa(this.getRequestId(request)); 1.172 + this._requestMap[requestId] = window; 1.173 + 1.174 + let encodedRecords = this.encodeNDEFRecords(records); 1.175 + cpmm.sendAsyncMessage("NFC:WriteNDEF", { 1.176 + requestId: requestId, 1.177 + sessionToken: sessionToken, 1.178 + records: encodedRecords 1.179 + }); 1.180 + return request; 1.181 + }, 1.182 + 1.183 + makeReadOnlyNDEF: function makeReadOnlyNDEF(window, sessionToken) { 1.184 + if (window == null) { 1.185 + throw Components.Exception("Can't get window object", 1.186 + Cr.NS_ERROR_UNEXPECTED); 1.187 + } 1.188 + 1.189 + let request = Services.DOMRequest.createRequest(window); 1.190 + let requestId = btoa(this.getRequestId(request)); 1.191 + this._requestMap[requestId] = window; 1.192 + 1.193 + cpmm.sendAsyncMessage("NFC:MakeReadOnlyNDEF", { 1.194 + requestId: requestId, 1.195 + sessionToken: sessionToken 1.196 + }); 1.197 + return request; 1.198 + }, 1.199 + 1.200 + connect: function connect(window, techType, sessionToken) { 1.201 + if (window == null) { 1.202 + throw Components.Exception("Can't get window object", 1.203 + Cr.NS_ERROR_UNEXPECTED); 1.204 + } 1.205 + let request = Services.DOMRequest.createRequest(window); 1.206 + let requestId = btoa(this.getRequestId(request)); 1.207 + this._requestMap[requestId] = window; 1.208 + 1.209 + cpmm.sendAsyncMessage("NFC:Connect", { 1.210 + requestId: requestId, 1.211 + sessionToken: sessionToken, 1.212 + techType: techType 1.213 + }); 1.214 + return request; 1.215 + }, 1.216 + 1.217 + close: function close(window, sessionToken) { 1.218 + if (window == null) { 1.219 + throw Components.Exception("Can't get window object", 1.220 + Cr.NS_ERROR_UNEXPECTED); 1.221 + } 1.222 + let request = Services.DOMRequest.createRequest(window); 1.223 + let requestId = btoa(this.getRequestId(request)); 1.224 + this._requestMap[requestId] = window; 1.225 + 1.226 + cpmm.sendAsyncMessage("NFC:Close", { 1.227 + requestId: requestId, 1.228 + sessionToken: sessionToken 1.229 + }); 1.230 + return request; 1.231 + }, 1.232 + 1.233 + sendFile: function sendFile(window, data, sessionToken) { 1.234 + if (window == null) { 1.235 + throw Components.Exception("Can't get window object", 1.236 + Cr.NS_ERROR_UNEXPECTED); 1.237 + } 1.238 + let request = Services.DOMRequest.createRequest(window); 1.239 + let requestId = btoa(this.getRequestId(request)); 1.240 + this._requestMap[requestId] = window; 1.241 + 1.242 + cpmm.sendAsyncMessage("NFC:SendFile", { 1.243 + requestId: requestId, 1.244 + sessionToken: sessionToken, 1.245 + blob: data.blob 1.246 + }); 1.247 + return request; 1.248 + }, 1.249 + 1.250 + notifySendFileStatus: function notifySendFileStatus(window, status, 1.251 + requestId) { 1.252 + if (window == null) { 1.253 + throw Components.Exception("Can't get window object", 1.254 + Cr.NS_ERROR_UNEXPECTED); 1.255 + } 1.256 + 1.257 + cpmm.sendAsyncMessage("NFC:NotifySendFileStatus", { 1.258 + status: status, 1.259 + requestId: requestId 1.260 + }); 1.261 + }, 1.262 + 1.263 + registerTargetForPeerEvent: function registerTargetForPeerEvent(window, 1.264 + appId, event, callback) { 1.265 + if (window == null) { 1.266 + throw Components.Exception("Can't get window object", 1.267 + Cr.NS_ERROR_UNEXPECTED); 1.268 + } 1.269 + this.peerEventsCallbackMap[event] = callback; 1.270 + cpmm.sendAsyncMessage("NFC:RegisterPeerTarget", { 1.271 + appId: appId, 1.272 + event: event 1.273 + }); 1.274 + }, 1.275 + 1.276 + unregisterTargetForPeerEvent: function unregisterTargetForPeerEvent(window, 1.277 + appId, event) { 1.278 + if (window == null) { 1.279 + throw Components.Exception("Can't get window object", 1.280 + Cr.NS_ERROR_UNEXPECTED); 1.281 + } 1.282 + let callback = this.peerEventsCallbackMap[event]; 1.283 + if (callback != null) { 1.284 + delete this.peerEventsCallbackMap[event]; 1.285 + } 1.286 + 1.287 + cpmm.sendAsyncMessage("NFC:UnregisterPeerTarget", { 1.288 + appId: appId, 1.289 + event: event 1.290 + }); 1.291 + }, 1.292 + 1.293 + checkP2PRegistration: function checkP2PRegistration(window, appId) { 1.294 + if (window == null) { 1.295 + throw Components.Exception("Can't get window object", 1.296 + Cr.NS_ERROR_UNEXPECTED); 1.297 + } 1.298 + let request = Services.DOMRequest.createRequest(window); 1.299 + let requestId = btoa(this.getRequestId(request)); 1.300 + this._requestMap[requestId] = window; 1.301 + 1.302 + cpmm.sendAsyncMessage("NFC:CheckP2PRegistration", { 1.303 + appId: appId, 1.304 + requestId: requestId 1.305 + }); 1.306 + return request; 1.307 + }, 1.308 + 1.309 + notifyUserAcceptedP2P: function notifyUserAcceptedP2P(window, appId) { 1.310 + if (window == null) { 1.311 + throw Components.Exception("Can't get window object", 1.312 + Cr.NS_ERROR_UNEXPECTED); 1.313 + } 1.314 + 1.315 + cpmm.sendAsyncMessage("NFC:NotifyUserAcceptedP2P", { 1.316 + appId: appId 1.317 + }); 1.318 + }, 1.319 + 1.320 + startPoll: function startPoll(window) { 1.321 + if (window == null) { 1.322 + throw Components.Exception("Can't get window object", 1.323 + Cr.NS_ERROR_UNEXPECTED); 1.324 + } 1.325 + 1.326 + let request = Services.DOMRequest.createRequest(window); 1.327 + let requestId = btoa(this.getRequestId(request)); 1.328 + this._requestMap[requestId] = window; 1.329 + 1.330 + cpmm.sendAsyncMessage("NFC:StartPoll", 1.331 + {requestId: requestId}); 1.332 + return request; 1.333 + }, 1.334 + 1.335 + stopPoll: function stopPoll(window) { 1.336 + if (window == null) { 1.337 + throw Components.Exception("Can't get window object", 1.338 + Cr.NS_ERROR_UNEXPECTED); 1.339 + } 1.340 + 1.341 + let request = Services.DOMRequest.createRequest(window); 1.342 + let requestId = btoa(this.getRequestId(request)); 1.343 + this._requestMap[requestId] = window; 1.344 + 1.345 + cpmm.sendAsyncMessage("NFC:StopPoll", 1.346 + {requestId: requestId}); 1.347 + return request; 1.348 + }, 1.349 + 1.350 + powerOff: function powerOff(window) { 1.351 + if (window == null) { 1.352 + throw Components.Exception("Can't get window object", 1.353 + Cr.NS_ERROR_UNEXPECTED); 1.354 + } 1.355 + 1.356 + let request = Services.DOMRequest.createRequest(window); 1.357 + let requestId = btoa(this.getRequestId(request)); 1.358 + this._requestMap[requestId] = window; 1.359 + 1.360 + cpmm.sendAsyncMessage("NFC:PowerOff", 1.361 + {requestId: requestId}); 1.362 + return request; 1.363 + }, 1.364 + 1.365 + // nsIObserver 1.366 + observe: function observe(subject, topic, data) { 1.367 + if (topic == "xpcom-shutdown") { 1.368 + this.destroyDOMRequestHelper(); 1.369 + Services.obs.removeObserver(this, "xpcom-shutdown"); 1.370 + cpmm = null; 1.371 + } 1.372 + }, 1.373 + 1.374 + // nsIMessageListener 1.375 + 1.376 + fireRequestSuccess: function fireRequestSuccess(requestId, result) { 1.377 + let request = this.takeRequest(requestId); 1.378 + if (!request) { 1.379 + debug("not firing success for id: " + requestId + 1.380 + ", result: " + JSON.stringify(result)); 1.381 + return; 1.382 + } 1.383 + 1.384 + debug("fire request success, id: " + requestId + 1.385 + ", result: " + JSON.stringify(result)); 1.386 + Services.DOMRequest.fireSuccess(request, result); 1.387 + }, 1.388 + 1.389 + fireRequestError: function fireRequestError(requestId, error) { 1.390 + let request = this.takeRequest(requestId); 1.391 + if (!request) { 1.392 + debug("not firing error for id: " + requestId + 1.393 + ", error: " + JSON.stringify(error)); 1.394 + return; 1.395 + } 1.396 + 1.397 + debug("fire request error, id: " + requestId + 1.398 + ", result: " + JSON.stringify(error)); 1.399 + Services.DOMRequest.fireError(request, error); 1.400 + }, 1.401 + 1.402 + receiveMessage: function receiveMessage(message) { 1.403 + debug("Message received: " + JSON.stringify(message)); 1.404 + let result = message.json; 1.405 + 1.406 + switch (message.name) { 1.407 + case "NFC:ReadNDEFResponse": 1.408 + this.handleReadNDEFResponse(result); 1.409 + break; 1.410 + case "NFC:GetDetailsNDEFResponse": 1.411 + this.handleGetDetailsNDEFResponse(result); 1.412 + break; 1.413 + case "NFC:ConnectResponse": // Fall through. 1.414 + case "NFC:CloseResponse": 1.415 + case "NFC:WriteNDEFResponse": 1.416 + case "NFC:MakeReadOnlyNDEFResponse": 1.417 + case "NFC:CheckP2PRegistrationResponse": 1.418 + case "NFC:NotifySendFileStatusResponse": 1.419 + case "NFC:ConfigResponse": 1.420 + if (result.status !== NFC.GECKO_NFC_ERROR_SUCCESS) { 1.421 + this.fireRequestError(atob(result.requestId), result.status); 1.422 + } else { 1.423 + this.fireRequestSuccess(atob(result.requestId), result); 1.424 + } 1.425 + break; 1.426 + case "NFC:PeerEvent": 1.427 + let callback = this.peerEventsCallbackMap[result.event]; 1.428 + if (callback) { 1.429 + callback.peerNotification(result.event, result.sessionToken); 1.430 + } else { 1.431 + debug("PeerEvent: No valid callback registered for the event " + 1.432 + result.event); 1.433 + } 1.434 + break; 1.435 + } 1.436 + }, 1.437 + 1.438 + handleReadNDEFResponse: function handleReadNDEFResponse(result) { 1.439 + let requester = this._requestMap[result.requestId]; 1.440 + if (!requester) { 1.441 + debug("Response Invalid requestId=" + result.requestId); 1.442 + return; 1.443 + } 1.444 + delete this._requestMap[result.requestId]; 1.445 + 1.446 + if (result.status !== NFC.GECKO_NFC_ERROR_SUCCESS) { 1.447 + this.fireRequestError(atob(result.requestId), result.status); 1.448 + return; 1.449 + } 1.450 + 1.451 + let requestId = atob(result.requestId); 1.452 + let ndefMsg = []; 1.453 + let records = result.records; 1.454 + for (let i = 0; i < records.length; i++) { 1.455 + let record = records[i]; 1.456 + ndefMsg.push(new requester.MozNDEFRecord(record.tnf, 1.457 + record.type, 1.458 + record.id, 1.459 + record.payload)); 1.460 + } 1.461 + this.fireRequestSuccess(requestId, ndefMsg); 1.462 + }, 1.463 + 1.464 + handleGetDetailsNDEFResponse: function handleGetDetailsNDEFResponse(result) { 1.465 + if (result.status !== NFC.GECKO_NFC_ERROR_SUCCESS) { 1.466 + this.fireRequestError(atob(result.requestId), result.status); 1.467 + return; 1.468 + } 1.469 + 1.470 + let requestId = atob(result.requestId); 1.471 + let result = new GetDetailsNDEFResponse(result); 1.472 + this.fireRequestSuccess(requestId, result); 1.473 + }, 1.474 +}; 1.475 + 1.476 +if (NFC_ENABLED) { 1.477 + this.NSGetFactory = XPCOMUtils.generateNSGetFactory([NfcContentHelper]); 1.478 +}