/** * BluetoothContext: * - BluetoothContext is an Observable that wraps the platform Bluetooth * object. * - BluetoothContext is a singleton that you can easily use it to fetch some * shared data across different panels. * - It has some observable properties: state, enabled, address, name, * discoverable, discovering, numberOfPairedDevices, firstPairedDeviceName, * hasPairedDevice. * - It has two observable array: _pairedDevices, _remoteDevices. * BluetoothContext only update state and does not involve in any UI logic. * * @module BluetoothContext */ define(function(require) { 'use strict'; var AdapterManager = require('modules/bluetooth/bluetooth_adapter_manager'); var BtDevice = require('modules/bluetooth/bluetooth_device'); var ConnectionManager = require('modules/bluetooth/bluetooth_connection_manager'); var Observable = require('modules/mvvm/observable'); var ObservableArray = require('modules/mvvm/observable_array'); var SettingsCache = require('modules/settings_cache'); var settings = navigator.mozSettings; var _debug = false; var debug = function() {}; if (_debug) { debug = function btc_debug(msg) { console.log('--> [BluetoothContext]: ' + msg); }; } var BluetoothContext = { /** * State of Bluetooth default adapter. * This is an enum of BluetoothAdapterState. * State: 'disabled', 'disabling', 'enabled', 'enabling' * * @readonly * @memberOf BluetoothContext * @type {String} */ state: 'disabled', /** * State of Bluetooth. * * Set the default state as undefined in bug 1191104 Since Bluetooth * adapter API need sometime to respond for true Bluetooth state * * @readonly * @access private * @memberOf BluetoothContext * @type {Boolean} */ enabled: undefined, /** * The address of the device's adapter on the bluetooth micro-network. * * @readonly * @memberOf BluetoothContext * @type {String} */ address: null, /** * The human readable name of the device's adapter. * * @readonly * @memberOf BluetoothContext * @type {String} */ name: '', /** * Indicates if the device is discoverable (true) or not (false) * by other bluetooth devices. * * @readonly * @memberOf BluetoothContext * @type {Boolean} */ discoverable: false, /** * Indicates if the device is in the process of discovering (true) or * not (false) surrounding bluetooth devices. * * @readonly * @memberOf BluetoothContext * @type {Boolean} */ discovering: false, /** * Number of Bluetooth paired devices. * * @readonly * @memberOf BluetoothContext * @type {Number} */ numberOfPairedDevices: 0, /** * Device name of Bluetooth paired devices in the first sorting. * * @readonly * @memberOf BluetoothContext * @type {String} */ firstPairedDeviceName: '', /** * Indicates if the paired device is in the paired devices list (true) or * not (false). * * @readonly * @memberOf BluetoothContext * @type {Boolean} */ hasPairedDevice: false, /** * Default adapter of Bluetooth. * * @access private * @memberOf BluetoothContext * @type {BluetoothAdapter} */ _defaultAdapter: null, /** * Init BluetoothContext module. * * @access private * @memberOf BluetoothContext */ _init: function btc__init() { // Observe 'defaultAdapter' property for reaching default adapter. AdapterManager.observe('defaultAdapter', this._onDefaultAdapterChanged.bind(this)); this._onDefaultAdapterChanged(AdapterManager.defaultAdapter); // Watch 'connecting' event for reaching connecting device. ConnectionManager.addEventListener('connecting', this._updateDeviceConnectionInfo.bind(this)); // Watch 'connected' event for reaching connected device. ConnectionManager.addEventListener('connected', this._updateDeviceConnectionInfo.bind(this)); // Watch 'disconnected' event for reaching disconnected device. ConnectionManager.addEventListener('disconnected', this._updateDeviceConnectionInfo.bind(this)); // Watch 'profileChange' event for reaching device connection profile. ConnectionManager.addEventListener('profileChanged', this._updateDeviceConnectionInfo.bind(this)); }, /** * Init properties from default adapter. * * @access private * @memberOf BluetoothContext * @param {BluetoothAdapter} adapter */ _initProperties: function btc__initProperties(adapter) { // init observable properties this._updateStatus(adapter.state); this.address = adapter.address; this.name = adapter.name; this.discoverable = adapter.discoverable; this.discovering = adapter.discovering; }, /** * Only reset properties since there is no available default adapter. * * @access private * @memberOf BluetoothContext */ _resetProperties: function btc__resetProperties() { this._updateStatus('disabled'); this.address = ''; this.name = ''; this.discoverable = false; this.discovering = false; }, /** * Watch 'attributechanged' event from default adapter for updating * enabled/disabled status immediately. * * Description of 'attributechanged' event: * A handler to trigger when one of the local bluetooth adapter's properties * has changed. Note access to the changed property in this event handler * would get the updated value. * * @access private * @memberOf BluetoothContext * @param {BluetoothAdapter} adapter */ _watchDefaultAdapterAttributechanged: function btc__watchDefaultAdapterAttributechanged(adapter) { adapter.addEventListener('attributechanged', this._onAdapterAttributeChanged.bind(this, adapter)); }, /** * Unwatch 'attributechanged' event from default adapter since adapter is * removed. * * @access private * @memberOf BluetoothContext * @param {BluetoothAdapter} adapter */ _unwatchDefaultAdapterAttributechanged: function btc__unwatchDefaultAdapterAttributechanged(adapter) { adapter.removeEventListener('attributechanged', this._onAdapterAttributeChanged); }, /** * Watch 'ondevicepaired' event from default adapter for updating paired * device immediately. * * Description of 'ondevicepaired' event: * A handler to trigger when a remote device gets paired with local * bluetooth adapter. * * @access private * @memberOf BluetoothContext * @param {BluetoothAdapter} adapter */ _watchDefaultAdapterOndevicepaired: function btc__watchDefaultAdapterOndevicepaired(adapter) { adapter.ondevicepaired = this._onAdapterDevicepaired.bind(this, adapter); }, /** * Unwatch 'ondevicepaired' event from default adapter since adapter is * removed. * * @access private * @memberOf BluetoothContext * @param {BluetoothAdapter} adapter */ _unwatchDefaultAdapterOndevicepaired: function btc__unwatchDefaultAdapterOndevicepaired(adapter) { adapter.ondevicepaired = null; }, /** * Watch 'ondeviceunpaired' event from default adapter for updating unpaired * device immediately. * * Description of 'ondeviceunpaired' event: * A handler to trigger when a remote device gets unpaired from local * bluetooth adapter. * * @access private * @memberOf BluetoothContext * @param {BluetoothAdapter} adapter */ _watchDefaultAdapterOndeviceunpaired: function btc__watchDefaultAdapterOndeviceunpaired(adapter) { adapter.ondeviceunpaired = this._onAdapterDeviceunpaired.bind(this, adapter); }, /** * Unwatch 'ondeviceunpaired' event from default adapter since adapter is * removed. * * @access private * @memberOf BluetoothContext * @param {BluetoothAdapter} adapter */ _unwatchDefaultAdapterOndeviceunpaired: function btc__unwatchDefaultAdapterOndeviceunpaired(adapter) { adapter.ondeviceunpaired = null; }, /** * 'attributechanged' event handler from default adapter for updating * latest BluetoothContext information. * * @access private * @memberOf BluetoothContext * @param {BluetoothAdapter} adapter * @param {event} evt */ _onAdapterAttributeChanged: function btc__onAdapterAttributeChanged(adapter, evt) { for (var i in evt.attrs) { debug('--> _onAdapterAttributeChanged(): ' + evt.attrs[i]); switch (evt.attrs[i]) { case 'state': this._updateStatus(adapter.state); if (adapter.state === 'enabled') { // Init paired device information while Bluetooth is enabled. this._refreshPairedDevicesInfo(adapter); // Manually start discovery while the adapter state // is already enabled. this.startDiscovery(); } break; case 'address': this.address = adapter.address; break; case 'name': this.name = adapter.name; break; case 'discoverable': this.discoverable = adapter.discoverable; break; case 'discovering': this.discovering = adapter.discovering; break; default: break; } } }, /** * 'ondevicepaired' event handler from default adapter for updating paired * device in remote/paired devices list. * * @access private * @memberOf BluetoothContext * @param {BluetoothAdapter} adapter * @param {event} evt */ _onAdapterDevicepaired: function btc__onAdapterDevicepaired(adapter, evt) { debug('_onAdapterDevicepaired evt = ' + evt); // have to get device object in this event handler // Ex. evt.device --> device // Remove the paired device from remote devices list. this._removeItemFromList(this._remoteDevices, evt.device.address); // Instead of adding the paired device in paired devices list, // get paired devices from adapter directly. this._refreshPairedDevicesInfo(adapter); }, /** * 'ondeviceunpaired' event handler from default adapter for updating * unpaired device in remote/paired devices list. * * @access private * @memberOf BluetoothContext * @param {BluetoothAdapter} adapter * @param {event} evt */ _onAdapterDeviceunpaired: function btc__onAdapterDeviceunpaired(adapter, evt) { debug('_onAdapterDeviceunpaired evt = ' + evt); // have to get the device address in this event handler Ex. evt -> address // Instead of removing the paired device from paired devices list, // get paired devices from adapter directly. this._refreshPairedDevicesInfo(adapter); }, /** * 'defaultAdapter' change event handler from adapter manager for * watch/unwatch default adapter relative event immediately. * * @access private * @memberOf BluetoothContext * @param {BluetoothAdapter} newAdapter * @param {BluetoothAdapter} oldAdapter */ _onDefaultAdapterChanged: function btc__onDefaultAdapterChanged(newAdapter, oldAdapter) { debug('_onDefaultAdapterChanged(): newAdapter = ' + newAdapter); debug('_onDefaultAdapterChanged(): oldAdapter = ' + oldAdapter); // save default adapter this._defaultAdapter = newAdapter; if (oldAdapter) { // unwatch event since the old adapter is no longer usefull this._unwatchDefaultAdapterAttributechanged(oldAdapter); this._unwatchDefaultAdapterOndeviceunpaired(oldAdapter); this._unwatchDefaultAdapterOndevicepaired(oldAdapter); } if (newAdapter) { // watch event since the new adapter is ready to access this._initProperties(newAdapter); this._watchDefaultAdapterAttributechanged(newAdapter); this._watchDefaultAdapterOndevicepaired(newAdapter); this._watchDefaultAdapterOndeviceunpaired(newAdapter); // init paired device information while Bluetooth is enabled if (newAdapter.state === 'enabled') { this._refreshPairedDevicesInfo(newAdapter); } } else { // reset properties only this._resetProperties(); } }, /** * Refresh paired devices information. * * @access private * @memberOf BluetoothContext * @param {BluetoothAdapter} adapter */ _refreshPairedDevicesInfo: function btc__refreshPairedDevicesInfo(adapter) { var pairedDevices = adapter.getPairedDevices(); debug('pairedDevices.length = ' + pairedDevices.length); // reset paired devices list this._pairedDevices.reset([]); // refresh properties about paired devices if (pairedDevices.length === 0) { // reset the name this.firstPairedDeviceName = ''; // update property 'hasPairedDevice' this.hasPairedDevice = false; } else { // sort paired devices pairedDevices.sort(function(a, b) { return a.name > b.name; }); // save paired devices in list for (var i in pairedDevices) { // create observable BtDevice var observableBtDevice = BtDevice(pairedDevices[i]); // push device in devices list with observable object this._pairedDevices.push(observableBtDevice); } // set the name this.firstPairedDeviceName = this._pairedDevices.get(0).name; // update property 'hasPairedDevice' this.hasPairedDevice = true; // Update connection status and profile for these paired devices. this._initConnectingDevices(); this._initConnectedDevices(); } this.numberOfPairedDevices = pairedDevices.length; }, /** * Since we have three properties which are relative with hardware status, * update them via this method here. * Update status, enabled, settings key 'bluetooth.enabled' * The input state would be {'disabled', 'disabling', 'enabled', 'enabling'} * * @access private * @memberOf BluetoothContext * @param {String} state */ _updateStatus: function btc__updateStatus(state) { // Wrapper state to enabled/disabled toggle state. var enabled; if (state === 'enabled' || state === 'disabling') { enabled = true; } else if (state === 'disabled' || state === 'enabling') { enabled = false; } // Update state this.state = state; debug('_updateStatus(): set state = ' + state); // Update enabled this.enabled = enabled; debug('_updateStatus(): set enabled = ' + enabled); // Sync with settings key this._syncWithSettingsKey(enabled); }, /** * The function provides to set booleans to update the 'bluetooth.enabled' * settings key if the value is not sync. * * @access private * @memberOf BluetoothContext * @param {Boolean} enabled */ _syncWithSettingsKey: function btc__syncWithSettingsKey(enabled) { SettingsCache.getSettings((results) => { var btEnabled = results['bluetooth.enabled']; if (btEnabled !== enabled) { settings.createLock().set({'bluetooth.enabled': enabled}); } }); }, /** * Set Bluetooth enable/disable. * * @access public * @memberOf BluetoothContext * @param {Boolean} enabled * @returns {Promise} */ setEnabled: function btc_setEnabled(enabled) { debug('setEnabled(): request set enabled = ' + enabled); if ((this.enabled === enabled) || (this.state === 'enabling') || (this.state === 'disabling')) { return Promise.reject('state transition!!'); } if (!this._defaultAdapter) { return Promise.reject('default adapter is not existed!!'); } if (enabled) { return this._defaultAdapter.enable().then(() => { debug('setEnabled(): set enable successfully :)'); }, (reason) => { debug('setEnabled(): set enable failed: reason = ' + reason); return Promise.reject(reason); }); } else { return this._defaultAdapter.disable().then(() => { debug('setEnabled(): set disable successfully :)'); }, (reason) => { debug('setEnabled(): set disable failed: reason = ' + reason); return Promise.reject(reason); }); } }, /** * Set Bluetooth discoverable. * * @access public * @memberOf BluetoothContext * @param {Boolean} enabled * @returns {Promise} */ setDiscoverable: function btc_setDiscoverable(enabled) { if ((this.discoverable === enabled) || (this.state !== 'enabled')) { return Promise.reject('same state or Bluetooth is disabled!!'); } if (!this._defaultAdapter) { return Promise.reject('default adapter is not existed!!'); } return this._defaultAdapter.setDiscoverable(enabled).then(() => { debug('setDiscoverable(): set discoverable ' + enabled + ' successfully :)'); }, (reason) => { debug('setDiscoverable(): set discoverable failed: ' + 'reason = ' + reason); return Promise.reject(reason); }); }, /** * Set adapter name. * * @access public * @memberOf BluetoothContext * @param {String} name * @returns {Promise} */ setName: function btc_setName(name) { if (name === this.name) { return Promise.reject('same name!!'); } if (!this._defaultAdapter) { return Promise.reject('default adapter is not existed!!'); } return this._defaultAdapter.setName(name).then(() => { debug('setName(): set name successfully :) name = ' + this._defaultAdapter.name); }, (reason) => { debug('setName(): set name failed: reason = ' + reason); return Promise.reject(reason); }); }, /** * Set adapter name by product model. * * @access public * @memberOf BluetoothContext */ setNameByProductModel: function btc_setNameByProductModel() { // Bug 847459: Default name of the bluetooth device is set by bluetoothd // to the value of the Android ro.product.model property upon first // start. In case the user gives an empty bluetooth device name, we want // to revert to the original ro.product.model. Gecko exposes it under // the deviceinfo.product_model setting. SettingsCache.getSettings((results) => { var productModel = results['deviceinfo.product_model']; debug('setNameByProductModel(): productModel = ' + productModel); this.setName(productModel); }); }, /** * An observable array to maintain paired devices which are just found out. * * @access private * @memberOf BluetoothContext * @type {ObservableArray} */ _pairedDevices: ObservableArray([]), /** * An observable array to maintain remote devices which are just found out. * * @access private * @memberOf BluetoothContext * @type {ObservableArray} */ _remoteDevices: ObservableArray([]), /** * An handler to handle 'ondevicefound' event. Then, we can save and update * found device in the remote devices array. * * @access private * @memberOf BluetoothContext * @type {Function} */ _discoveryHandler: null, /** * The method makes the device's adapter start seeking for remote devices. * The discovery process may be terminated after discovering a period of * time. If the startDiscovery operation succeeds, an onattributechanged * event would be triggered before the Promise is resolved to indicate * property discovering becomes true. * * @access public * @memberOf BluetoothContext * @type {Function} * @returns {Promise} */ startDiscovery: function btc_startDiscovery() { if ((this.discovering === true) || (this.state !== 'enabled')) { return Promise.reject('same state or Bluetooth is disabled!!'); } // clean up found devices list this._remoteDevices.reset([]); if (!this._defaultAdapter) { return Promise.reject('default adapter is not existed!!'); } return this._defaultAdapter.startDiscovery().then((handle) => { debug('startDiscovery(): startDiscovery successfully :)'); // Keep reference to handle in order to listen to // ondevicefound event handler this._setDiscoveryHandler(handle); }, (reason) => { debug('startDiscovery(): startDiscovery failed: ' + 'reason = ' + reason); return Promise.reject(reason); }); }, /** * The method makes the device's adapter stop seeking for remote devices. * This is an asynchronous method and its result is returned via a Promise. * If the stopDiscovery operation succeeds, an onattributechanged would be * triggered before the Promise is resolved to indicate property discovering * becomes false. Note adapter may still receive * BluetoothDiscoveryHandle.ondevicefound event until the Promise is * resolved. * * @access public * @memberOf BluetoothContext * @type {Function} * @returns {Promise} */ stopDiscovery: function btc_stopDiscovery() { if (this.discovering === false) { debug('stopDiscovery(): stopDiscovery successfully in same state :)'); return Promise.resolve('same state'); } if (this.state !== 'enabled') { return Promise.reject('Bluetooth is disabled!!'); } if (!this._defaultAdapter) { return Promise.reject('default adapter is not existed!!'); } return this._defaultAdapter.stopDiscovery().then(() => { debug('stopDiscovery(): stopDiscovery successfully :)'); }, (reason) => { debug('stopDiscovery(): stopDiscovery failed: reason = ' + reason); return Promise.reject(reason); }); }, /** * A function to receive BluetoothDiscoveryHandle. And set a function to * handle 'ondevicefound' event. * * @access private * @memberOf BluetoothContext * @param {BluetoothDiscoveryHandle} handle */ _setDiscoveryHandler: function btc__setDiscoveryHandler(handle) { debug('_setDiscoveryHandler(): handle = ' + handle); // make the code base easy to do unit test this._discoveryHandler = handle; this._discoveryHandler.ondevicefound = this._onDeviceFound.bind(this); }, /** * Handle 'ondevicefound' event to access remote device in list with * observable object. * * @access private * @memberOf BluetoothContext * @param {Object} evt */ _onDeviceFound: function btc__onDeviceFound(evt) { // save device this._saveDevice(evt.device); }, /** * To distinguish between paired and unpaired. * Then, save/update the device in list corresponding to the state of * property paired. * * @access private * @memberOf BluetoothContext * @param {Observable} device */ _saveDevice: function btc__saveDevice(device) { // Find the device is existed in devices list or not. var existedDevice = this._findDeviceByAddress({ paired: device.paired, address: device.address }); // If the device is not existed yet, create observable object // for saving this device. if (!existedDevice) { // create observable BtDevice var observableBtDevice = BtDevice(device); // push device in devices list with observable object var operatingDevices = (device.paired) ? this.getPairedDevices() : this.getRemoteDevices(); operatingDevices.push(observableBtDevice); } else { // The device is existed, no need to do any thing here. // set device in devices list // operatingDevices.set(index, device); } }, /** * Given an observable arrry and item address. The function will remove it, * if it's existed in the array. * * @access private * @memberOf BluetoothContext * @param {ObservableArray} list * @param {String} address */ _removeItemFromList: function btc__removeItemFromList(list, address) { // check the device is existed or not in remote/paired devices array var index = list.array.findIndex(this._matchDeviceByAddress.bind(this, address)); if (index > -1) { // The device is existed, remove it from observable list. list.splice(index, 1); debug('_removeItemFromList(): index = ' + index); } else { // The device is not existed, no need to do any thing here. } }, /** * Given paired, address properties to find out device element * from remote/paired devices list. * * @access private * @memberOf BluetoothContext * @param {Object} options * @param {String} options.paired - is paired or not * @param {String} options.address - the address of the device * @return {Object} device */ _findDeviceByAddress: function btc__findDeviceByAddress(options) { // Distinguish to find the specific device in remote/paired devices list. var operatingDevices = (options.paired) ? this.getPairedDevices() : this.getRemoteDevices(); // Check the device is existed or not in remote/paired devices array. var index = operatingDevices.array.findIndex( this._matchDeviceByAddress.bind(this, options.address)); if (index > -1) { return operatingDevices.get(index); } else { return null; } }, /** * Given address to find out device element from array. * * @access private * @memberOf BluetoothContext * @param {String} address * @param {BluetoothDevice} btDevice * @return {Boolean} */ _matchDeviceByAddress: function btc__matchDeviceByAddress(address, btDevice) { return btDevice.address && (btDevice.address === address); }, /** * Return paired devices list which is maintained in BluetoothContext. * * @access public * @memberOf BluetoothContext * @return {ObservableArray} */ getPairedDevices: function btc_getPairedDevices() { return this._pairedDevices; }, /** * Return remote devices list which is maintained in BluetoothContext. * * @access public * @memberOf BluetoothContext * @return {ObservableArray} */ getRemoteDevices: function btc_getRemoteDevices() { return this._remoteDevices; }, /** * The method starts pairing a remote device with the device's adapter. * * @access public * @memberOf BluetoothContext * @param {String} address * @returns {Promise} */ pair: function btc_pair(address) { if (!this._defaultAdapter) { return Promise.reject('default adapter is not existed!!'); } // Note on Bluedroid stack, discovery has to be stopped before pairing // (i.e., call stopDiscovery() before pair()) otherwise stack callbacks // with pairing failure. return this.stopDiscovery().then(() => { return this._defaultAdapter.pair(address).then(() => { debug('pair(): Resolved with void value'); }, (reason) => { debug('pair(): Reject with this reason: ' + reason); return Promise.reject(reason); }); }, (reason) => { return Promise.reject(reason); }); }, /** * The method starts unpairs a remote device with the device's adapter. * * @access public * @memberOf BluetoothContext * @param {String} address * @returns {Promise} */ unpair: function btc_unpair(address) { if (!this._defaultAdapter) { return Promise.reject('default adapter is not existed!!'); } return this._defaultAdapter.unpair(address).then(() => { debug('unpair(): Resolved with void value'); }, (reason) => { debug('unpair(): Reject with this reason: ' + reason); return Promise.reject(reason); }); }, /** * The method starts sending file to a remote device with the device's * adapter. * * @access public * @memberOf BluetoothContext * @param {String} address - address of target device * @param {Object} blob - blob(file) to send * @returns {Promise} */ sendFile: function btc_sendFile(address, blob) { if (!this._defaultAdapter) { return Promise.reject('default adapter is not existed!!'); } return this._defaultAdapter.sendFile(address, blob).then(() => { debug('sendFile(): Resolved with void value'); }, (reason) => { debug('sendFile(): Reject with this reason: ' + reason); return Promise.reject(reason); }); }, /** * Init the connecting device which is browsed in paired devices list. * Get connection info from ConnectionManager. * * @access private * @memberOf BluetoothContext */ _initConnectingDevices: function btc__initConnectingDevices() { // Init the paired device connection status for connecting device. if (!ConnectionManager.connectingAddress) { return; } var existedDevice = this._findDeviceByAddress({ paired: true, address: ConnectionManager.connectingAddress }); if (existedDevice) { // The connecting device is existed. Init connection status for it. var options = { connectionStatus: 'connecting' }; debug('_initConnectingDevices(): options = ' + JSON.stringify(options)); existedDevice.updateConnectionInfo(options); } }, /** * Init the connected device which is browsed in paired devices list. * Get connection info from ConnectionManager. * * @access private * @memberOf BluetoothContext */ _initConnectedDevices: function btc__initConnectedDevices() { // Init the connection status of paired device for connected device. ConnectionManager.getConnectedDevices().then((connectedDevices) => { for (var address in connectedDevices) { var existedDevice = this._findDeviceByAddress({paired: true, address: address}); if (existedDevice) { // The connected device is existed. // Init connection status/profiles for it. var options = { connectionStatus: 'connected', profiles: connectedDevices[address].connectedProfiles }; debug('_initConnectedDevices(): address = ' + address + ', options = ' + JSON.stringify(options)); existedDevice.updateConnectionInfo(options); } } }, (reason) => { debug('_initConnectedDevices(): getConnectedDevices(): failed, ' + 'reason = ' + reason); }); }, /** * Device 'connecting', 'connected', 'disconnected', and 'profiles' * properties are changed from ConnectionManager operation. * Update device properties of connection info via event 'type', 'detail'. * * @access private * @memberOf BluetoothContext * @param {Object} event * @param {String} event.type - type of event name * @param {Object} event.detail - device info in this object * @param {Object} event.detail.address - address of device * @param {Object} event.detail.profiles - connection profiles of device */ _updateDeviceConnectionInfo: function btc__updateDeviceConnectionInfo(event) { debug('_updateDeviceConnectionInfo(): event = ' + JSON.stringify(event)); var existedDevice = this._findDeviceByAddress( {paired: true, address: event.detail.address}); if (existedDevice) { // The device is existed, update device info by event type. var options; switch (event.type) { case 'connecting': case 'connected': case 'disconnected': options = { connectionStatus: event.type }; break; case 'profileChanged': options = { profiles: event.detail.profiles }; break; default: break; } debug('_updateDeviceConnectionInfo(): options = ' + JSON.stringify(options)); existedDevice.updateConnectionInfo(options); } else { // If the device is not existed yet, do nothing here. } } }; // Create the observable object using the prototype. var bluetoothContext = Observable(BluetoothContext); bluetoothContext._init(); return bluetoothContext; });