dom/system/gonk/NfcContentHelper.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 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 }

mercurial