gecko/dom/bluetooth/tests/marionette/head.js

911 lines
27 KiB
JavaScript

/* 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/. */
// https://github.com/mozilla-b2g/platform_external_qemu/blob/master/vl-android.c#L765
// static int bt_hci_parse(const char *str) {
// ...
// bdaddr.b[0] = 0x52;
// bdaddr.b[1] = 0x54;
// bdaddr.b[2] = 0x00;
// bdaddr.b[3] = 0x12;
// bdaddr.b[4] = 0x34;
// bdaddr.b[5] = 0x56 + nb_hcis;
const EMULATOR_ADDRESS = "56:34:12:00:54:52";
// $ adb shell hciconfig /dev/ttyS2 name
// hci0: Type: BR/EDR Bus: UART
// BD Address: 56:34:12:00:54:52 ACL MTU: 512:1 SCO MTU: 0:0
// Name: 'Full Android on Emulator'
const EMULATOR_NAME = "Full Android on Emulator";
// $ adb shell hciconfig /dev/ttyS2 class
// hci0: Type: BR/EDR Bus: UART
// BD Address: 56:34:12:00:54:52 ACL MTU: 512:1 SCO MTU: 0:0
// Class: 0x58020c
// Service Classes: Capturing, Object Transfer, Telephony
// Device Class: Phone, Smart phone
const EMULATOR_CLASS = 0x58020c;
// Use same definition in QEMU for special bluetooth address,
// which were defined at external/qemu/hw/bt.h:
const BDADDR_ANY = "00:00:00:00:00:00";
const BDADDR_ALL = "ff:ff:ff:ff:ff:ff";
const BDADDR_LOCAL = "ff:ff:ff:00:00:00";
// A user friendly name for remote BT device.
const REMOTE_DEVICE_NAME = "Remote_BT_Device";
// Emulate Promise.jsm semantics.
Promise.defer = function() { return new Deferred(); }
function Deferred() {
this.promise = new Promise(function(resolve, reject) {
this.resolve = resolve;
this.reject = reject;
}.bind(this));
Object.freeze(this);
}
var bluetoothManager;
var pendingEmulatorCmdCount = 0;
/**
* Push required permissions and test if |navigator.mozBluetooth| exists.
* Resolve if it does, reject otherwise.
*
* Fulfill params:
* bluetoothManager -- an reference to navigator.mozBluetooth.
* Reject params: (none)
*
* @param aPermissions
* Additional permissions to push before any test cases. Could be either
* a string or an array of strings.
*
* @return A deferred promise.
*/
function ensureBluetoothManager(aPermissions) {
let deferred = Promise.defer();
let permissions = ["bluetooth"];
if (aPermissions) {
if (Array.isArray(aPermissions)) {
permissions = permissions.concat(aPermissions);
} else if (typeof aPermissions == "string") {
permissions.push(aPermissions);
}
}
let obj = [];
for (let perm of permissions) {
obj.push({
"type": perm,
"allow": 1,
"context": document,
});
}
SpecialPowers.pushPermissions(obj, function() {
ok(true, "permissions pushed: " + JSON.stringify(permissions));
bluetoothManager = window.navigator.mozBluetooth;
log("navigator.mozBluetooth is " +
(bluetoothManager ? "available" : "unavailable"));
if (bluetoothManager instanceof BluetoothManager) {
deferred.resolve(bluetoothManager);
} else {
deferred.reject();
}
});
return deferred.promise;
}
/**
* Send emulator command with safe guard.
*
* We should only call |finish()| after all emulator command transactions
* end, so here comes with the pending counter. Resolve when the emulator
* gives positive response, and reject otherwise.
*
* Fulfill params:
* result -- an array of emulator response lines.
*
* Reject params:
* result -- an array of emulator response lines.
*
* @return A deferred promise.
*/
function runEmulatorCmdSafe(aCommand) {
let deferred = Promise.defer();
++pendingEmulatorCmdCount;
runEmulatorCmd(aCommand, function(aResult) {
--pendingEmulatorCmdCount;
ok(true, "Emulator response: " + JSON.stringify(aResult));
if (Array.isArray(aResult) && aResult[aResult.length - 1] === "OK") {
deferred.resolve(aResult);
} else {
ok(false, "Got an abnormal response from emulator.");
log("Fail to execute emulator command: [" + aCommand + "]");
deferred.reject(aResult);
}
});
return deferred.promise;
}
/**
* Add a Bluetooth remote device to scatternet and set its properties.
*
* Use QEMU command 'bt remote add' to add a virtual Bluetooth remote
* and set its properties by setEmulatorDeviceProperty().
*
* Fulfill params:
* result -- bluetooth address of the remote device.
* Reject params: (none)
*
* @param aProperies
* A javascript object with zero or several properties for initializing
* the remote device. By now, the properies could be 'name' or
* 'discoverable'. It valid to put a null object or a javascript object
* which don't have any properies.
*
* @return A promise object.
*/
function addEmulatorRemoteDevice(aProperties) {
let address;
let promise = runEmulatorCmdSafe("bt remote add")
.then(function(aResults) {
address = aResults[0].toUpperCase();
});
for (let key in aProperties) {
let value = aProperties[key];
let propertyName = key;
promise = promise.then(function() {
return setEmulatorDeviceProperty(address, propertyName, value);
});
}
return promise.then(function() {
return address;
});
}
/**
* Remove Bluetooth remote devices in scatternet.
*
* Use QEMU command 'bt remote remove <addr>' to remove a specific virtual
* Bluetooth remote device in scatternet or remove them all by QEMU command
* 'bt remote remove BDADDR_ALL'.
*
* @param aAddress
* The string of Bluetooth address with format xx:xx:xx:xx:xx:xx.
*
* Fulfill params:
* result -- an array of emulator response lines.
* Reject params: (none)
*
* @return A promise object.
*/
function removeEmulatorRemoteDevice(aAddress) {
let cmd = "bt remote remove " + aAddress;
return runEmulatorCmdSafe(cmd)
.then(function(aResults) {
// 'bt remote remove <bd_addr>' returns a list of removed device one at a line.
// The last item is "OK".
return aResults.slice(0, -1);
});
}
/**
* Set a property for a Bluetooth device.
*
* Use QEMU command 'bt property <bd_addr> <prop_name> <value>' to set property.
*
* Fulfill params:
* result -- an array of emulator response lines.
* Reject params:
* result -- an array of emulator response lines.
*
* @param aAddress
* The string of Bluetooth address with format xx:xx:xx:xx:xx:xx.
* @param aPropertyName
* The property name of Bluetooth device.
* @param aValue
* The new value of the specifc property.
*
* @return A deferred promise.
*/
function setEmulatorDeviceProperty(aAddress, aPropertyName, aValue) {
let cmd = "bt property " + aAddress + " " + aPropertyName + " " + aValue;
return runEmulatorCmdSafe(cmd);
}
/**
* Get a property from a Bluetooth device.
*
* Use QEMU command 'bt property <bd_addr> <prop_name>' to get properties.
*
* Fulfill params:
* result -- a string with format <prop_name>: <value_of_prop>
* Reject params:
* result -- an array of emulator response lines.
*
* @param aAddress
* The string of Bluetooth address with format xx:xx:xx:xx:xx:xx.
* @param aPropertyName
* The property name of Bluetooth device.
*
* @return A deferred promise.
*/
function getEmulatorDeviceProperty(aAddress, aPropertyName) {
let cmd = "bt property " + aAddress + " " + aPropertyName;
return runEmulatorCmdSafe(cmd)
.then(function(aResults) {
return aResults[0];
});
}
/**
* Get mozSettings value specified by @aKey.
*
* Resolve if that mozSettings value is retrieved successfully, reject
* otherwise.
*
* Fulfill params:
* The corresponding mozSettings value of the key.
* Reject params: (none)
*
* @param aKey
* A string.
*
* @return A deferred promise.
*/
function getSettings(aKey) {
let deferred = Promise.defer();
let request = navigator.mozSettings.createLock().get(aKey);
request.addEventListener("success", function(aEvent) {
ok(true, "getSettings(" + aKey + ")");
deferred.resolve(aEvent.target.result[aKey]);
});
request.addEventListener("error", function() {
ok(false, "getSettings(" + aKey + ")");
deferred.reject();
});
return deferred.promise;
}
/**
* Set mozSettings values.
*
* Resolve if that mozSettings value is set successfully, reject otherwise.
*
* Fulfill params: (none)
* Reject params: (none)
*
* @param aSettings
* An object of format |{key1: value1, key2: value2, ...}|.
*
* @return A deferred promise.
*/
function setSettings(aSettings) {
let lock = window.navigator.mozSettings.createLock();
let request = lock.set(aSettings);
let deferred = Promise.defer();
lock.onsettingstransactionsuccess = function () {
ok(true, "setSettings(" + JSON.stringify(aSettings) + ")");
deferred.resolve();
};
lock.onsettingstransactionfailure = function (aEvent) {
ok(false, "setSettings(" + JSON.stringify(aSettings) + ")");
deferred.reject();
};
return deferred.promise;
}
/**
* Get the boolean value which indicates defaultAdapter of bluetooth is enabled.
*
* Resolve if that defaultAdapter is enabled
*
* Fulfill params:
* A boolean value.
* Reject params: (none)
*
* @return A deferred promise.
*/
function getBluetoothEnabled() {
log("bluetoothManager.defaultAdapter.state: " + bluetoothManager.defaultAdapter.state);
return (bluetoothManager.defaultAdapter.state == "enabled");
}
/**
* Set mozSettings value of 'bluetooth.enabled'.
*
* Resolve if that mozSettings value is set successfully, reject otherwise.
*
* Fulfill params: (none)
* Reject params: (none)
*
* @param aEnabled
* A boolean value.
*
* @return A deferred promise.
*/
function setBluetoothEnabled(aEnabled) {
let obj = {};
obj["bluetooth.enabled"] = aEnabled;
return setSettings(obj);
}
/**
* Wait for one named BluetoothManager event.
*
* Resolve if that named event occurs. Never reject.
*
* Fulfill params: the DOMEvent passed.
*
* @param aEventName
* The name of the EventHandler.
*
* @return A deferred promise.
*/
function waitForManagerEvent(aEventName) {
let deferred = Promise.defer();
bluetoothManager.addEventListener(aEventName, function onevent(aEvent) {
bluetoothManager.removeEventListener(aEventName, onevent);
ok(true, "BluetoothManager event '" + aEventName + "' got.");
deferred.resolve(aEvent);
});
return deferred.promise;
}
/**
* Wait for one named BluetoothAdapter event.
*
* Resolve if that named event occurs. Never reject.
*
* Fulfill params: the DOMEvent passed.
*
* @param aAdapter
* The BluetoothAdapter you want to use.
* @param aEventName
* The name of the EventHandler.
*
* @return A deferred promise.
*/
function waitForAdapterEvent(aAdapter, aEventName) {
let deferred = Promise.defer();
aAdapter.addEventListener(aEventName, function onevent(aEvent) {
aAdapter.removeEventListener(aEventName, onevent);
ok(true, "BluetoothAdapter event '" + aEventName + "' got.");
deferred.resolve(aEvent);
});
return deferred.promise;
}
/**
* Wait for 'onattributechanged' events for state changes of BluetoothAdapter
* with specified order.
*
* Resolve if those expected events occur in order. Never reject.
*
* Fulfill params: an array which contains every changed attributes during
* the waiting.
*
* @param aAdapter
* The BluetoothAdapter you want to use.
* @param aStateChangesInOrder
* An array which contains an expected order of BluetoothAdapterState.
* Example 1: [enabling, enabled]
* Example 2: [disabling, disabled]
*
* @return A deferred promise.
*/
function waitForAdapterStateChanged(aAdapter, aStateChangesInOrder) {
let deferred = Promise.defer();
let stateIndex = 0;
let prevStateIndex = 0;
let statesArray = [];
let changedAttrs = [];
aAdapter.onattributechanged = function(aEvent) {
for (let i in aEvent.attrs) {
changedAttrs.push(aEvent.attrs[i]);
switch (aEvent.attrs[i]) {
case "state":
log(" 'state' changed to " + aAdapter.state);
// Received state change order may differ from expected one even though
// state changes in expected order, because the value of state may change
// again before we receive prior 'onattributechanged' event.
//
// For example, expected state change order [A,B,C] may result in
// received ones:
// - [A,C,C] if state becomes C before we receive 2nd 'onattributechanged'
// - [B,B,C] if state becomes B before we receive 1st 'onattributechanged'
// - [C,C,C] if state becomes C before we receive 1st 'onattributechanged'
// - [A,B,C] if all 'onattributechanged' are received in perfect timing
//
// As a result, we ensure only following conditions instead of exactly
// matching received and expected state change order.
// - Received state change order never reverse expected one. For example,
// [B,A,C] should never occur with expected state change order [A,B,C].
// - The changed value of state in received state change order never
// appears later than that in expected one. For example, [A,A,C] should
// never occur with expected state change order [A,B,C].
let stateIndex = aStateChangesInOrder.indexOf(aAdapter.state);
if (stateIndex >= prevStateIndex && stateIndex + 1 > statesArray.length) {
statesArray.push(aAdapter.state);
prevStateIndex = stateIndex;
if (statesArray.length == aStateChangesInOrder.length) {
aAdapter.onattributechanged = null;
ok(true, "BluetoothAdapter event 'onattributechanged' got.");
deferred.resolve(changedAttrs);
}
} else {
ok(false, "The order of 'onattributechanged' events is unexpected.");
}
break;
case "name":
log(" 'name' changed to " + aAdapter.name);
if (aAdapter.state == "enabling") {
isnot(aAdapter.name, "", "adapter.name");
}
else if (aAdapter.state == "disabling") {
is(aAdapter.name, "", "adapter.name");
}
break;
case "address":
log(" 'address' changed to " + aAdapter.address);
if (aAdapter.state == "enabling") {
isnot(aAdapter.address, "", "adapter.address");
}
else if (aAdapter.state == "disabling") {
is(aAdapter.address, "", "adapter.address");
}
break;
case "discoverable":
log(" 'discoverable' changed to " + aAdapter.discoverable);
if (aAdapter.state == "enabling") {
is(aAdapter.discoverable, true, "adapter.discoverable");
}
else if (aAdapter.state == "disabling") {
is(aAdapter.discoverable, false, "adapter.discoverable");
}
break;
case "discovering":
log(" 'discovering' changed to " + aAdapter.discovering);
if (aAdapter.state == "enabling") {
is(aAdapter.discovering, true, "adapter.discovering");
}
else if (aAdapter.state == "disabling") {
is(aAdapter.discovering, false, "adapter.discovering");
}
break;
case "unknown":
default:
ok(false, "Unknown attribute '" + aEvent.attrs[i] + "' changed." );
break;
}
}
};
return deferred.promise;
}
/**
* Wait for an 'onattributechanged' event for a specified attribute and compare
* the new value with the expected value.
*
* Resolve if the specified event occurs. Never reject.
*
* Fulfill params: a BluetoothAttributeEvent with property attrs that contains
* changed BluetoothAdapterAttributes.
*
* @param aAdapter
* The BluetoothAdapter you want to use.
* @param aAttrName
* The name of the attribute of adapter.
* @param aExpectedValue
* The expected new value of the attribute.
*
* @return A deferred promise.
*/
function waitForAdapterAttributeChanged(aAdapter, aAttrName, aExpectedValue) {
let deferred = Promise.defer();
aAdapter.onattributechanged = function(aEvent) {
let i = aEvent.attrs.indexOf(aAttrName);
if (i >= 0) {
switch (aEvent.attrs[i]) {
case "state":
log(" 'state' changed to " + aAdapter.state);
is(aAdapter.state, aExpectedValue, "adapter.state");
break;
case "name":
log(" 'name' changed to " + aAdapter.name);
is(aAdapter.name, aExpectedValue, "adapter.name");
break;
case "address":
log(" 'address' changed to " + aAdapter.address);
is(aAdapter.address, aExpectedValue, "adapter.address");
break;
case "discoverable":
log(" 'discoverable' changed to " + aAdapter.discoverable);
is(aAdapter.discoverable, aExpectedValue, "adapter.discoverable");
break;
case "discovering":
log(" 'discovering' changed to " + aAdapter.discovering);
is(aAdapter.discovering, aExpectedValue, "adapter.discovering");
break;
case "unknown":
default:
ok(false, "Unknown attribute '" + aAttrName + "' changed." );
break;
}
aAdapter.onattributechanged = null;
deferred.resolve(aEvent);
}
};
return deferred.promise;
}
/**
* Wait for specified number of 'devicefound' events.
*
* Resolve if specified number of devices has been found. Never reject.
*
* Fulfill params: an array which contains BluetoothDeviceEvents that we
* received from the BluetoothDiscoveryHandle.
*
* @param aDiscoveryHandle
* A BluetoothDiscoveryHandle which is used to notify application of
* discovered remote bluetooth devices.
* @param aExpectedNumberOfDevices
* The number of remote devices we expect to discover.
*
* @return A deferred promise.
*/
function waitForDevicesFound(aDiscoveryHandle, aExpectedNumberOfDevices) {
let deferred = Promise.defer();
ok(aDiscoveryHandle instanceof BluetoothDiscoveryHandle,
"aDiscoveryHandle should be a BluetoothDiscoveryHandle");
let devicesArray = [];
aDiscoveryHandle.ondevicefound = function onDeviceFound(aEvent) {
ok(aEvent instanceof BluetoothDeviceEvent,
"aEvent should be a BluetoothDeviceEvent");
devicesArray.push(aEvent);
if (devicesArray.length >= aExpectedNumberOfDevices) {
aDiscoveryHandle.ondevicefound = null;
deferred.resolve(devicesArray);
}
};
return deferred.promise;
}
/**
* Wait for 'devicefound' events of specified devices.
*
* Resolve if every specified device has been found. Never reject.
*
* Fulfill params: an array which contains the BluetoothDeviceEvents that we
* expected to receive from the BluetoothDiscoveryHandle.
*
* @param aDiscoveryHandle
* A BluetoothDiscoveryHandle which is used to notify application of
* discovered remote bluetooth devices.
* @param aRemoteAddresses
* An array which contains addresses of remote devices.
*
* @return A deferred promise.
*/
function waitForSpecifiedDevicesFound(aDiscoveryHandle, aRemoteAddresses) {
let deferred = Promise.defer();
ok(aDiscoveryHandle instanceof BluetoothDiscoveryHandle,
"aDiscoveryHandle should be a BluetoothDiscoveryHandle");
let devicesArray = [];
aDiscoveryHandle.ondevicefound = function onDeviceFound(aEvent) {
ok(aEvent instanceof BluetoothDeviceEvent,
"aEvent should be a BluetoothDeviceEvent");
if (aRemoteAddresses.indexOf(aEvent.device.address) != -1) {
devicesArray.push(aEvent);
}
if (devicesArray.length == aRemoteAddresses.length) {
aDiscoveryHandle.ondevicefound = null;
ok(true, "BluetoothAdapter has found all remote devices.");
deferred.resolve(devicesArray);
}
};
return deferred.promise;
}
/**
* Verify the correctness of 'devicepaired' or 'deviceunpaired' events.
*
* Use BluetoothAdapter.getPairedDevices() to get current device array.
* Resolve if the device of from 'devicepaired' event exists in device array or
* the device of address from 'deviceunpaired' event has been removed from
* device array.
* Otherwise, reject the promise.
*
* Fulfill params: the device event from 'devicepaired' or 'deviceunpaired'.
*
* @param aAdapter
* The BluetoothAdapter you want to use.
* @param aDeviceEvent
* The device event from "devicepaired" or "deviceunpaired".
*
* @return A deferred promise.
*/
function verifyDevicePairedUnpairedEvent(aAdapter, aDeviceEvent) {
let deferred = Promise.defer();
let devices = aAdapter.getPairedDevices();
let isPromisePending = true;
if (aDeviceEvent.device) {
log(" - Verify 'devicepaired' event");
for (let i in devices) {
if (devices[i].address == aDeviceEvent.device.address) {
deferred.resolve(aDeviceEvent);
isPromisePending = false;
}
}
if (isPromisePending) {
deferred.reject(aDeviceEvent);
isPromisePending = false;
}
} else if (aDeviceEvent.address) {
log(" - Verify 'deviceunpaired' event");
for (let i in devices) {
if (devices[i].address == aDeviceEvent.address) {
deferred.reject(aDeviceEvent);
isPromisePending = false;
}
}
if (isPromisePending) {
deferred.resolve(aDeviceEvent);
isPromisePending = false;
}
} else {
log(" - Exception occurs. Unexpected aDeviceEvent properties.");
deferred.reject(aDeviceEvent);
isPromisePending = false;
}
return deferred.promise;
}
/**
* Add event handlers for pairing request listener.
*
* @param aAdapter
* The BluetoothAdapter you want to use.
* @param aSpecifiedBdAddress (optional)
* Bluetooth address of the specified remote device which adapter wants
* to pair with. If aSpecifiedBdAddress is an empty string, 'null' or
* 'undefined', this function accepts every pairing request.
*/
function addEventHandlerForPairingRequest(aAdapter, aSpecifiedBdAddress) {
log(" - Add event handlers for pairing requests.");
aAdapter.pairingReqs.ondisplaypasskeyreq = function onDisplayPasskeyReq(evt) {
let passkey = evt.handle.passkey; // passkey to display
ok(typeof passkey === 'string', "type checking for passkey.");
log(" - Received 'ondisplaypasskeyreq' event with passkey: " + passkey);
let device = evt.device;
if (!aSpecifiedBdAddress || device.address == aSpecifiedBdAddress) {
cleanupPairingListener(aAdapter.pairingReqs);
}
};
aAdapter.pairingReqs.onenterpincodereq = function onEnterPinCodeReq(evt) {
log(" - Received 'onenterpincodereq' event.");
let device = evt.device;
if (!aSpecifiedBdAddress || device.address == aSpecifiedBdAddress) {
// TODO: Allow user to enter pincode.
let UserEnteredPinCode = "0000";
let pinCode = UserEnteredPinCode;
evt.handle.setPinCode(pinCode).then(
function onResolve() {
log(" - 'setPinCode' resolve.");
cleanupPairingListener(aAdapter.pairingReqs);
},
function onReject() {
log(" - 'setPinCode' reject.");
cleanupPairingListener(aAdapter.pairingReqs);
});
}
};
aAdapter.pairingReqs.onpairingconfirmationreq
= function onPairingConfirmationReq(evt) {
let passkey = evt.handle.passkey; // passkey for user to confirm
ok(typeof passkey === 'string', "type checking for passkey.");
log(" - Received 'onpairingconfirmationreq' event with passkey: " + passkey);
let device = evt.device;
if (!aSpecifiedBdAddress || device.address == aSpecifiedBdAddress) {
evt.handle.accept().then(
function onResolve() {
log(" - 'accept' resolve.");
cleanupPairingListener(aAdapter.pairingReqs);
},
function onReject() {
log(" - 'accept' reject.");
cleanupPairingListener(aAdapter.pairingReqs);
});
}
};
aAdapter.pairingReqs.onpairingconsentreq = function onPairingConsentReq(evt) {
log(" - Received 'onpairingconsentreq' event.");
let device = evt.device;
if (!aSpecifiedBdAddress || device.address == aSpecifiedBdAddress) {
evt.handle.accept().then(
function onResolve() {
log(" - 'accept' resolve.");
cleanupPairingListener(aAdapter.pairingReqs);
},
function onReject() {
log(" - 'accept' reject.");
cleanupPairingListener(aAdapter.pairingReqs);
});
}
};
}
/**
* Clean up event handlers for pairing listener.
*
* @param aPairingReqs
* A BluetoothPairingListener with event handlers.
*/
function cleanupPairingListener(aPairingReqs) {
aPairingReqs.ondisplaypasskeyreq = null;
aPairingReqs.onenterpasskeyreq = null;
aPairingReqs.onpairingconfirmationreq = null;
aPairingReqs.onpairingconsentreq = null;
}
/**
* Compare two uuid arrays to see if them are the same.
*
* @param aUuidArray1
* An array which contains uuid strings.
* @param aUuidArray2
* Another array which contains uuid strings.
*
* @return A boolean value.
*/
function isUuidsEqual(aUuidArray1, aUuidArray2) {
if (!Array.isArray(aUuidArray1) || !Array.isArray(aUuidArray2)) {
return false;
}
if (aUuidArray1.length != aUuidArray2.length) {
return false;
}
for (let i = 0, l = aUuidArray1.length; i < l; i++) {
if (aUuidArray1[i] != aUuidArray2[i]) {
return false;
}
}
return true;
}
/**
* Wait for pending emulator transactions and call |finish()|.
*/
function cleanUp() {
// Use ok here so that we have at least one test run.
ok(true, ":: CLEANING UP ::");
waitFor(finish, function() {
return pendingEmulatorCmdCount === 0;
});
}
function startBluetoothTestBase(aPermissions, aTestCaseMain) {
ensureBluetoothManager(aPermissions)
.then(function() {
log("Wait for creating bluetooth adapter...");
return waitForManagerStateChanged(bluetoothManager);
})
.then(aTestCaseMain)
.then(cleanUp, function() {
ok(false, "Unhandled rejected promise.");
cleanUp();
});
}
function startBluetoothTest(aReenable, aTestCaseMain) {
startBluetoothTestBase([], function() {
let origEnabled, needEnable;
return Promise.resolve()
.then(function() {
origEnabled = getBluetoothEnabled();
needEnable = !origEnabled;
log("Original state of bluetooth is " + bluetoothManager.defaultAdapter.state);
if (origEnabled && aReenable) {
log("Disable Bluetooth ...");
needEnable = true;
isnot(bluetoothManager.defaultAdapter, null,
"bluetoothManager.defaultAdapter")
return bluetoothManager.defaultAdapter.disable();
}
})
.then(function() {
if (needEnable) {
log("Enable Bluetooth ...");
isnot(bluetoothManager.defaultAdapter, null,
"bluetoothManager.defaultAdapter")
return bluetoothManager.defaultAdapter.enable();
}
})
.then(() => bluetoothManager.defaultAdapter)
.then(aTestCaseMain)
.then(function() {
if (!origEnabled) {
log("Disable Bluetooth ...");
return bluetoothManager.defaultAdapter.disable();
}
});
});
}
function waitForManagerStateChanged(aManager) {
let deferred = Promise.defer();
aManager.onattributechanged = function(evt) {
for (var i in evt.attrs) {
switch (evt.attrs[i]) {
case 'defaultAdapter':
deferred.resolve(evt);
break;
default:
break;
}
}
}
return deferred.promise;
}