Publish Vulpes Preview 15 sources for desktop, Android and Tundra
Share Gaia assets and adapters, keep private profiles and development documents local, and update both public READMEs.
This commit is contained in:
parent
93e3a48004
commit
b38dea0597
25901 changed files with 9982925 additions and 369 deletions
575
assets/webapps/system.gaiamobile.org/js/bluetooth_v2.js
Normal file
575
assets/webapps/system.gaiamobile.org/js/bluetooth_v2.js
Normal file
|
|
@ -0,0 +1,575 @@
|
|||
'use strict';
|
||||
/**
|
||||
* Bluetooth2 is compatible with Bluetooth APIv2 and used to enable/
|
||||
* disable bluetooth hardware, get bluetooth adapter, and check target
|
||||
* bluetooth profile is connected.
|
||||
*
|
||||
* Bluetooth api v2 is the two level structure.
|
||||
* We use _btManagerHandler to handle BluetoothManager defaultAdapter
|
||||
* change event and _btAdapterHandler to handle status change event.
|
||||
*
|
||||
* Current supported Bluetooth profiles are:
|
||||
* - hfp: Hands-Free Profile
|
||||
* - opp: Object Push Profile
|
||||
* - a2dp: Advenced Audio Distribution Profile
|
||||
* - sco: Synchronous Connection-Oriented Profile
|
||||
*/
|
||||
/* global Service, LazyLoader, BluetoothIcon, BluetoothTransferIcon,
|
||||
BluetoothHeadphoneIcon, BluetoothTransfer */
|
||||
/* exported Bluetooth2 */
|
||||
(function(exports) {
|
||||
var Bluetooth = function() {};
|
||||
|
||||
Bluetooth.prototype = {
|
||||
name: 'Bluetooth',
|
||||
|
||||
/**
|
||||
* Debug message.
|
||||
*
|
||||
* @public
|
||||
* @type {Boolean} turn on/off the console log
|
||||
*/
|
||||
onDebug: false,
|
||||
|
||||
/**
|
||||
* Store a reference of the default adapter.
|
||||
* If the adapter is not availble, no bluetooth operation could be
|
||||
* executed.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
_adapter: null,
|
||||
|
||||
/**
|
||||
* Hold instance of bluetooth adapter state change handler.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
_bindBtAdapterHandler: null,
|
||||
|
||||
/**
|
||||
* Hold instance of HFP status changed handler.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
_bindHfpStatusChangedHandler: null,
|
||||
|
||||
/**
|
||||
* Hold instance of A2DP status changed handler.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
_bindA2dpStatusChangedHandler: null,
|
||||
|
||||
/**
|
||||
* Hold instance of SCO status changed handler.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
_bindScoStatusChangedHandler: null,
|
||||
|
||||
/**
|
||||
* Store a reference for mozBluetooth.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
_bluetooth: null,
|
||||
|
||||
/**
|
||||
* State of Bluetooth default adapter.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
_isEnabled: false,
|
||||
|
||||
/**
|
||||
* Set profile connect state.
|
||||
*
|
||||
* @private
|
||||
* @param {String} profile profile id
|
||||
* @param {Boolean} connected connect status
|
||||
*/
|
||||
_setProfileConnected: function bt_setProfileConnected(profile, connected) {
|
||||
var value = this['_' + profile + 'Connected'];
|
||||
if (value !== connected) {
|
||||
this['_' + profile + 'Connected'] = connected;
|
||||
|
||||
// Raise an event for the profile connection changes.
|
||||
window.dispatchEvent(new CustomEvent('bluetoothprofileconnectionchange',
|
||||
{
|
||||
detail: {
|
||||
name: profile,
|
||||
connected: connected
|
||||
}
|
||||
}
|
||||
));
|
||||
// Update Bluetooth and profile icons
|
||||
this.icon && this.icon.update();
|
||||
if (profile === 'opp' && this.transferIcon) {
|
||||
this.transferIcon.update();
|
||||
}
|
||||
if (profile === 'a2dp' && this.headphoneIcon) {
|
||||
this.headphoneIcon.update();
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Check if bluetooth profile is connected.
|
||||
*
|
||||
* @private
|
||||
* @param {String} profile profile name
|
||||
* @return {Boolean} connected state
|
||||
*/
|
||||
_isProfileConnected: function bt__isProfileConnected(profile) {
|
||||
var isConnected = this['_' + profile + 'Connected'];
|
||||
if (isConnected === undefined) {
|
||||
return false;
|
||||
} else {
|
||||
return isConnected;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Initialize bluetooth module.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
start: function bt_start() {
|
||||
if (!window.navigator.mozSettings || !window.navigator.mozBluetooth) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._bluetooth = window.navigator.mozBluetooth;
|
||||
|
||||
// hold the instances so we can remove it when needed
|
||||
this._bindBtAdapterHandler =
|
||||
this._btAdapterHandler.bind(this);
|
||||
|
||||
this._bindHfpStatusChangedHandler = function(evt) {
|
||||
this._setProfileConnected('hfp', evt.status);
|
||||
}.bind(this);
|
||||
this._bindA2dpStatusChangedHandler = function(evt) {
|
||||
this._setProfileConnected('a2dp', evt.status);
|
||||
}.bind(this);
|
||||
this._bindScoStatusChangedHandler = function(evt) {
|
||||
this._setProfileConnected('sco', evt.status);
|
||||
}.bind(this);
|
||||
|
||||
this._initDefaultAdapter();
|
||||
|
||||
this._bluetooth.addEventListener('attributechanged',
|
||||
this._btManagerHandler.bind(this));
|
||||
|
||||
// decouple enable/disable bluetooth function from other system part
|
||||
window.addEventListener('request-enable-bluetooth',
|
||||
this._requestEnableHandler.bind(this));
|
||||
window.addEventListener('request-disable-bluetooth',
|
||||
this._requestDisableHandler.bind(this));
|
||||
|
||||
// relay bluetooth transfer system messages
|
||||
navigator.mozSetMessageHandler('bluetooth-opp-transfer-start',
|
||||
this._oppTransferStartHandler.bind(this));
|
||||
navigator.mozSetMessageHandler('bluetooth-opp-transfer-complete',
|
||||
this._oppTransferCompleteHandler.bind(this));
|
||||
|
||||
// expose functions to Service.request
|
||||
Service.register('adapter', this);
|
||||
Service.register('pair', this);
|
||||
Service.register('getPairedDevices', this);
|
||||
// expose functions to Service.query
|
||||
Service.registerState('isEnabled', this);
|
||||
Service.registerState('getAdapter', this);
|
||||
Service.registerState('isOPPProfileConnected', this);
|
||||
Service.registerState('isA2DPProfileConnected', this);
|
||||
Service.registerState('isSCOProfileConnected', this);
|
||||
|
||||
// handle statusbar icons
|
||||
LazyLoader.load(['js/bluetooth_transfer.js',
|
||||
'js/bluetooth_icon.js',
|
||||
'js/bluetooth_transfer_icon.js',
|
||||
'js/bluetooth_headphone_icon.js']).then(() => {
|
||||
BluetoothTransfer.start();
|
||||
this.icon = new BluetoothIcon(this);
|
||||
this.icon.start();
|
||||
this.transferIcon = new BluetoothTransferIcon(this);
|
||||
this.transferIcon.start();
|
||||
this.headphoneIcon = new BluetoothHeadphoneIcon(this);
|
||||
this.headphoneIcon.start();
|
||||
}).catch(function(err) {
|
||||
console.error(err);
|
||||
});
|
||||
},
|
||||
|
||||
stop: function() {
|
||||
Service.unregister('adapter', this);
|
||||
Service.unregister('pair', this);
|
||||
Service.unregister('getPairedDevices', this);
|
||||
Service.unregisterState('isEnabled', this);
|
||||
Service.unregisterState('getAdapter', this);
|
||||
Service.unregisterState('isOPPProfileConnected', this);
|
||||
Service.unregisterState('isA2DPProfileConnected', this);
|
||||
Service.unregisterState('isSCOProfileConnected', this);
|
||||
},
|
||||
|
||||
/**
|
||||
* Generally bluetooth adapter is already available when start
|
||||
* this module and no related event will be received.
|
||||
* so we try to get the adapter then listen to mozBluetooth change
|
||||
* to prevent race condition
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
_initDefaultAdapter: function() {
|
||||
this.debug('init bluetooth adapter');
|
||||
this._adapter = this._bluetooth.defaultAdapter;
|
||||
if (this._adapter) {
|
||||
this.debug('adapter is available');
|
||||
// listen states when the adapter is available
|
||||
this._adapterAvailableHandler();
|
||||
|
||||
// dispatch default bluetooth enable state
|
||||
this._isEnabled = (this._adapter.state === 'enabled');
|
||||
this._dispatchEnableState();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Once adapter is available, listen to bluetooth state and
|
||||
* the connect stat of supported profiles.
|
||||
*
|
||||
* we only support two use cases for bluetooth connection:
|
||||
* 1. connecting with a headset
|
||||
* 2. transfering a file to/from another device
|
||||
* So we need to listen to corresponding events to know we are (aren't)
|
||||
* connected, then summarize to an event and dispatch to Statusbar
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
_adapterAvailableHandler: function bt__adapterAvailableHandler() {
|
||||
// listen to adapter state
|
||||
this._adapter.addEventListener('attributechanged',
|
||||
this._bindBtAdapterHandler);
|
||||
|
||||
// headset connected cases
|
||||
this._adapter.addEventListener('hfpstatuschanged',
|
||||
this._bindHfpStatusChangedHandler);
|
||||
this._adapter.addEventListener('a2dpstatuschanged',
|
||||
this._bindA2dpStatusChangedHandler);
|
||||
this._adapter.addEventListener('scostatuschanged',
|
||||
this._bindScoStatusChangedHandler);
|
||||
},
|
||||
|
||||
/**
|
||||
* Remove all EventListeners when default adapter is changed.
|
||||
*/
|
||||
_adapterUnavailableHandler: function bt__adapterUnavailableHandler() {
|
||||
this.debug('default adapter is removed');
|
||||
// unbind headset connected cases
|
||||
this._adapter.removeEventListener('hfpstatuschanged',
|
||||
this._bindHfpStatusChangedHandler);
|
||||
this._adapter.removeEventListener('a2dpstatuschanged',
|
||||
this._bindA2dpStatusChangedHandler);
|
||||
this._adapter.removeEventListener('scostatuschanged',
|
||||
this._bindScoStatusChangedHandler);
|
||||
|
||||
// unbind adapter
|
||||
this._adapter.removeEventListener('attributechanged',
|
||||
this._bindBtAdapterHandler);
|
||||
},
|
||||
|
||||
/**
|
||||
* Update settings value and enable bluetooth hardware.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
_requestEnableHandler: function bt__requestEnableHandler() {
|
||||
this.debug('enabling bluetooth');
|
||||
if (this._adapter) {
|
||||
// the state will be dispatched in _btAdapterHandler
|
||||
this._adapter.enable().then(() => { //resolve
|
||||
this.debug('bluetooth enabled');
|
||||
}, () => { //reject
|
||||
this.debug('can not get bluetooth adapter');
|
||||
});
|
||||
} else { // return current state since we can't process the request
|
||||
this.debug('adapter is not available');
|
||||
this._dispatchEnableState();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Update settings value and disable bluetooth hardware.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
_requestDisableHandler: function bt__requestDisableHandler() {
|
||||
this.debug('disabling bluetooth');
|
||||
if (this._adapter) {
|
||||
// the state will be dispatched in _btAdapterHandler
|
||||
this._adapter.disable().then(() => { //resolve
|
||||
this.debug('bluetooth disabled');
|
||||
}, () => { //reject
|
||||
this.debug('can not get bluetooth adapter');
|
||||
});
|
||||
} else { // return current state since we can't process the request
|
||||
this.debug('adapter is not available');
|
||||
this._dispatchEnableState();
|
||||
}
|
||||
},
|
||||
|
||||
/*
|
||||
* In file transfering case:
|
||||
* since System Message can't be listened in two js files within a app,
|
||||
* so we listen here but dispatch events to bluetooth_transfer.js
|
||||
* while getting bluetooth file transfer start system messages
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
_oppTransferStartHandler: function(transferInfo) {
|
||||
this._setProfileConnected('opp', true);
|
||||
window.dispatchEvent(new CustomEvent('bluetooth-opp-transfer-start',
|
||||
{
|
||||
detail: { transferInfo: transferInfo }
|
||||
}
|
||||
));
|
||||
},
|
||||
|
||||
/*
|
||||
* In file transfering case:
|
||||
* since System Message can't be listened in two js files within a app,
|
||||
* so we listen here but dispatch events to bluetooth_transfer.js
|
||||
* while getting bluetooth file transfer complete system messages
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
_oppTransferCompleteHandler: function(transferInfo) {
|
||||
this._setProfileConnected('opp', false);
|
||||
window.dispatchEvent(new CustomEvent('bluetooth-opp-transfer-complete',
|
||||
{
|
||||
detail: { transferInfo: transferInfo }
|
||||
}
|
||||
));
|
||||
},
|
||||
|
||||
/**
|
||||
* BT APIv2: Watch 'onattributechanged' event from
|
||||
* mozBluetooth.defaultAdapter for updating state information.
|
||||
*
|
||||
* @private
|
||||
* @param {Object} evt event object
|
||||
*/
|
||||
_btAdapterHandler:
|
||||
function bt__btAdapterHandler(evt) {
|
||||
for (var i in evt.attrs) {
|
||||
switch (evt.attrs[i]) {
|
||||
case 'state':
|
||||
if (this._adapter.state === 'enabled') {
|
||||
this.debug('state true');
|
||||
this._isEnabled = true;
|
||||
navigator.mozSettings.createLock()
|
||||
.set({'bluetooth.enabled': true});
|
||||
window.dispatchEvent(new CustomEvent('bluetooth-enabled'));
|
||||
this.icon && this.icon.update();
|
||||
} else if (this._adapter.state === 'disabled') {
|
||||
this.debug('state false');
|
||||
this._isEnabled = false;
|
||||
navigator.mozSettings.createLock()
|
||||
.set({'bluetooth.enabled': false});
|
||||
window.dispatchEvent(new CustomEvent('bluetooth-disabled'));
|
||||
this.icon && this.icon.update();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Watch 'onattributechanged' event from mozBluetooth for updating default
|
||||
* adapter information.
|
||||
*
|
||||
* 'onattributechanged' event description:
|
||||
* A handler to trigger when bluetooth manager's only property
|
||||
* defaultAdapter has changed.
|
||||
*
|
||||
* Here are three adapter change cases:
|
||||
*
|
||||
* null -> adapter: set new adapter and dispatch adapter state.
|
||||
* adapter -> null: clear defaultAdapter and listener.
|
||||
* adapterA -> adapterB: clean defaultAdapter and listener,
|
||||
* then set new adapter and dispatch adapter state.
|
||||
*
|
||||
* @private
|
||||
* @param {Object} evt event object
|
||||
*/
|
||||
_btManagerHandler:
|
||||
function bt__btManagerHandler(evt) {
|
||||
for (var i in evt.attrs) {
|
||||
switch (evt.attrs[i]) {
|
||||
// Default adapter attribute change.
|
||||
// Usually, it means that we reach new default adapter.
|
||||
case 'defaultAdapter':
|
||||
this.debug('defaultAdapter changed.');
|
||||
if (this._bluetooth.defaultAdapter) {
|
||||
if (this._adapter !== this._bluetooth.defaultAdapter) {
|
||||
if (this._adapter !== null) { // adapter A -> adapter B
|
||||
this.debug('origin adapter is removed');
|
||||
this._adapterUnavailableHandler();
|
||||
this._adapter = null;
|
||||
}
|
||||
// set new adapter and dispatch adapter state
|
||||
this.debug('new adapter is added');
|
||||
this._adapter = this._bluetooth.defaultAdapter;
|
||||
this._isEnabled = (this._adapter.state === 'enabled');
|
||||
// listen states when the adapter is available
|
||||
this._adapterAvailableHandler();
|
||||
}
|
||||
} else { // adapter -> null
|
||||
this.debug('default adapter is removed');
|
||||
this._adapterUnavailableHandler();
|
||||
this._adapter = null;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Dispatch bluetooth enable/disable state to system.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
_dispatchEnableState: function bt__dispatchEnableState() {
|
||||
if (this._isEnabled) {
|
||||
window.dispatchEvent(new CustomEvent('bluetooth-enabled'));
|
||||
} else {
|
||||
window.dispatchEvent(new CustomEvent('bluetooth-disabled'));
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Get adapter from bluetooth through promise interface.
|
||||
* XXX: the function abstract the Bluetooth API difference.
|
||||
* We can remove it and use service query once BTv1 is deprecated.
|
||||
*
|
||||
* @public
|
||||
* @return {Promise} A promise that resolve the Bluetooth Adapter
|
||||
*/
|
||||
adapter: function bt__adapter() {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (this._adapter !== null) {
|
||||
resolve(this._adapter);
|
||||
} else {
|
||||
this.debug('No BT adapter retrieved');
|
||||
reject();
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Return device pairing result.
|
||||
* XXX: the function abstract the Bluetooth API difference.
|
||||
*
|
||||
* @public
|
||||
* @param {string} mac target device address
|
||||
* @return {Promise} A promise that resolve when pair successfully,
|
||||
* reject when pair failed
|
||||
*/
|
||||
pair: function bt__pair(mac) {
|
||||
return this._adapter.pair(mac);
|
||||
},
|
||||
|
||||
/**
|
||||
* Return paired devices list.
|
||||
* XXX: the function abstract the Bluetooth API difference.
|
||||
* We can use service query to return list once BTv1 is deprecated.
|
||||
*
|
||||
* @public
|
||||
* @returns {Object[]} sequence of BluetoothDevice
|
||||
*/
|
||||
getPairedDevices: function bt__getPairedDevices() {
|
||||
return this._adapter.getPairedDevices();
|
||||
},
|
||||
|
||||
/**
|
||||
* Return bluetooth adapter.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
get getAdapter() {
|
||||
return this._adapter;
|
||||
},
|
||||
|
||||
/**
|
||||
* Maintain bluetooth enable/disable state.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
get isEnabled() {
|
||||
return this._isEnabled;
|
||||
},
|
||||
|
||||
/**
|
||||
* Check if bluetooth OPP profile is connected.
|
||||
*
|
||||
* @public
|
||||
* @return {Boolean} connected state
|
||||
*/
|
||||
get isOPPProfileConnected() {
|
||||
return this._isProfileConnected('opp');
|
||||
},
|
||||
|
||||
/**
|
||||
* Check if bluetooth A2DP profile is connected.
|
||||
*
|
||||
* @public
|
||||
* @return {Boolean} connected state
|
||||
*/
|
||||
get isA2DPProfileConnected() {
|
||||
return this._isProfileConnected('a2dp');
|
||||
},
|
||||
|
||||
/**
|
||||
* Check if bluetooth SCO profile is connected.
|
||||
*
|
||||
* @public
|
||||
* @return {Boolean} connected state
|
||||
*/
|
||||
get isSCOProfileConnected() {
|
||||
return this._isProfileConnected('sco');
|
||||
},
|
||||
|
||||
/**
|
||||
* Check if any of bluetooth profiles is connected.
|
||||
* Referenced by Bluetooth icon update
|
||||
*
|
||||
* @public
|
||||
* @return {Boolean} connected state
|
||||
*/
|
||||
get connected() {
|
||||
return this._isProfileConnected('hfp') ||
|
||||
this._isProfileConnected('a2dp') ||
|
||||
this._isProfileConnected('opp');
|
||||
},
|
||||
|
||||
/**
|
||||
* Console log.
|
||||
*
|
||||
* @private
|
||||
* @param {Object} msg debug message
|
||||
*/
|
||||
debug: function bt_debug(msg) {
|
||||
if (!this.onDebug) {
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('[System Bluetooth]: ' + msg);
|
||||
}
|
||||
};
|
||||
|
||||
exports.Bluetooth2 = Bluetooth;
|
||||
})(window);
|
||||
Loading…
Reference in a new issue