summaryrefslogtreecommitdiffstats
path: root/dom/wifi/WifiP2pWorkerObserver.jsm
diff options
context:
space:
mode:
Diffstat (limited to 'dom/wifi/WifiP2pWorkerObserver.jsm')
-rw-r--r--dom/wifi/WifiP2pWorkerObserver.jsm319
1 files changed, 319 insertions, 0 deletions
diff --git a/dom/wifi/WifiP2pWorkerObserver.jsm b/dom/wifi/WifiP2pWorkerObserver.jsm
new file mode 100644
index 000000000..d04e8db5e
--- /dev/null
+++ b/dom/wifi/WifiP2pWorkerObserver.jsm
@@ -0,0 +1,319 @@
+/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
+
+const CONNECTION_STATUS_DISCONNECTED = "disconnected";
+const CONNECTION_STATUS_CONNECTING = "connecting";
+const CONNECTION_STATUS_CONNECTED = "connected";
+const CONNECTION_STATUS_DISCONNECTING = "disconnecting";
+
+const DEBUG = false;
+
+this.EXPORTED_SYMBOLS = ["WifiP2pWorkerObserver"];
+
+// WifiP2pWorkerObserver resides in WifiWorker to handle DOM message
+// by either 1) returning internally maintained information or
+// 2) delegating to aDomMsgResponder. It is also responsible
+// for observing events from WifiP2pManager and dispatch to DOM.
+//
+// @param aDomMsgResponder handles DOM messages, including
+// - setScanEnabled
+// - connect
+// - disconnect
+// - setPairingConfirmation
+// The instance is actually WifiP2pManager.
+this.WifiP2pWorkerObserver = function(aDomMsgResponder) {
+ function debug(aMsg) {
+ if (DEBUG) {
+ dump('-------------- WifiP2pWorkerObserver: ' + aMsg);
+ }
+ }
+
+ // Private member variables.
+ let _localDevice;
+ let _peerList = {}; // List of P2pDevice.
+ let _domManagers = [];
+ let _enabled = false;
+ let _groupOwner = null;
+ let _currentPeer = null;
+
+ // Constructor of P2pDevice. It will be exposed to DOM.
+ //
+ // @param aPeer object representing a P2P device:
+ // .name: string for the device name.
+ // .address: Mac address.
+ // .isGroupOwner: boolean to indicate if this device is the group owner.
+ // .wpsCapabilities: array of string of {"pbc", "display", "keypad"}.
+ function P2pDevice(aPeer) {
+ this.address = aPeer.address;
+ this.name = (aPeer.name ? aPeer.name : aPeer.address);
+ this.isGroupOwner = aPeer.isGroupOwner;
+ this.wpsCapabilities = aPeer.wpsCapabilities;
+ this.connectionStatus = CONNECTION_STATUS_DISCONNECTED;
+
+ // Since this object will be exposed to web, defined the exposed
+ // properties here.
+ this.__exposedProps__ = {
+ address: "r",
+ name: "r",
+ isGroupOwner: "r",
+ wpsCapabilities: "r",
+ connectionStatus: "r"
+ };
+ }
+
+ // Constructor of P2pGroupOwner.
+ //
+ // @param aGroupOwner:
+ // .macAddress
+ // .ipAddress
+ // .passphrase
+ // .ssid
+ // .freq
+ // .isLocal
+ function P2pGroupOwner(aGroupOwner) {
+ this.macAddress = aGroupOwner.macAddress; // The identifier to get further information.
+ this.ipAddress = aGroupOwner.ipAddress;
+ this.passphrase = aGroupOwner.passphrase;
+ this.ssid = aGroupOwner.ssid; // e.g. DIRECT-xy.
+ this.freq = aGroupOwner.freq;
+ this.isLocal = aGroupOwner.isLocal;
+
+ let detail = _peerList[aGroupOwner.macAddress];
+ if (detail) {
+ this.name = detail.name;
+ this.wpsCapabilities = detail.wpsCapabilities;
+ } else if (_localDevice.address === this.macAddress) {
+ this.name = _localDevice.name;
+ this.wpsCapabilities = _localDevice.wpsCapabilities;
+ } else {
+ debug("We don't know this group owner: " + aGroupOwner.macAddress);
+ this.name = aGroupOwner.macAddress;
+ this.wpsCapabilities = [];
+ }
+ }
+
+ function fireEvent(aMessage, aData) {
+ debug('domManager: ' + JSON.stringify(_domManagers));
+ _domManagers.forEach(function(manager) {
+ // Note: We should never have a dead message manager here because we
+ // observe our child message managers shutting down below.
+ manager.sendAsyncMessage("WifiP2pManager:" + aMessage, aData);
+ });
+ }
+
+ function addDomManager(aMsg) {
+ if (-1 === _domManagers.indexOf(aMsg.manager)) {
+ _domManagers.push(aMsg.manager);
+ }
+ }
+
+ function returnMessage(aMessage, aSuccess, aData, aMsg) {
+ let rMsg = aMessage + ":Return:" + (aSuccess ? "OK" : "NO");
+ aMsg.manager.sendAsyncMessage(rMsg,
+ { data: aData, rid: aMsg.rid, mid: aMsg.mid });
+ }
+
+ function handlePeerListUpdated() {
+ fireEvent("onpeerinfoupdate", {});
+ }
+
+ // Return a literal object as the constructed object.
+ return {
+ onLocalDeviceChanged: function(aDevice) {
+ _localDevice = aDevice;
+ debug('Local device updated to: ' + JSON.stringify(_localDevice));
+ },
+
+ onEnabled: function() {
+ _peerList = [];
+ _enabled = true;
+ fireEvent("p2pUp", {});
+ },
+
+ onDisbaled: function() {
+ _enabled = false;
+ fireEvent("p2pDown", {});
+ },
+
+ onPeerFound: function(aPeer) {
+ let newFoundPeer = new P2pDevice(aPeer);
+ let origianlPeer = _peerList[aPeer.address];
+ _peerList[aPeer.address] = newFoundPeer;
+ if (origianlPeer) {
+ newFoundPeer.connectionStatus = origianlPeer.connectionStatus;
+ }
+ handlePeerListUpdated();
+ },
+
+ onPeerLost: function(aPeer) {
+ let lostPeer = _peerList[aPeer.address];
+ if (!lostPeer) {
+ debug('Unknown peer lost: ' + aPeer.address);
+ return;
+ }
+ delete _peerList[aPeer.address];
+ handlePeerListUpdated();
+ },
+
+ onConnecting: function(aPeer) {
+ let peer = _peerList[aPeer.address];
+ if (!peer) {
+ debug('Unknown peer connecting: ' + aPeer.address);
+ peer = new P2pDevice(aPeer);
+ _peerList[aPeer.address] = peer;
+ handlePeerListUpdated();
+ }
+ peer.connectionStatus = CONNECTION_STATUS_CONNECTING;
+
+ fireEvent('onconnecting', { peer: peer });
+ },
+
+ onConnected: function(aGroupOwner, aPeer) {
+ let go = new P2pGroupOwner(aGroupOwner);
+ let peer = _peerList[aPeer.address];
+ if (!peer) {
+ debug('Unknown peer connected: ' + aPeer.address);
+ peer = new P2pDevice(aPeer);
+ _peerList[aPeer.address] = peer;
+ handlePeerListUpdated();
+ }
+ peer.connectionStatus = CONNECTION_STATUS_CONNECTED;
+ peer.isGroupOwner = (aPeer.address === aGroupOwner.address);
+
+ _groupOwner = go;
+ _currentPeer = peer;
+
+ fireEvent('onconnected', { groupOwner: go, peer: peer });
+ },
+
+ onDisconnected: function(aPeer) {
+ let peer = _peerList[aPeer.address];
+ if (!peer) {
+ debug('Unknown peer disconnected: ' + aPeer.address);
+ return;
+ }
+
+ peer.connectionStatus = CONNECTION_STATUS_DISCONNECTED;
+
+ _groupOwner = null;
+ _currentPeer = null;
+
+ fireEvent('ondisconnected', { peer: peer });
+ },
+
+ getObservedDOMMessages: function() {
+ return [
+ "WifiP2pManager:getState",
+ "WifiP2pManager:getPeerList",
+ "WifiP2pManager:setScanEnabled",
+ "WifiP2pManager:connect",
+ "WifiP2pManager:disconnect",
+ "WifiP2pManager:setPairingConfirmation",
+ "WifiP2pManager:setDeviceName"
+ ];
+ },
+
+ onDOMMessage: function(aMessage) {
+ let msg = aMessage.data || {};
+ msg.manager = aMessage.target;
+
+ if ("child-process-shutdown" === aMessage.name) {
+ let i;
+ if (-1 !== (i = _domManagers.indexOf(msg.manager))) {
+ _domManagers.splice(i, 1);
+ }
+ return;
+ }
+
+ if (!aMessage.target.assertPermission("wifi-manage")) {
+ return;
+ }
+
+ switch (aMessage.name) {
+ case "WifiP2pManager:getState": // A new DOM manager is created.
+ addDomManager(msg);
+ return { // Synchronous call. Simply return it.
+ enabled: _enabled,
+ groupOwner: _groupOwner,
+ currentPeer: _currentPeer
+ };
+
+ case "WifiP2pManager:setScanEnabled":
+ {
+ let enabled = msg.data;
+
+ aDomMsgResponder.setScanEnabled(enabled, function(success) {
+ returnMessage(aMessage.name, success, (success ? true : "ERROR"), msg);
+ });
+ }
+ break;
+
+ case "WifiP2pManager:getPeerList":
+ {
+ // Convert the object to an array.
+ let peerArray = [];
+ for (let key in _peerList) {
+ if (_peerList.hasOwnProperty(key)) {
+ peerArray.push(_peerList[key]);
+ }
+ }
+
+ returnMessage(aMessage.name, true, peerArray, msg);
+ }
+ break;
+
+ case "WifiP2pManager:connect":
+ {
+ let peer = msg.data;
+
+ let onDoConnect = function(success) {
+ returnMessage(aMessage.name, success, (success ? true : "ERROR"), msg);
+ };
+
+ aDomMsgResponder.connect(peer.address, peer.wpsMethod,
+ peer.goIntent, onDoConnect);
+ }
+ break;
+
+ case "WifiP2pManager:disconnect":
+ {
+ let address = msg.data;
+
+ aDomMsgResponder.disconnect(address, function(success) {
+ returnMessage(aMessage.name, success, (success ? true : "ERROR"), msg);
+ });
+ }
+ break;
+
+ case "WifiP2pManager:setPairingConfirmation":
+ {
+ let result = msg.data;
+ aDomMsgResponder.setPairingConfirmation(result);
+ returnMessage(aMessage.name, true, true, msg);
+ }
+ break;
+
+ case "WifiP2pManager:setDeviceName":
+ {
+ let newDeviceName = msg.data;
+ aDomMsgResponder.setDeviceName(newDeviceName, function(success) {
+ returnMessage(aMessage.name, success, (success ? true : "ERROR"), msg);
+ });
+ }
+ break;
+
+ default:
+ if (0 === aMessage.name.indexOf("WifiP2pManager:")) {
+ debug("DOM WifiP2pManager message not handled: " + aMessage.name);
+ }
+ } // End of switch.
+ }
+ };
+};