VulpesOS/assets/webapps/uitest.gaiamobile.org/shared/js/bluetooth_helper.js
OverSu b38dea0597 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.
2026-09-30 23:13:03 +02:00

322 lines
7.4 KiB
JavaScript

/* exported BluetoothHelper */
'use strict';
var BluetoothHelper = function() {
var profiles = {
'HFP': 0x111E,
'A2DP': 0x110D
};
var _bluetooth = window.navigator.mozBluetooth;
var _isReady = false;
var _callbacks = [];
var _adapter = null;
var _oldAdapter = null; // The varaible is accessed for v1 only.
var _v2 = true;
var _ready = function(callback) {
if (!callback || !_bluetooth) {
return;
}
if (_isReady) {
callback();
} else {
_callbacks.push(callback);
}
};
var _handleRequest = function(request, callback, errorcb) {
request.onsuccess = function() {
if (callback) {
callback(request.result);
}
};
request.onerror = function() {
console.log('Error handling bluetooth request');
if (errorcb) {
errorcb();
}
};
};
// run callbacks when adapter is ready
var _processCallbacks = function() {
if (_adapter) {
_isReady = true;
_callbacks.forEach(function(callback) {
callback();
});
// clean up the _callback queue
_callbacks = [];
} else {
// We can do nothing without default adapter.
console.log('BluetoothHelper(): connot get default adapter yet');
}
};
// API v2 get adapter via bluetooth
var _fetchAdapterV2 = function() {
// need time to get bluetooth adapter at first run
_bluetooth.onattributechanged = function onManagerAttributeChanged(evt) {
for (var i in evt.attrs) {
switch (evt.attrs[i]) {
case 'defaultAdapter':
console.log('defaultAdapter changed. address:',
_bluetooth.defaultAdapter.address);
_adapter = _bluetooth.defaultAdapter;
_processCallbacks();
break;
default:
break;
}
}
};
_adapter = _bluetooth.defaultAdapter;
if (_adapter) {
_processCallbacks();
}
};
// API v1 get adapter via bluetooth
var _fetchAdapter = function() {
var req = _bluetooth.getDefaultAdapter();
if (req) {
req.onsuccess = function() {
if (_adapter) {
_oldAdapter = _adapter;
}
_isReady = true;
_adapter = req.result;
// Put the callback function of onpairedstatuschanged to the new adapter
// because the new adapter won't remember those callback function which
// is registered before. In other word, we get a new adpater after
// turned on/off Bluetooth. The new adapter have no registered callback.
if (_oldAdapter && _oldAdapter.onpairedstatuschanged) {
_adapter.onpairedstatuschanged = _oldAdapter.onpairedstatuschanged;
}
_callbacks.forEach(function(callback) {
callback();
});
// clean up the _callback queue
_callbacks = [];
};
req.onerror = function() {
// We can do nothing without default adapter.
console.log('BluetoothHelper(): connot get default adapter!!!');
};
}
};
var _getAdapter = function() {
if (_v2) {
_fetchAdapterV2();
} else {
_fetchAdapter();
}
};
var _resetAdapter = function() {
if (_adapter) {
_oldAdapter = _adapter;
}
// clean up state and adapter
_isReady = false;
_adapter = null;
};
// init
if (_bluetooth) {
// detect API version
if (typeof(_bluetooth.onattributechanged) === 'undefined') {
_v2 = false;
}
if (_v2) {
_bluetooth.onadapteradded = function onAdapterAdded(evt) {
_getAdapter();
};
} else {
_bluetooth.addEventListener('enabled', _getAdapter);
_bluetooth.addEventListener('adapteradded', _getAdapter);
_bluetooth.addEventListener('disabled', _resetAdapter);
}
_getAdapter();
}
return {
profiles: profiles,
answerWaitingCall: function() {
_ready(function() {
_adapter.answerWaitingCall();
});
},
ignoreWaitingCall: function() {
_ready(function() {
_adapter.ignoreWaitingCall();
});
},
toggleCalls: function() {
_ready(function() {
_adapter.toggleCalls();
});
},
getConnectedDevicesByProfile: function(profileID, cb) {
_ready(function() {
_handleRequest(_adapter.getConnectedDevices(profileID), cb);
});
},
connectSco: function(cb) {
_ready(function() {
_handleRequest(_adapter.connectSco(), cb);
});
},
disconnectSco: function(cb) {
_ready(function() {
_handleRequest(_adapter.disconnectSco(), cb);
});
},
getPairedDevices: function(cb) {
_ready(function() {
_handleRequest(_adapter.getPairedDevices(), cb);
});
},
getAddress: function(cb) {
if (_v2) {
console.log('getAddress function is deprecated');
return;
}
_ready(function() {
var address = _adapter.address;
cb(address);
});
},
setPairingConfirmation: function(address, confirmed) {
if (_v2) {
console.log('setPairingConfirmation API is deprecated');
return;
}
_ready(function() {
_adapter.setPairingConfirmation(address, confirmed);
});
},
setPinCode: function(address, pincode) {
if (_v2) {
console.log('setPairingConfirmation API is deprecated');
return;
}
_ready(function() {
_adapter.setPinCode(address, pincode);
});
},
setPasskey: function(address, key) {
if (_v2) {
console.log('setPairingConfirmation API is deprecated');
return;
}
_ready(function() {
_adapter.setPasskey(address, key);
});
},
isScoConnected: function(cb, errorcb) {
_ready(function() {
_handleRequest(_adapter.isScoConnected(), cb, errorcb);
});
},
sendMediaMetaData: function(metadata, cb, errorcb) {
_ready(function() {
_handleRequest(_adapter.sendMediaMetaData(metadata), cb, errorcb);
});
},
sendMediaPlayStatus: function(metadata, cb, errorcb) {
_ready(function() {
_handleRequest(_adapter.sendMediaPlayStatus(metadata), cb, errorcb);
});
},
set onhfpstatuschanged(callback) {
_ready(function() {
_adapter.onhfpstatuschanged = callback;
});
},
set onscostatuschanged(callback) {
_ready(function() {
_adapter.onscostatuschanged = callback;
});
},
set ona2dpstatuschanged(callback) {
_ready(function() {
_adapter.ona2dpstatuschanged = callback;
});
},
set onrequestmediaplaystatus(callback) {
_ready(function() {
_adapter.onrequestmediaplaystatus = callback;
});
},
set onpairedstatuschanged(callback) {
if (_v2) {
console.log('onpairedstatuschanged API is deprecated');
return;
}
_ready(function() {
_adapter.onpairedstatuschanged = callback;
});
},
v2: _v2, // expose API version for app reference
// bypass the enable/disable state if works in APIv1
enable: function() {
if (_v2) {
_ready(function() {
_adapter.enable();
});
} else {
console.log('enable is not support in v1 API!');
}
},
disable: function() {
if (_v2) {
_ready(function() {
_adapter.disable();
});
} else {
console.log('disable is not support in v1 API!');
}
}
};
};