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

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

mercurial