dom/system/gonk/Nfc.js

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/dom/system/gonk/Nfc.js	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,637 @@
     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 +
    1.28 +let NFC = {};
    1.29 +Cu.import("resource://gre/modules/nfc_consts.js", NFC);
    1.30 +
    1.31 +Cu.import("resource://gre/modules/systemlibs.js");
    1.32 +const NFC_ENABLED = libcutils.property_get("ro.moz.nfc.enabled", "false") === "true";
    1.33 +
    1.34 +// set to true in nfc_consts.js to see debug messages
    1.35 +let DEBUG = NFC.DEBUG_NFC;
    1.36 +
    1.37 +let debug;
    1.38 +if (DEBUG) {
    1.39 +  debug = function (s) {
    1.40 +    dump("-*- Nfc: " + s + "\n");
    1.41 +  };
    1.42 +} else {
    1.43 +  debug = function (s) {};
    1.44 +}
    1.45 +
    1.46 +const NFC_CONTRACTID = "@mozilla.org/nfc;1";
    1.47 +const NFC_CID =
    1.48 +  Components.ID("{2ff24790-5e74-11e1-b86c-0800200c9a66}");
    1.49 +
    1.50 +const NFC_IPC_MSG_NAMES = [
    1.51 +  "NFC:SetSessionToken"
    1.52 +];
    1.53 +
    1.54 +const NFC_IPC_READ_PERM_MSG_NAMES = [
    1.55 +  "NFC:ReadNDEF",
    1.56 +  "NFC:GetDetailsNDEF",
    1.57 +  "NFC:Connect",
    1.58 +  "NFC:Close",
    1.59 +];
    1.60 +
    1.61 +const NFC_IPC_WRITE_PERM_MSG_NAMES = [
    1.62 +  "NFC:WriteNDEF",
    1.63 +  "NFC:MakeReadOnlyNDEF",
    1.64 +  "NFC:SendFile",
    1.65 +  "NFC:RegisterPeerTarget",
    1.66 +  "NFC:UnregisterPeerTarget"
    1.67 +];
    1.68 +
    1.69 +const NFC_IPC_MANAGER_PERM_MSG_NAMES = [
    1.70 +  "NFC:CheckP2PRegistration",
    1.71 +  "NFC:NotifyUserAcceptedP2P",
    1.72 +  "NFC:NotifySendFileStatus",
    1.73 +  "NFC:StartPoll",
    1.74 +  "NFC:StopPoll",
    1.75 +  "NFC:PowerOff"
    1.76 +];
    1.77 +
    1.78 +XPCOMUtils.defineLazyServiceGetter(this, "ppmm",
    1.79 +                                   "@mozilla.org/parentprocessmessagemanager;1",
    1.80 +                                   "nsIMessageBroadcaster");
    1.81 +XPCOMUtils.defineLazyServiceGetter(this, "gSystemMessenger",
    1.82 +                                   "@mozilla.org/system-message-internal;1",
    1.83 +                                   "nsISystemMessagesInternal");
    1.84 +XPCOMUtils.defineLazyServiceGetter(this, "gSystemWorkerManager",
    1.85 +                                   "@mozilla.org/telephony/system-worker-manager;1",
    1.86 +                                   "nsISystemWorkerManager");
    1.87 +XPCOMUtils.defineLazyServiceGetter(this, "UUIDGenerator",
    1.88 +                                    "@mozilla.org/uuid-generator;1",
    1.89 +                                    "nsIUUIDGenerator");
    1.90 +XPCOMUtils.defineLazyGetter(this, "gMessageManager", function () {
    1.91 +  return {
    1.92 +    QueryInterface: XPCOMUtils.generateQI([Ci.nsIMessageListener,
    1.93 +                                           Ci.nsIObserver]),
    1.94 +
    1.95 +    nfc: null,
    1.96 +
    1.97 +    // Manage message targets in terms of sessionToken. Only the authorized and
    1.98 +    // registered contents can receive related messages.
    1.99 +    targetsBySessionTokens: {},
   1.100 +    sessionTokens: [],
   1.101 +
   1.102 +    // Manage registered Peer Targets
   1.103 +    peerTargetsMap: {},
   1.104 +    currentPeerAppId: null,
   1.105 +
   1.106 +    init: function init(nfc) {
   1.107 +      this.nfc = nfc;
   1.108 +
   1.109 +      Services.obs.addObserver(this, NFC.TOPIC_XPCOM_SHUTDOWN, false);
   1.110 +      this._registerMessageListeners();
   1.111 +    },
   1.112 +
   1.113 +    _shutdown: function _shutdown() {
   1.114 +      this.nfc = null;
   1.115 +
   1.116 +      Services.obs.removeObserver(this, NFC.TOPIC_XPCOM_SHUTDOWN);
   1.117 +      this._unregisterMessageListeners();
   1.118 +    },
   1.119 +
   1.120 +    _registerMessageListeners: function _registerMessageListeners() {
   1.121 +      ppmm.addMessageListener("child-process-shutdown", this);
   1.122 +
   1.123 +      for (let msgname of NFC_IPC_MSG_NAMES) {
   1.124 +        ppmm.addMessageListener(msgname, this);
   1.125 +      }
   1.126 +
   1.127 +      for (let msgname of NFC_IPC_READ_PERM_MSG_NAMES) {
   1.128 +        ppmm.addMessageListener(msgname, this);
   1.129 +      }
   1.130 +
   1.131 +      for (let msgname of NFC_IPC_WRITE_PERM_MSG_NAMES) {
   1.132 +        ppmm.addMessageListener(msgname, this);
   1.133 +      }
   1.134 +
   1.135 +      for (let msgname of NFC_IPC_MANAGER_PERM_MSG_NAMES) {
   1.136 +        ppmm.addMessageListener(msgname, this);
   1.137 +      }
   1.138 +    },
   1.139 +
   1.140 +    _unregisterMessageListeners: function _unregisterMessageListeners() {
   1.141 +      ppmm.removeMessageListener("child-process-shutdown", this);
   1.142 +
   1.143 +      for (let msgname of NFC_IPC_MSG_NAMES) {
   1.144 +        ppmm.removeMessageListener(msgname, this);
   1.145 +      }
   1.146 +
   1.147 +      for (let msgname of NFC_IPC_READ_PERM_MSG_NAMES) {
   1.148 +        ppmm.removeMessageListener(msgname, this);
   1.149 +      }
   1.150 +
   1.151 +      for (let msgname of NFC_IPC_WRITE_PERM_MSG_NAMES) {
   1.152 +        ppmm.removeMessageListener(msgname, this);
   1.153 +      }
   1.154 +
   1.155 +      for (let msgname of NFC_IPC_MANAGER_PERM_MSG_NAMES) {
   1.156 +        ppmm.removeMessageListener(msgname, this);
   1.157 +      }
   1.158 +
   1.159 +      ppmm = null;
   1.160 +    },
   1.161 +
   1.162 +    _registerMessageTarget: function _registerMessageTarget(sessionToken, target) {
   1.163 +      let targets = this.targetsBySessionTokens[sessionToken];
   1.164 +      if (!targets) {
   1.165 +        targets = this.targetsBySessionTokens[sessionToken] = [];
   1.166 +        let list = this.sessionTokens;
   1.167 +        if (list.indexOf(sessionToken) == -1) {
   1.168 +          list.push(sessionToken);
   1.169 +        }
   1.170 +      }
   1.171 +
   1.172 +      if (targets.indexOf(target) != -1) {
   1.173 +        debug("Already registered this target!");
   1.174 +        return;
   1.175 +      }
   1.176 +
   1.177 +      targets.push(target);
   1.178 +      debug("Registered :" + sessionToken + " target: " + target);
   1.179 +    },
   1.180 +
   1.181 +    _unregisterMessageTarget: function _unregisterMessageTarget(sessionToken, target) {
   1.182 +      if (sessionToken == null) {
   1.183 +        // Unregister the target for every sessionToken when no sessionToken is specified.
   1.184 +        for (let session of this.sessionTokens) {
   1.185 +          this._unregisterMessageTarget(session, target);
   1.186 +        }
   1.187 +        return;
   1.188 +      }
   1.189 +
   1.190 +      // Unregister the target for a specified sessionToken.
   1.191 +      let targets = this.targetsBySessionTokens[sessionToken];
   1.192 +      if (!targets) {
   1.193 +        return;
   1.194 +      }
   1.195 +
   1.196 +      if (target == null) {
   1.197 +        debug("Unregistered all targets for the " + sessionToken + " targets: " + targets);
   1.198 +        targets = [];
   1.199 +        let list = this.sessionTokens;
   1.200 +        if (sessionToken !== null) {
   1.201 +          let index = list.indexOf(sessionToken);
   1.202 +          if (index > -1) {
   1.203 +            list.splice(index, 1);
   1.204 +          }
   1.205 +        }
   1.206 +        return;
   1.207 +      }
   1.208 +
   1.209 +      let index = targets.indexOf(target);
   1.210 +      if (index != -1) {
   1.211 +        targets.splice(index, 1);
   1.212 +      }
   1.213 +    },
   1.214 +
   1.215 +    _sendTargetMessage: function _sendTargetMessage(sessionToken, message, options) {
   1.216 +      let targets = this.targetsBySessionTokens[sessionToken];
   1.217 +      if (!targets) {
   1.218 +        return;
   1.219 +      }
   1.220 +
   1.221 +      for (let target of targets) {
   1.222 +        target.sendAsyncMessage(message, options);
   1.223 +      }
   1.224 +    },
   1.225 +
   1.226 +    registerPeerTarget: function registerPeerTarget(msg) {
   1.227 +      let appInfo = msg.json;
   1.228 +      // Sanity check on PeerEvent
   1.229 +      if (!this.isValidPeerEvent(appInfo.event)) {
   1.230 +        return;
   1.231 +      }
   1.232 +      let targets = this.peerTargetsMap;
   1.233 +      let targetInfo = targets[appInfo.appId];
   1.234 +      // If the application Id is already registered
   1.235 +      if (targetInfo) {
   1.236 +        // If the event is not registered
   1.237 +        if (targetInfo.event !== appInfo.event) {
   1.238 +          // Update the event field ONLY
   1.239 +          targetInfo.event |= appInfo.event;
   1.240 +        }
   1.241 +        // Otherwise event is already registered, return!
   1.242 +        return;
   1.243 +      }
   1.244 +      // Target not registered yet! Add to the target map
   1.245 +
   1.246 +      // Registered targetInfo target consists of 2 fields (values)
   1.247 +      // target : Target to notify the right content for peer notifications
   1.248 +      // event  : NFC_PEER_EVENT_READY (0x01) Or NFC_PEER_EVENT_LOST (0x02)
   1.249 +      let newTargetInfo = { target : msg.target,
   1.250 +                            event  : appInfo.event };
   1.251 +      targets[appInfo.appId] = newTargetInfo;
   1.252 +    },
   1.253 +
   1.254 +    unregisterPeerTarget: function unregisterPeerTarget(msg) {
   1.255 +      let appInfo = msg.json;
   1.256 +      // Sanity check on PeerEvent
   1.257 +      if (!this.isValidPeerEvent(appInfo.event)) {
   1.258 +        return;
   1.259 +      }
   1.260 +      let targets = this.peerTargetsMap;
   1.261 +      let targetInfo = targets[appInfo.appId];
   1.262 +      if (targetInfo) {
   1.263 +        // Application Id registered and the event exactly matches.
   1.264 +        if (targetInfo.event === appInfo.event) {
   1.265 +          // Remove the target from the list of registered targets
   1.266 +          delete targets[appInfo.appId]
   1.267 +        }
   1.268 +        else {
   1.269 +          // Otherwise, update the event field ONLY, by removing the event flag
   1.270 +          targetInfo.event &= ~appInfo.event;
   1.271 +        }
   1.272 +      }
   1.273 +    },
   1.274 +
   1.275 +    removePeerTarget: function removePeerTarget(target) {
   1.276 +      let targets = this.peerTargetsMap;
   1.277 +      Object.keys(targets).forEach((appId) => {
   1.278 +        let targetInfo = targets[appId];
   1.279 +        if (targetInfo && targetInfo.target === target) {
   1.280 +          // Remove the target from the list of registered targets
   1.281 +          delete targets[appId];
   1.282 +        }
   1.283 +      });
   1.284 +    },
   1.285 +
   1.286 +    isRegisteredP2PTarget: function isRegisteredP2PTarget(appId, event) {
   1.287 +      let targetInfo = this.peerTargetsMap[appId];
   1.288 +      // Check if it is a registered target for the 'event'
   1.289 +      return ((targetInfo != null) && (targetInfo.event & event !== 0));
   1.290 +    },
   1.291 +
   1.292 +    notifyPeerEvent: function notifyPeerEvent(appId, event) {
   1.293 +      let targetInfo = this.peerTargetsMap[appId];
   1.294 +      // Check if the application id is a registeredP2PTarget
   1.295 +      if (this.isRegisteredP2PTarget(appId, event)) {
   1.296 +        targetInfo.target.sendAsyncMessage("NFC:PeerEvent", {
   1.297 +          event: event,
   1.298 +          sessionToken: this.nfc.sessionTokenMap[this.nfc._currentSessionId]
   1.299 +        });
   1.300 +        return;
   1.301 +      }
   1.302 +      debug("Application ID : " + appId + " is not a registered target" +
   1.303 +                             "for the event " + event + " notification");
   1.304 +    },
   1.305 +
   1.306 +    isValidPeerEvent: function isValidPeerEvent(event) {
   1.307 +      // Valid values : 0x01, 0x02 Or 0x03
   1.308 +      return ((event === NFC.NFC_PEER_EVENT_READY) ||
   1.309 +              (event === NFC.NFC_PEER_EVENT_LOST)  ||
   1.310 +              (event === (NFC.NFC_PEER_EVENT_READY | NFC.NFC_PEER_EVENT_LOST)));
   1.311 +    },
   1.312 +
   1.313 +    /**
   1.314 +     * nsIMessageListener interface methods.
   1.315 +     */
   1.316 +
   1.317 +    receiveMessage: function receiveMessage(msg) {
   1.318 +      debug("Received '" + msg.name + "' message from content process");
   1.319 +      if (msg.name == "child-process-shutdown") {
   1.320 +        // By the time we receive child-process-shutdown, the child process has
   1.321 +        // already forgotten its permissions so we need to unregister the target
   1.322 +        // for every permission.
   1.323 +        this._unregisterMessageTarget(null, msg.target);
   1.324 +        this.removePeerTarget(msg.target);
   1.325 +        return null;
   1.326 +      }
   1.327 +
   1.328 +      if (NFC_IPC_MSG_NAMES.indexOf(msg.name) != -1) {
   1.329 +        // Do nothing.
   1.330 +      } else if (NFC_IPC_READ_PERM_MSG_NAMES.indexOf(msg.name) != -1) {
   1.331 +        if (!msg.target.assertPermission("nfc-read")) {
   1.332 +          debug("Nfc message " + msg.name +
   1.333 +                " from a content process with no 'nfc-read' privileges.");
   1.334 +          return null;
   1.335 +        }
   1.336 +      } else if (NFC_IPC_WRITE_PERM_MSG_NAMES.indexOf(msg.name) != -1) {
   1.337 +        if (!msg.target.assertPermission("nfc-write")) {
   1.338 +          debug("Nfc Peer message  " + msg.name +
   1.339 +                " from a content process with no 'nfc-write' privileges.");
   1.340 +          return null;
   1.341 +        }
   1.342 +      } else if (NFC_IPC_MANAGER_PERM_MSG_NAMES.indexOf(msg.name) != -1) {
   1.343 +        if (!msg.target.assertPermission("nfc-manager")) {
   1.344 +          debug("NFC message " + message.name +
   1.345 +                " from a content process with no 'nfc-manager' privileges.");
   1.346 +          return null;
   1.347 +        }
   1.348 +      } else {
   1.349 +        debug("Ignoring unknown message type: " + msg.name);
   1.350 +        return null;
   1.351 +      }
   1.352 +
   1.353 +      switch (msg.name) {
   1.354 +        case "NFC:SetSessionToken":
   1.355 +          this._registerMessageTarget(this.nfc.sessionTokenMap[this.nfc._currentSessionId], msg.target);
   1.356 +          debug("Registering target for this SessionToken : " +
   1.357 +                this.nfc.sessionTokenMap[this.nfc._currentSessionId]);
   1.358 +          return null;
   1.359 +        case "NFC:RegisterPeerTarget":
   1.360 +          this.registerPeerTarget(msg);
   1.361 +          return null;
   1.362 +        case "NFC:UnregisterPeerTarget":
   1.363 +          this.unregisterPeerTarget(msg);
   1.364 +          return null;
   1.365 +        case "NFC:CheckP2PRegistration":
   1.366 +          // Check if the application id is a valid registered target.
   1.367 +          // (It should have registered for NFC_PEER_EVENT_READY).
   1.368 +          let isRegistered = this.isRegisteredP2PTarget(msg.json.appId,
   1.369 +                                                        NFC.NFC_PEER_EVENT_READY);
   1.370 +          // Remember the current AppId if registered.
   1.371 +          this.currentPeerAppId = (isRegistered) ? msg.json.appId : null;
   1.372 +          let status = (isRegistered) ? NFC.GECKO_NFC_ERROR_SUCCESS :
   1.373 +                                        NFC.GECKO_NFC_ERROR_GENERIC_FAILURE;
   1.374 +          // Notify the content process immediately of the status
   1.375 +          msg.target.sendAsyncMessage(msg.name + "Response", {
   1.376 +            status: status,
   1.377 +            requestId: msg.json.requestId
   1.378 +          });
   1.379 +          return null;
   1.380 +        case "NFC:NotifyUserAcceptedP2P":
   1.381 +          // Notify the 'NFC_PEER_EVENT_READY' since user has acknowledged
   1.382 +          this.notifyPeerEvent(msg.json.appId, NFC.NFC_PEER_EVENT_READY);
   1.383 +          return null;
   1.384 +        case "NFC:NotifySendFileStatus":
   1.385 +          // Upon receiving the status of sendFile operation, send the response
   1.386 +          // to appropriate content process.
   1.387 +          this.sendNfcResponseMessage(msg.name + "Response", msg.json);
   1.388 +          return null;
   1.389 +        default:
   1.390 +          return this.nfc.receiveMessage(msg);
   1.391 +      }
   1.392 +    },
   1.393 +
   1.394 +    /**
   1.395 +     * nsIObserver interface methods.
   1.396 +     */
   1.397 +
   1.398 +    observe: function observe(subject, topic, data) {
   1.399 +      switch (topic) {
   1.400 +        case NFC.TOPIC_XPCOM_SHUTDOWN:
   1.401 +          this._shutdown();
   1.402 +          break;
   1.403 +      }
   1.404 +    },
   1.405 +
   1.406 +    sendNfcResponseMessage: function sendNfcResponseMessage(message, data) {
   1.407 +      this._sendTargetMessage(this.nfc.sessionTokenMap[this.nfc._currentSessionId], message, data);
   1.408 +    },
   1.409 +  };
   1.410 +});
   1.411 +
   1.412 +function Nfc() {
   1.413 +  debug("Starting Worker");
   1.414 +  this.worker = new ChromeWorker("resource://gre/modules/nfc_worker.js");
   1.415 +  this.worker.onerror = this.onerror.bind(this);
   1.416 +  this.worker.onmessage = this.onmessage.bind(this);
   1.417 +
   1.418 +  gMessageManager.init(this);
   1.419 +
   1.420 +  // Maps sessionId (that are generated from nfcd) with a unique guid : 'SessionToken'
   1.421 +  this.sessionTokenMap = {};
   1.422 +  this.targetsByRequestId = {};
   1.423 +
   1.424 +  gSystemWorkerManager.registerNfcWorker(this.worker);
   1.425 +}
   1.426 +
   1.427 +Nfc.prototype = {
   1.428 +
   1.429 +  classID:   NFC_CID,
   1.430 +  classInfo: XPCOMUtils.generateCI({classID: NFC_CID,
   1.431 +                                    classDescription: "Nfc",
   1.432 +                                    interfaces: [Ci.nsIWorkerHolder]}),
   1.433 +
   1.434 +  QueryInterface: XPCOMUtils.generateQI([Ci.nsIWorkerHolder]),
   1.435 +
   1.436 +  _currentSessionId: null,
   1.437 +
   1.438 +  powerLevel: NFC.NFC_POWER_LEVEL_UNKNOWN,
   1.439 +
   1.440 +  onerror: function onerror(event) {
   1.441 +    debug("Got an error: " + event.filename + ":" +
   1.442 +          event.lineno + ": " + event.message + "\n");
   1.443 +    event.preventDefault();
   1.444 +  },
   1.445 +
   1.446 +  /**
   1.447 +   * Send arbitrary message to worker.
   1.448 +   *
   1.449 +   * @param nfcMessageType
   1.450 +   *        A text message type.
   1.451 +   * @param message [optional]
   1.452 +   *        An optional message object to send.
   1.453 +   */
   1.454 +  sendToWorker: function sendToWorker(nfcMessageType, message) {
   1.455 +    message = message || {};
   1.456 +    message.type = nfcMessageType;
   1.457 +    this.worker.postMessage(message);
   1.458 +  },
   1.459 +
   1.460 +  /**
   1.461 +   * Send Error response to content.
   1.462 +   *
   1.463 +   * @param message
   1.464 +   *        An nsIMessageListener's message parameter.
   1.465 +   */
   1.466 +  sendNfcErrorResponse: function sendNfcErrorResponse(message) {
   1.467 +    if (!message.target) {
   1.468 +      return;
   1.469 +    }
   1.470 +
   1.471 +    let nfcMsgType = message.name + "Response";
   1.472 +    message.target.sendAsyncMessage(nfcMsgType, {
   1.473 +      sessionId: message.json.sessionToken,
   1.474 +      requestId: message.json.requestId,
   1.475 +      status: NFC.GECKO_NFC_ERROR_GENERIC_FAILURE
   1.476 +    });
   1.477 +  },
   1.478 +
   1.479 +  /**
   1.480 +   * Process the incoming message from the NFC worker
   1.481 +   */
   1.482 +  onmessage: function onmessage(event) {
   1.483 +    let message = event.data;
   1.484 +    debug("Received message from NFC worker: " + JSON.stringify(message));
   1.485 +
   1.486 +    switch (message.type) {
   1.487 +      case "techDiscovered":
   1.488 +        this._currentSessionId = message.sessionId;
   1.489 +
   1.490 +        // Check if the session token already exists. If exists, continue to use the same one.
   1.491 +        // If not, generate a new token.
   1.492 +        if (!this.sessionTokenMap[this._currentSessionId]) {
   1.493 +          this.sessionTokenMap[this._currentSessionId] = UUIDGenerator.generateUUID().toString();
   1.494 +        }
   1.495 +        // Update the upper layers with a session token (alias)
   1.496 +        message.sessionToken = this.sessionTokenMap[this._currentSessionId];
   1.497 +        // Do not expose the actual session to the content
   1.498 +        delete message.sessionId;
   1.499 +
   1.500 +        gSystemMessenger.broadcastMessage("nfc-manager-tech-discovered", message);
   1.501 +        break;
   1.502 +      case "techLost":
   1.503 +        gMessageManager._unregisterMessageTarget(this.sessionTokenMap[this._currentSessionId], null);
   1.504 +
   1.505 +        // Update the upper layers with a session token (alias)
   1.506 +        message.sessionToken = this.sessionTokenMap[this._currentSessionId];
   1.507 +        // Do not expose the actual session to the content
   1.508 +        delete message.sessionId;
   1.509 +
   1.510 +        gSystemMessenger.broadcastMessage("nfc-manager-tech-lost", message);
   1.511 +        // Notify 'PeerLost' to appropriate registered target, if any
   1.512 +        gMessageManager.notifyPeerEvent(this.currentPeerAppId, NFC.NFC_PEER_EVENT_LOST);
   1.513 +        delete this.sessionTokenMap[this._currentSessionId];
   1.514 +        this._currentSessionId = null;
   1.515 +        this.currentPeerAppId = null;
   1.516 +        break;
   1.517 +     case "ConfigResponse":
   1.518 +        let target = this.targetsByRequestId[message.requestId];
   1.519 +        if (!target) {
   1.520 +          debug("No target for requestId: " + message.requestId);
   1.521 +          return;
   1.522 +        }
   1.523 +        delete this.targetsByRequestId[message.requestId];
   1.524 +
   1.525 +        if (message.status == NFC.GECKO_NFC_ERROR_SUCCESS) {
   1.526 +          this.powerLevel = message.powerLevel;
   1.527 +        }
   1.528 +
   1.529 +        target.sendAsyncMessage("NFC:ConfigResponse", message);
   1.530 +        break;
   1.531 +      case "ConnectResponse": // Fall through.
   1.532 +      case "CloseResponse":
   1.533 +      case "GetDetailsNDEFResponse":
   1.534 +      case "ReadNDEFResponse":
   1.535 +      case "MakeReadOnlyNDEFResponse":
   1.536 +      case "WriteNDEFResponse":
   1.537 +        message.sessionToken = this.sessionTokenMap[this._currentSessionId];
   1.538 +        // Do not expose the actual session to the content
   1.539 +        delete message.sessionId;
   1.540 +        gMessageManager.sendNfcResponseMessage("NFC:" + message.type, message);
   1.541 +        break;
   1.542 +      default:
   1.543 +        throw new Error("Don't know about this message type: " + message.type);
   1.544 +    }
   1.545 +  },
   1.546 +
   1.547 +  // nsINfcWorker
   1.548 +  worker: null,
   1.549 +
   1.550 +  sessionTokenMap: null,
   1.551 +
   1.552 +  targetsByRequestId: null,
   1.553 +
   1.554 +  /**
   1.555 +   * Process a message from the content process.
   1.556 +   */
   1.557 +  receiveMessage: function receiveMessage(message) {
   1.558 +    debug("Received '" + JSON.stringify(message) + "' message from content process");
   1.559 +
   1.560 +    // Handle messages without sessionToken.
   1.561 +    if (message.name == "NFC:StartPoll") {
   1.562 +      this.targetsByRequestId[message.json.requestId] = message.target;
   1.563 +      this.setConfig({powerLevel: NFC.NFC_POWER_LEVEL_ENABLED,
   1.564 +                      requestId: message.json.requestId});
   1.565 +      return null;
   1.566 +    } else if (message.name == "NFC:StopPoll") {
   1.567 +      this.targetsByRequestId[message.json.requestId] = message.target;
   1.568 +      this.setConfig({powerLevel: NFC.NFC_POWER_LEVEL_LOW,
   1.569 +                      requestId: message.json.requestId});
   1.570 +      return null;
   1.571 +    } else if (message.name == "NFC:PowerOff") {
   1.572 +      this.targetsByRequestId[message.json.requestId] = message.target;
   1.573 +      this.setConfig({powerLevel: NFC.NFC_POWER_LEVEL_DISABLED,
   1.574 +                      requestId: message.json.requestId});
   1.575 +      return null;
   1.576 +    }
   1.577 +
   1.578 +    if (this.powerLevel != NFC.NFC_POWER_LEVEL_ENABLED) {
   1.579 +      debug("NFC is not enabled. current powerLevel:" + this.powerLevel);
   1.580 +      this.sendNfcErrorResponse(message);
   1.581 +      return null;
   1.582 +    }
   1.583 +
   1.584 +    // Sanity check on sessionId
   1.585 +    if (message.json.sessionToken !== this.sessionTokenMap[this._currentSessionId]) {
   1.586 +      debug("Invalid Session Token: " + message.json.sessionToken +
   1.587 +            " Expected Session Token: " + this.sessionTokenMap[this._currentSessionId]);
   1.588 +      this.sendNfcErrorResponse(message);
   1.589 +      return null;
   1.590 +    }
   1.591 +
   1.592 +    // Update the current sessionId before sending to the worker
   1.593 +    message.json.sessionId = this._currentSessionId;
   1.594 +
   1.595 +    switch (message.name) {
   1.596 +      case "NFC:GetDetailsNDEF":
   1.597 +        this.sendToWorker("getDetailsNDEF", message.json);
   1.598 +        break;
   1.599 +      case "NFC:ReadNDEF":
   1.600 +        this.sendToWorker("readNDEF", message.json);
   1.601 +        break;
   1.602 +      case "NFC:WriteNDEF":
   1.603 +        this.sendToWorker("writeNDEF", message.json);
   1.604 +        break;
   1.605 +      case "NFC:MakeReadOnlyNDEF":
   1.606 +        this.sendToWorker("makeReadOnlyNDEF", message.json);
   1.607 +        break;
   1.608 +      case "NFC:Connect":
   1.609 +        this.sendToWorker("connect", message.json);
   1.610 +        break;
   1.611 +      case "NFC:Close":
   1.612 +        this.sendToWorker("close", message.json);
   1.613 +        break;
   1.614 +      case "NFC:SendFile":
   1.615 +        // Chrome process is the arbitrator / mediator between
   1.616 +        // system app (content process) that issued nfc 'sendFile' operation
   1.617 +        // and system app that handles the system message :
   1.618 +        // 'nfc-manager-send-file'. System app subsequently handover's
   1.619 +        // the data to alternate carrier's (BT / WiFi) 'sendFile' interface.
   1.620 +
   1.621 +        // Notify system app to initiate BT send file operation
   1.622 +        gSystemMessenger.broadcastMessage("nfc-manager-send-file",
   1.623 +                                           message.json);
   1.624 +        break;
   1.625 +      default:
   1.626 +        debug("UnSupported : Message Name " + message.name);
   1.627 +        return null;
   1.628 +    }
   1.629 +
   1.630 +    return null;
   1.631 +  },
   1.632 +
   1.633 +  setConfig: function setConfig(prop) {
   1.634 +    this.sendToWorker("config", prop);
   1.635 +  }
   1.636 +};
   1.637 +
   1.638 +if (NFC_ENABLED) {
   1.639 +  this.NSGetFactory = XPCOMUtils.generateNSGetFactory([Nfc]);
   1.640 +}

mercurial