Skip to content
This repository has been archived by the owner on Nov 3, 2021. It is now read-only.

Commit

Permalink
Merge pull request #29240 from svic/Bug_1146744_v2.2
Browse files Browse the repository at this point in the history
Bug 1146744 - Don't call pair() on an already paired BT device
  • Loading branch information
rvandermeulen committed Apr 9, 2015
2 parents c1d66f9 + 272ef5b commit 0bfb78b
Show file tree
Hide file tree
Showing 3 changed files with 141 additions and 61 deletions.
150 changes: 97 additions & 53 deletions apps/system/js/nfc_handover_manager.js
Expand Up @@ -294,30 +294,93 @@ var NfcHandoverManager = {
},

/**
* Performs bluetooth pairing with other device
* @param {string} mac MAC address of the peer device
* Look for a paired device and invoke the appropriate callback function.
* @param {string} mac MAC address of the device
* @param {function} foundCb Found callback
* @param {function} notFoundCb Not found callback
* @memberof NfcHandoverManager.prototype
*/
_doPairing: function _doPairing(mac) {
this._debug('doPairing: ' + mac);
_findPairedDevice: function _findPairedDevice(mac, foundCb, notFoundCb) {
this._debug('_findPairedDevice');
if (this.defaultAdapter == null) {
// No BT
this._debug('No defaultAdapter');
return;
}
var req = this.defaultAdapter.pair(mac);
var self = this;
req.onsuccess = function() {
self._debug('Pairing succeeded');
self._clearBluetoothStatus();
self._doConnect(mac);

var req = this.defaultAdapter.getPairedDevices();
req.onsuccess = () => {
var devices = req.result;
this._debug('# devices: ' + devices.length);
for (var i = 0; i < devices.length; i++) {
var device = devices[i];
this._debug('Address: ' + device.address);
this._debug('Connected: ' + device.connected);
if (device.address.toLowerCase() === mac.toLowerCase()) {
this._debug('Found device ' + mac);
foundCb(device);
return;
}
}
if (notFoundCb) {
notFoundCb();
}
};
req.onerror = function() {
self._logVisibly('Pairing failed');
self._restoreBluetoothStatus();
req.onerror = () => {
this._logVisibly('Cannot get paired devices from adapter.');
};
},

/**
* Connects via bluetooth to the paired device.
* @param {string} device Device to be paired
* @memberof NfcHandoverManager.prototype
*/
_doConnect: function _doConnect(device) {
this._debug('doConnect with: ' + device.address);
var req = this.defaultAdapter.connect(device);
req.onsuccess = () => { this._debug('Connect succeeded'); };
req.onerror = () => { this._debug('Connect failed'); };
},

/**
* Performs bluetooth pairing with other device
* @param {string} mac MAC address of the peer device
* @memberof NfcHandoverManager.prototype
*/
_doPairing: function _doPairing(mac) {
this._debug('doPairing: ' + mac);

var alreadyPaired = (device) => {
this.defaultAdapter.connect(device);
};

var notYetPaired = () => {
this._debug('Device not yet paired');
var req = this.defaultAdapter.pair(mac);
req.onsuccess = () => {
this._debug('Pairing succeeded');
this._clearBluetoothStatus();
/*
* Bug 979427:
* After pairing we connect to the remote device. The only thing we
* know here is the MAC address, but the defaultAdapter.connect()
* requires a BluetoothDevice argument. So we use _findPairedDevice()
* to map the MAC to a BluetoothDevice instance.
*/
this._findPairedDevice(mac, (device) => {
this.defaultAdapter.connect(device);
});
};
req.onerror = () => {
this._logVisibly('Pairing failed');
this._restoreBluetoothStatus();
};
};

this._findPairedDevice(mac, alreadyPaired, notYetPaired);
},

/**
* Show an error notification when file transfer failed.
* @param {String} msg Optional message.
Expand Down Expand Up @@ -484,44 +547,6 @@ var NfcHandoverManager = {
this.responseTimeoutMillis);
},

/**
* Connects via bluetooth to the paired device.
* @param {string} mac MAC addres of the paired device
* @memberof NfcHandoverManager.prototype
*/
_doConnect: function _doConnect(mac) {
this._debug('doConnect with: ' + mac);
/*
* Bug 979427:
* After pairing we connect to the remote device. The only thing we
* know here is the MAC address, but the defaultAdapter.connect()
* requires a BluetoothDevice argument. So we use getPairedDevices()
* to map the MAC to a BluetoothDevice instance.
*/
var req = this.defaultAdapter.getPairedDevices();
var self = this;
req.onsuccess = function() {
var devices = req.result;
self._debug('# devices: ' + devices.length);
var successCb = function() { self._debug('Connect succeeded'); };
var errorCb = function() { self._debug('Connect failed'); };
for (var i = 0; i < devices.length; i++) {
var device = devices[i];
self._debug('Address: ' + device.address);
self._debug('Connected: ' + device.connected);
if (device.address.toLowerCase() == mac.toLowerCase()) {
self._debug('Connecting to ' + mac);
var r = self.defaultAdapter.connect(device);
r.onsuccess = successCb;
r.onerror = errorCb;
}
}
};
req.onerror = function() {
self._logVisibly('Cannot get paired devices from adapter.');
};
},

/**
* Clears timeout that handles the case an outstanding handover message
* has not been received within a certain timeframe.
Expand Down Expand Up @@ -568,6 +593,25 @@ var NfcHandoverManager = {
this.nfcConnectSystemDialog.show(btssp.localName, onconfirm, onabort);
},

/**
* Check if a device is already paired and connected.
* @param {Object} btssp BT SSP record
* @memberof NfcHandoverManager.prototype
*/
_checkConnected: function _checkConnected(btssp) {
if (!this.bluetooth.enabled) {
this._onRequestConnect(btssp);
return;
}
this._findPairedDevice(btssp.mac, (device) => {
if (!device.connected) {
this._onRequestConnect(btssp);
}
}, () => {
this._onRequestConnect(btssp);
});
},

/**
* Handles simplified pairing record.
* @param {Array} ndef NDEF message containing simplified pairing record
Expand All @@ -579,7 +623,7 @@ var NfcHandoverManager = {
var pairingRecord = ndef[0];
var btssp = NDEFUtils.parseBluetoothSSP(pairingRecord);
this._debug('Simplified pairing with: ' + btssp.mac);
this._onRequestConnect(btssp);
this._checkConnected(btssp);
},

/**
Expand Down Expand Up @@ -609,7 +653,7 @@ var NfcHandoverManager = {
this._doAction({callback: this._doFileTransfer, args: [btssp.mac]});
} else {
// This is a static handover
this._onRequestConnect(btssp);
this._checkConnected(btssp);
}
},

Expand Down
3 changes: 3 additions & 0 deletions apps/system/test/unit/mock_bluetooth.js
Expand Up @@ -48,6 +48,9 @@ var MockBluetooth = {
},
pair: function() {
return new MockDOMRequest();
},
connect: function() {
return new MockDOMRequest();
}
};
this.defaultAdapter = mockAdapater;
Expand Down
49 changes: 41 additions & 8 deletions apps/system/test/unit/nfc_handover_manager_test.js
Expand Up @@ -2,7 +2,7 @@

/* globals MocksHelper, MockBluetooth, MockNavigatorSettings,
NDEF, NfcConnectSystemDialog, MockBluetoothTransfer,
MockL10n, NfcHandoverManager, NDEFUtils,
MockDOMRequest, MockL10n, NfcHandoverManager, NDEFUtils,
MockMozNfc, NfcUtils, MockNavigatormozSetMessageHandler */

require('/shared/test/unit/mocks/mock_navigator_moz_set_message_handler.js');
Expand Down Expand Up @@ -99,6 +99,9 @@ suite('Nfc Handover Manager Functions', function() {
var activityInjection1;
var activityInjection2;
var nfcUtils;
var peerMac;
var pairedDevices;
var stubGetPairedDevices;

setup(function() {
nfcUtils = new NfcUtils();
Expand Down Expand Up @@ -131,14 +134,25 @@ suite('Nfc Handover Manager Functions', function() {
}],
peer: MockMozNfc.MockNFCPeer
};
peerMac = '01:23:45:67:89:AB';
pairedDevices = [{ address: peerMac, connected: false }];
stubGetPairedDevices = this.sinon.stub(MockBluetooth.defaultAdapter,
'getPairedDevices',
() => { return new MockDOMRequest(); });
NfcHandoverManager.init();
invokeBluetoothGetDefaultAdapter();
});

teardown(function() {
stubGetPairedDevices.restore();
});

test('nfc/HandoverSelect', function() {
var spyName = this.sinon.spy(NfcConnectSystemDialog.prototype, 'show');
var spyPairing = this.sinon.spy(NfcHandoverManager, '_doPairing');

NfcHandoverManager.tryHandover(activityInjection1.records,
activityInjection1.peer);
stubGetPairedDevices.firstCall.returnValue.fireSuccess([]);
assert.isTrue(spyName.withArgs('UE MINI BOOM').calledOnce);
assert.isTrue(spyPairing.withArgs('00:0D:44:E7:95:AB').calledOnce);
});
Expand All @@ -149,23 +163,36 @@ suite('Nfc Handover Manager Functions', function() {

NfcHandoverManager.tryHandover(activityInjection2.records,
activityInjection2.peer);
stubGetPairedDevices.firstCall.returnValue.fireSuccess([]);
assert.isTrue(spyName.withArgs('MBH10').calledOnce);
assert.isTrue(spyPairing.withArgs('4C:21:D0:9F:12:F1').calledOnce);
});

test('Attempts to connect to peer after pairing', function() {
var spyBluetoothPair = this.sinon.spy(MockBluetooth.defaultAdapter,
'pair');
var spyConnect = this.sinon.spy(NfcHandoverManager, '_doConnect');

NfcHandoverManager.init();
invokeBluetoothGetDefaultAdapter();
var spyConnect = this.sinon.spy(MockBluetooth.defaultAdapter, 'connect');

NfcHandoverManager._doPairing('01:23:45:67:89:AB');
NfcHandoverManager._doPairing(peerMac);
stubGetPairedDevices.firstCall.returnValue.fireSuccess([]);
spyBluetoothPair.firstCall.returnValue.fireSuccess();
stubGetPairedDevices.getCall(1).returnValue.fireSuccess(pairedDevices);

assert.isTrue(spyConnect.calledOnce);
assert.equal(spyConnect.firstCall.args[0], '01:23:45:67:89:AB');
assert.equal(spyConnect.firstCall.args[0].address, peerMac);
});

test('Attempts to connect to already paired peer', function() {
var spyBluetoothPair = this.sinon.spy(MockBluetooth.defaultAdapter,
'pair');
var spyConnect = this.sinon.spy(MockBluetooth.defaultAdapter, 'connect');

NfcHandoverManager._doPairing(peerMac);
stubGetPairedDevices.firstCall.returnValue.fireSuccess(pairedDevices);

assert.isTrue(spyBluetoothPair.notCalled);
assert.isTrue(spyConnect.calledOnce);
assert.equal(spyConnect.firstCall.args[0].address, peerMac);
});
});

Expand Down Expand Up @@ -210,8 +237,14 @@ suite('Nfc Handover Manager Functions', function() {
});

test('_handleHandoverSelect() attempts to pair BT devices', function() {
//MockBluetooth.enabled = false;
var stubGetPairedDevices = this.sinon.stub(MockBluetooth.defaultAdapter,
'getPairedDevices',
() => { return new MockDOMRequest(); });

var handoverSelect = NDEFUtils.encodeHandoverSelect(mac, cps);
NfcHandoverManager._handleHandoverSelect(handoverSelect);
stubGetPairedDevices.firstCall.returnValue.fireSuccess([]);

assert.isTrue(spyPairing.calledOnce);
assert.equal(mac, spyPairing.firstCall.args[0]);
Expand Down

0 comments on commit 0bfb78b

Please sign in to comment.