dom/system/gonk/nfc_worker.js

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

michael@0 1 /* Copyright 2012 Mozilla Foundation and Mozilla contributors
michael@0 2 *
michael@0 3 * Licensed under the Apache License, Version 2.0 (the "License");
michael@0 4 * you may not use this file except in compliance with the License.
michael@0 5 * You may obtain a copy of the License at
michael@0 6 *
michael@0 7 * http://www.apache.org/licenses/LICENSE-2.0
michael@0 8 *
michael@0 9 * Unless required by applicable law or agreed to in writing, software
michael@0 10 * distributed under the License is distributed on an "AS IS" BASIS,
michael@0 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
michael@0 12 * See the License for the specific language governing permissions and
michael@0 13 * limitations under the License.
michael@0 14 */
michael@0 15
michael@0 16 /* Copyright © 2013, Deutsche Telekom, Inc. */
michael@0 17
michael@0 18 "use strict";
michael@0 19
michael@0 20 importScripts("systemlibs.js", "nfc_consts.js");
michael@0 21 importScripts("resource://gre/modules/workers/require.js");
michael@0 22
michael@0 23 // set to true in nfc_consts.js to see debug messages
michael@0 24 let DEBUG = DEBUG_WORKER;
michael@0 25
michael@0 26 function getPaddingLen(len) {
michael@0 27 return (len % 4) ? (4 - len % 4) : 0;
michael@0 28 }
michael@0 29
michael@0 30 let Buf = {
michael@0 31 __proto__: (function(){
michael@0 32 return require("resource://gre/modules/workers/worker_buf.js").Buf;
michael@0 33 })(),
michael@0 34
michael@0 35 init: function init() {
michael@0 36 this._init();
michael@0 37 },
michael@0 38
michael@0 39 /**
michael@0 40 * Process one parcel.
michael@0 41 */
michael@0 42 processParcel: function processParcel() {
michael@0 43 let pduType = this.readInt32();
michael@0 44 if (DEBUG) debug("Number of bytes available in Parcel : " + this.readAvailable);
michael@0 45 NfcWorker.handleParcel(pduType, this.mCallback);
michael@0 46 },
michael@0 47
michael@0 48 /**
michael@0 49 * Start a new outgoing parcel.
michael@0 50 *
michael@0 51 * @param type
michael@0 52 * Integer specifying the request type.
michael@0 53 * @param callback
michael@0 54 */
michael@0 55 newParcel: function newParcel(type, callback) {
michael@0 56 if (DEBUG) debug("New outgoing parcel of type " + type);
michael@0 57 this.mCallback = callback;
michael@0 58 // We're going to leave room for the parcel size at the beginning.
michael@0 59 this.outgoingIndex = this.PARCEL_SIZE_SIZE;
michael@0 60 this.writeInt32(type);
michael@0 61 },
michael@0 62
michael@0 63 simpleRequest: function simpleRequest(type) {
michael@0 64 this.newParcel(type);
michael@0 65 this.sendParcel();
michael@0 66 },
michael@0 67
michael@0 68 onSendParcel: function onSendParcel(parcel) {
michael@0 69 postNfcMessage(parcel);
michael@0 70 },
michael@0 71
michael@0 72 /**
michael@0 73 * TODO: Bug 933593. Callback map of NFC_RESPONSE_XXX and RequestID
michael@0 74 * needs to be maintained
michael@0 75 */
michael@0 76 mCallback: null,
michael@0 77 };
michael@0 78
michael@0 79 /**
michael@0 80 * Provide a high-level API representing NFC capabilities.
michael@0 81 * Rensponsible for converting NFC requests from Content process to binary data
michael@0 82 * and NFC Responses from binary data to dictionary objects.
michael@0 83 */
michael@0 84 let NfcWorker = {
michael@0 85 /**
michael@0 86 * Handle incoming messages from the main UI thread.
michael@0 87 *
michael@0 88 * @param message
michael@0 89 * Object containing the message. Messages are supposed
michael@0 90 */
michael@0 91 handleDOMMessage: function handleMessage(message) {
michael@0 92 if (DEBUG) debug("Received DOM message " + JSON.stringify(message));
michael@0 93 let method = this[message.type];
michael@0 94 if (typeof method != "function") {
michael@0 95 if (DEBUG) {
michael@0 96 debug("Don't know what to do with message " + JSON.stringify(message));
michael@0 97 }
michael@0 98 return;
michael@0 99 }
michael@0 100 method.call(this, message);
michael@0 101 },
michael@0 102
michael@0 103 /**
michael@0 104 * Unmarshals a NDEF message
michael@0 105 */
michael@0 106 unMarshallNdefMessage: function unMarshallNdefMessage() {
michael@0 107 let numOfRecords = Buf.readInt32();
michael@0 108 debug("numOfRecords = " + numOfRecords);
michael@0 109 if (numOfRecords <= 0) {
michael@0 110 return null;
michael@0 111 }
michael@0 112 let records = [];
michael@0 113
michael@0 114 for (let i = 0; i < numOfRecords; i++) {
michael@0 115 let tnf = Buf.readInt32() & 0xff;
michael@0 116 let typeLength = Buf.readInt32();
michael@0 117 let type = Buf.readUint8Array(typeLength);
michael@0 118 let padding = getPaddingLen(typeLength);
michael@0 119 for (let i = 0; i < padding; i++) {
michael@0 120 Buf.readUint8();
michael@0 121 }
michael@0 122
michael@0 123 let idLength = Buf.readInt32();
michael@0 124 let id = Buf.readUint8Array(idLength);
michael@0 125 padding = getPaddingLen(idLength);
michael@0 126 for (let i = 0; i < padding; i++) {
michael@0 127 Buf.readUint8();
michael@0 128 }
michael@0 129
michael@0 130 let payloadLength = Buf.readInt32();
michael@0 131 let payload = Buf.readUint8Array(payloadLength);
michael@0 132 padding = getPaddingLen(payloadLength);
michael@0 133 for (let i = 0; i < padding; i++) {
michael@0 134 Buf.readUint8();
michael@0 135 }
michael@0 136 records.push({tnf: tnf,
michael@0 137 type: type,
michael@0 138 id: id,
michael@0 139 payload: payload});
michael@0 140 }
michael@0 141 return records;
michael@0 142 },
michael@0 143
michael@0 144 /**
michael@0 145 * Read and return NDEF data, if present.
michael@0 146 */
michael@0 147 readNDEF: function readNDEF(message) {
michael@0 148 let cb = function callback() {
michael@0 149 let error = Buf.readInt32();
michael@0 150 let sessionId = Buf.readInt32();
michael@0 151 let records = this.unMarshallNdefMessage();
michael@0 152
michael@0 153 message.type = "ReadNDEFResponse";
michael@0 154 message.sessionId = sessionId;
michael@0 155 message.records = records;
michael@0 156 message.status = (error === 0) ? GECKO_NFC_ERROR_SUCCESS :
michael@0 157 GECKO_NFC_ERROR_GENERIC_FAILURE;
michael@0 158 this.sendDOMMessage(message);
michael@0 159 }
michael@0 160
michael@0 161 Buf.newParcel(NFC_REQUEST_READ_NDEF, cb);
michael@0 162 Buf.writeInt32(message.sessionId);
michael@0 163 Buf.sendParcel();
michael@0 164 },
michael@0 165
michael@0 166 /**
michael@0 167 * Write to a target that accepts NDEF formattable data
michael@0 168 */
michael@0 169 writeNDEF: function writeNDEF(message) {
michael@0 170 let cb = function callback() {
michael@0 171 let error = Buf.readInt32();
michael@0 172 let sessionId = Buf.readInt32();
michael@0 173
michael@0 174 message.type = "WriteNDEFResponse";
michael@0 175 message.sessionId = sessionId;
michael@0 176 message.status = (error === 0) ? GECKO_NFC_ERROR_SUCCESS :
michael@0 177 GECKO_NFC_ERROR_GENERIC_FAILURE;
michael@0 178 this.sendDOMMessage(message);
michael@0 179 };
michael@0 180
michael@0 181 Buf.newParcel(NFC_REQUEST_WRITE_NDEF, cb);
michael@0 182 Buf.writeInt32(message.sessionId);
michael@0 183 let records = message.records;
michael@0 184 let numRecords = records.length;
michael@0 185 Buf.writeInt32(numRecords);
michael@0 186 for (let i = 0; i < numRecords; i++) {
michael@0 187 let record = records[i];
michael@0 188 Buf.writeInt32(record.tnf);
michael@0 189
michael@0 190 let typeLength = record.type ? record.type.length : 0;
michael@0 191 Buf.writeInt32(typeLength);
michael@0 192 for (let j = 0; j < typeLength; j++) {
michael@0 193 Buf.writeUint8(record.type[j]);
michael@0 194 }
michael@0 195 let padding = getPaddingLen(typeLength);
michael@0 196 for (let i = 0; i < padding; i++) {
michael@0 197 Buf.writeUint8(0x00);
michael@0 198 }
michael@0 199
michael@0 200 let idLength = record.id ? record.id.length : 0;
michael@0 201 Buf.writeInt32(idLength);
michael@0 202 for (let j = 0; j < idLength; j++) {
michael@0 203 Buf.writeUint8(record.id[j]);
michael@0 204 }
michael@0 205 padding = getPaddingLen(idLength);
michael@0 206 for (let i = 0; i < padding; i++) {
michael@0 207 Buf.writeUint8(0x00);
michael@0 208 }
michael@0 209
michael@0 210 let payloadLength = record.payload ? record.payload.length : 0;
michael@0 211 Buf.writeInt32(payloadLength);
michael@0 212 for (let j = 0; j < payloadLength; j++) {
michael@0 213 Buf.writeUint8(record.payload[j]);
michael@0 214 }
michael@0 215 padding = getPaddingLen(payloadLength);
michael@0 216 for (let i = 0; i < padding; i++) {
michael@0 217 Buf.writeUint8(0x00);
michael@0 218 }
michael@0 219 }
michael@0 220
michael@0 221 Buf.sendParcel();
michael@0 222 },
michael@0 223
michael@0 224 /**
michael@0 225 * Make the NFC NDEF tag permanently read only
michael@0 226 */
michael@0 227 makeReadOnlyNDEF: function makeReadOnlyNDEF(message) {
michael@0 228 let cb = function callback() {
michael@0 229 let error = Buf.readInt32();
michael@0 230 let sessionId = Buf.readInt32();
michael@0 231
michael@0 232 message.type = "MakeReadOnlyNDEFResponse";
michael@0 233 message.sessionId = sessionId;
michael@0 234 message.status = (error === 0) ? GECKO_NFC_ERROR_SUCCESS :
michael@0 235 GECKO_NFC_ERROR_GENERIC_FAILURE;
michael@0 236 this.sendDOMMessage(message);
michael@0 237 };
michael@0 238
michael@0 239 Buf.newParcel(NFC_REQUEST_MAKE_NDEF_READ_ONLY, cb);
michael@0 240 Buf.writeInt32(message.sessionId);
michael@0 241 Buf.sendParcel();
michael@0 242 },
michael@0 243
michael@0 244 /**
michael@0 245 * Retrieve metadata describing the NDEF formatted data, if present.
michael@0 246 */
michael@0 247 getDetailsNDEF: function getDetailsNDEF(message) {
michael@0 248 let cb = function callback() {
michael@0 249 let error = Buf.readInt32();
michael@0 250 let sessionId = Buf.readInt32();
michael@0 251 let isReadOnly = Buf.readUint8();
michael@0 252 let canBeMadeReadOnly = Buf.readUint8();
michael@0 253 // Ensure that padding is taken care here after reading two successive uint8's
michael@0 254 Buf.readUint8();
michael@0 255 Buf.readUint8();
michael@0 256 let maxSupportedLength = Buf.readInt32();
michael@0 257
michael@0 258 message.type = "GetDetailsNDEFResponse";
michael@0 259 message.sessionId = sessionId;
michael@0 260 message.isReadOnly = isReadOnly;
michael@0 261 message.canBeMadeReadOnly = canBeMadeReadOnly;
michael@0 262 message.maxSupportedLength = maxSupportedLength;
michael@0 263 message.status = (error === 0) ? GECKO_NFC_ERROR_SUCCESS :
michael@0 264 GECKO_NFC_ERROR_GENERIC_FAILURE;
michael@0 265 this.sendDOMMessage(message);
michael@0 266 };
michael@0 267 Buf.newParcel(NFC_REQUEST_GET_DETAILS, cb);
michael@0 268 Buf.writeInt32(message.sessionId);
michael@0 269 Buf.sendParcel();
michael@0 270 },
michael@0 271
michael@0 272
michael@0 273 /**
michael@0 274 * Open a connection to the NFC target.
michael@0 275 */
michael@0 276 connect: function connect(message) {
michael@0 277 let cb = function callback() {
michael@0 278 let error = Buf.readInt32();
michael@0 279 let sessionId = Buf.readInt32();
michael@0 280
michael@0 281 message.type = "ConnectResponse";
michael@0 282 message.sessionId = sessionId;
michael@0 283 message.status = (error === 0) ? GECKO_NFC_ERROR_SUCCESS :
michael@0 284 GECKO_NFC_ERROR_GENERIC_FAILURE;
michael@0 285 this.sendDOMMessage(message);
michael@0 286 };
michael@0 287
michael@0 288 Buf.newParcel(NFC_REQUEST_CONNECT, cb);
michael@0 289 Buf.writeInt32(message.sessionId);
michael@0 290 Buf.writeInt32(message.techType);
michael@0 291 Buf.sendParcel();
michael@0 292 },
michael@0 293
michael@0 294 /**
michael@0 295 * NFC Configuration
michael@0 296 */
michael@0 297 config: function config(message) {
michael@0 298 let cb = function callback() {
michael@0 299 let error = Buf.readInt32();
michael@0 300
michael@0 301 message.type = "ConfigResponse";
michael@0 302 message.status = (error === 0) ? GECKO_NFC_ERROR_SUCCESS :
michael@0 303 GECKO_NFC_ERROR_GENERIC_FAILURE;
michael@0 304 this.sendDOMMessage(message);
michael@0 305 };
michael@0 306
michael@0 307 Buf.newParcel(NFC_REQUEST_CONFIG , cb);
michael@0 308 Buf.writeInt32(message.powerLevel);
michael@0 309 Buf.sendParcel();
michael@0 310 },
michael@0 311
michael@0 312 /**
michael@0 313 * Close connection to the NFC target.
michael@0 314 */
michael@0 315 close: function close(message) {
michael@0 316 let cb = function callback() {
michael@0 317 let error = Buf.readInt32();
michael@0 318 let sessionId = Buf.readInt32();
michael@0 319
michael@0 320 message.type = "CloseResponse";
michael@0 321 message.sessionId = sessionId;
michael@0 322 message.status = (error === 0) ? GECKO_NFC_ERROR_SUCCESS :
michael@0 323 GECKO_NFC_ERROR_GENERIC_FAILURE;
michael@0 324 this.sendDOMMessage(message);
michael@0 325 };
michael@0 326
michael@0 327 Buf.newParcel(NFC_REQUEST_CLOSE , cb);
michael@0 328 Buf.writeInt32(message.sessionId);
michael@0 329 Buf.sendParcel();
michael@0 330 },
michael@0 331
michael@0 332 handleParcel: function handleParcel(request_type, callback) {
michael@0 333 let method = this[request_type];
michael@0 334 if (typeof method == "function") {
michael@0 335 if (DEBUG) debug("Handling parcel as " + method.name);
michael@0 336 method.call(this);
michael@0 337 } else if (typeof callback == "function") {
michael@0 338 callback.call(this, request_type);
michael@0 339 this.mCallback = null;
michael@0 340 } else {
michael@0 341 debug("Unable to handle ReqType:"+request_type);
michael@0 342 }
michael@0 343 },
michael@0 344
michael@0 345 /**
michael@0 346 * Send messages to the main UI thread.
michael@0 347 */
michael@0 348 sendDOMMessage: function sendDOMMessage(message) {
michael@0 349 postMessage(message);
michael@0 350 }
michael@0 351 };
michael@0 352
michael@0 353 /**
michael@0 354 * Notification Handlers
michael@0 355 */
michael@0 356 NfcWorker[NFC_NOTIFICATION_INITIALIZED] = function NFC_NOTIFICATION_INITIALIZED () {
michael@0 357 let status = Buf.readInt32();
michael@0 358 let majorVersion = Buf.readInt32();
michael@0 359 let minorVersion = Buf.readInt32();
michael@0 360 debug("NFC_NOTIFICATION_INITIALIZED status:" + status);
michael@0 361 if ((majorVersion != NFC_MAJOR_VERSION) || (minorVersion != NFC_MINOR_VERSION)) {
michael@0 362 debug("Version Mismatch! Current Supported Version : " +
michael@0 363 NFC_MAJOR_VERSION + "." + NFC_MINOR_VERSION +
michael@0 364 " Received Version : " + majorVersion + "." + minorVersion);
michael@0 365 }
michael@0 366 };
michael@0 367
michael@0 368 NfcWorker[NFC_NOTIFICATION_TECH_DISCOVERED] = function NFC_NOTIFICATION_TECH_DISCOVERED() {
michael@0 369 debug("NFC_NOTIFICATION_TECH_DISCOVERED");
michael@0 370 let techList = [];
michael@0 371 let records = null;
michael@0 372
michael@0 373 let sessionId = Buf.readInt32();
michael@0 374 let techCount = Buf.readInt32();
michael@0 375 for (let count = 0; count < techCount; count++) {
michael@0 376 let tech = NFC_TECHS[Buf.readUint8()];
michael@0 377 if (tech) {
michael@0 378 techList.push(tech);
michael@0 379 }
michael@0 380 }
michael@0 381
michael@0 382 let padding = getPaddingLen(techCount);
michael@0 383 for (let i = 0; i < padding; i++) {
michael@0 384 Buf.readUint8();
michael@0 385 }
michael@0 386
michael@0 387 let ndefMsgCount = Buf.readInt32();
michael@0 388 if (ndefMsgCount > 0) {
michael@0 389 records = this.unMarshallNdefMessage();
michael@0 390 }
michael@0 391 this.sendDOMMessage({type: "techDiscovered",
michael@0 392 sessionId: sessionId,
michael@0 393 techList: techList,
michael@0 394 records: records});
michael@0 395 };
michael@0 396
michael@0 397 NfcWorker[NFC_NOTIFICATION_TECH_LOST] = function NFC_NOTIFICATION_TECH_LOST() {
michael@0 398 debug("NFC_NOTIFICATION_TECH_LOST");
michael@0 399 let sessionId = Buf.readInt32();
michael@0 400 debug("sessionId = " + sessionId);
michael@0 401 this.sendDOMMessage({type: "techLost",
michael@0 402 sessionId: sessionId,
michael@0 403 });
michael@0 404 };
michael@0 405
michael@0 406 /**
michael@0 407 * Global stuff.
michael@0 408 */
michael@0 409
michael@0 410 if (!this.debug) {
michael@0 411 // Debugging stub that goes nowhere.
michael@0 412 this.debug = function debug(message) {
michael@0 413 dump("Nfc Worker: " + message + "\n");
michael@0 414 };
michael@0 415 }
michael@0 416
michael@0 417 // Initialize buffers. This is a separate function so that unit tests can
michael@0 418 // re-initialize the buffers at will.
michael@0 419 Buf.init();
michael@0 420
michael@0 421 function onNfcMessage(data) {
michael@0 422 Buf.processIncoming(data);
michael@0 423 };
michael@0 424
michael@0 425 onmessage = function onmessage(event) {
michael@0 426 NfcWorker.handleDOMMessage(event.data);
michael@0 427 };
michael@0 428
michael@0 429 onerror = function onerror(event) {
michael@0 430 debug("OnError: event: " + JSON.stringify(event));
michael@0 431 debug("NFC Worker error " + event.message + " " + event.filename + ":" +
michael@0 432 event.lineno + ":\n");
michael@0 433 };

mercurial