fix: allow cancelling of bluetooth requests (#37601)

* fix: allow cancelling of bluetooth requests

allows cancelling of bluetooth requests when no devices present

* docs: update docs to reflect how bluetooth works.
This commit is contained in:
John Kleinschmidt 2023-03-27 09:31:15 -04:00 коммит произвёл GitHub
Родитель 42e7cd9b3f
Коммит 6a6908c4c8
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
7 изменённых файлов: 56 добавлений и 31 удалений

Просмотреть файл

@ -777,20 +777,24 @@ Returns:
* `callback` Function
* `deviceId` string
Emitted when bluetooth device needs to be selected on call to
`navigator.bluetooth.requestDevice`. To use `navigator.bluetooth` api
`webBluetooth` should be enabled. If `event.preventDefault` is not called,
first available device will be selected. `callback` should be called with
`deviceId` to be selected, passing empty string to `callback` will
cancel the request.
Emitted when a bluetooth device needs to be selected when a call to
`navigator.bluetooth.requestDevice` is made. `callback` should be called with
the `deviceId` of the device to be selected. Passing an empty string to
`callback` will cancel the request.
If no event listener is added for this event, all bluetooth requests will be cancelled.
If an event listener is not added for this event, or if `event.preventDefault`
is not called when handling this event, the first available device will be
automatically selected.
Due to the nature of bluetooth, scanning for devices when
`navigator.bluetooth.requestDevice` is called may take time and will cause
`select-bluetooth-device` to fire multiple times until `callback` is called
with either a device id or an empty string to cancel the request.
```javascript title='main.js'
const { app, BrowserWindow } = require('electron')
let win = null
app.commandLine.appendSwitch('enable-experimental-web-platform-features')
app.whenReady().then(() => {
win = new BrowserWindow({ width: 800, height: 600 })
@ -800,6 +804,9 @@ app.whenReady().then(() => {
return device.deviceName === 'test'
})
if (!result) {
// The device wasn't found so we need to either wait longer (eg until the
// device is turned on) or cancel the request by calling the callback
// with an empty string.
callback('')
} else {
callback(result.deviceId)

Просмотреть файл

@ -9,6 +9,7 @@
<h1>Web Bluetooth API</h1>
<button id="clickme">Test Bluetooth</button>
<button id="cancel">Cancel Bluetooth Request</button>
<p>Currently selected bluetooth device: <strong id="device-name""></strong></p>

Просмотреть файл

@ -1,6 +1,9 @@
const {app, BrowserWindow, ipcMain} = require('electron')
const path = require('path')
let bluetoothPinCallback
let selectBluetoothCallback
function createWindow () {
const mainWindow = new BrowserWindow({
width: 800,
@ -12,11 +15,23 @@ function createWindow () {
mainWindow.webContents.on('select-bluetooth-device', (event, deviceList, callback) => {
event.preventDefault()
if (deviceList && deviceList.length > 0) {
callback(deviceList[0].deviceId)
}
selectBluetoothCallback = callback
const result = deviceList.find((device) => {
return device.deviceName === 'test'
})
if (result) {
callback(result.deviceId)
} else {
// The device wasn't found so we need to either wait longer (eg until the
// device is turned on) or until the user cancels the request
}
})
ipcMain.on('cancel-bluetooth-request', (event) => {
selectBluetoothCallback('')
})
// Listen for a message from the renderer to get the response for the Bluetooth pairing.
ipcMain.on('bluetooth-pairing-response', (event, response) => {
bluetoothPinCallback(response)

Просмотреть файл

@ -1,6 +1,7 @@
const { contextBridge, ipcRenderer } = require('electron')
contextBridge.exposeInMainWorld('electronAPI', {
cancelBluetoothRequest: (callback) => ipcRenderer.send('cancel-bluetooth-request', callback),
bluetoothPairingRequest: (callback) => ipcRenderer.on('bluetooth-pairing-request', callback),
bluetoothPairingResponse: (response) => ipcRenderer.send('bluetooth-pairing-response', response)
})

Просмотреть файл

@ -7,6 +7,12 @@ async function testIt() {
document.getElementById('clickme').addEventListener('click',testIt)
function cancelRequest() {
window.electronAPI.cancelBluetoothRequest()
}
document.getElementById('cancel').addEventListener('click', cancelRequest)
window.electronAPI.bluetoothPairingRequest((event, details) => {
const response = {}

Просмотреть файл

@ -27,8 +27,6 @@ namespace electron {
namespace {
const int kMaxScanRetries = 5;
void OnDeviceChosen(const content::BluetoothChooser::EventHandler& handler,
const std::string& device_id) {
if (device_id.empty()) {
@ -66,29 +64,15 @@ void BluetoothChooser::SetAdapterPresence(AdapterPresence presence) {
}
void BluetoothChooser::ShowDiscoveryState(DiscoveryState state) {
bool idle_state = false;
switch (state) {
case DiscoveryState::FAILED_TO_START:
refreshing_ = false;
event_handler_.Run(content::BluetoothChooserEvent::CANCELLED, "");
break;
return;
case DiscoveryState::IDLE:
refreshing_ = false;
if (device_map_.empty()) {
auto event = ++num_retries_ > kMaxScanRetries
? content::BluetoothChooserEvent::CANCELLED
: content::BluetoothChooserEvent::RESCAN;
event_handler_.Run(event, "");
} else {
bool prevent_default = api_web_contents_->Emit(
"select-bluetooth-device", GetDeviceList(),
base::BindOnce(&OnDeviceChosen, event_handler_));
if (!prevent_default) {
auto it = device_map_.begin();
auto device_id = it->first;
event_handler_.Run(content::BluetoothChooserEvent::SELECTED,
device_id);
}
}
idle_state = true;
break;
case DiscoveryState::DISCOVERING:
// The first time this state fires is due to a rescan triggering so set a
@ -101,6 +85,18 @@ void BluetoothChooser::ShowDiscoveryState(DiscoveryState state) {
}
break;
}
bool prevent_default =
api_web_contents_->Emit("select-bluetooth-device", GetDeviceList(),
base::BindOnce(&OnDeviceChosen, event_handler_));
if (!prevent_default && idle_state) {
if (device_map_.empty()) {
event_handler_.Run(content::BluetoothChooserEvent::CANCELLED, "");
} else {
auto it = device_map_.begin();
auto device_id = it->first;
event_handler_.Run(content::BluetoothChooserEvent::SELECTED, device_id);
}
}
}
void BluetoothChooser::AddOrUpdateDevice(const std::string& device_id,

Просмотреть файл

@ -44,7 +44,6 @@ class BluetoothChooser : public content::BluetoothChooser {
std::map<std::string, std::u16string> device_map_;
api::WebContents* api_web_contents_;
EventHandler event_handler_;
int num_retries_ = 0;
bool refreshing_ = false;
bool rescan_ = false;
};