Browse Source

fix: navigator.bluetooth.requestDevice crash (#27941)

* fix: navigator.bluetooth.requestDevice crash

* update bluetooth test to handle bluetooth permission denied

(cherry picked from commit 1c7ca277cc0b7f1a9e4e93205012b116b5d23c54)
John Kleinschmidt 4 years ago
parent
commit
26c5cc2801

+ 15 - 0
shell/browser/lib/bluetooth_chooser.cc

@@ -60,9 +60,11 @@ void BluetoothChooser::SetAdapterPresence(AdapterPresence presence) {
 void BluetoothChooser::ShowDiscoveryState(DiscoveryState state) {
   switch (state) {
     case DiscoveryState::FAILED_TO_START:
+      refreshing_ = false;
       event_handler_.Run(content::BluetoothChooserEvent::CANCELLED, "");
       break;
     case DiscoveryState::IDLE:
+      refreshing_ = false;
       if (device_map_.empty()) {
         auto event = ++num_retries_ > kMaxScanRetries
                          ? content::BluetoothChooserEvent::CANCELLED
@@ -81,6 +83,14 @@ void BluetoothChooser::ShowDiscoveryState(DiscoveryState state) {
       }
       break;
     case DiscoveryState::DISCOVERING:
+      // The first time this state fires is due to a rescan triggering so set a
+      // flag to ignore devices
+      if (!refreshing_) {
+        refreshing_ = true;
+      } else {
+        // The second time this state fires we are now safe to pick a device
+        refreshing_ = false;
+      }
       break;
   }
 }
@@ -91,6 +101,11 @@ void BluetoothChooser::AddOrUpdateDevice(const std::string& device_id,
                                          bool is_gatt_connected,
                                          bool is_paired,
                                          int signal_strength_level) {
+  if (refreshing_) {
+    // If the list of bluetooth devices is currently being generated don't fire
+    // an event
+    return;
+  }
   bool changed = false;
   auto entry = device_map_.find(device_id);
   if (entry == device_map_.end()) {

+ 1 - 0
shell/browser/lib/bluetooth_chooser.h

@@ -41,6 +41,7 @@ class BluetoothChooser : public content::BluetoothChooser {
   api::WebContents* api_web_contents_;
   EventHandler event_handler_;
   int num_retries_ = 0;
+  bool refreshing_ = false;
 
   DISALLOW_COPY_AND_ASSIGN(BluetoothChooser);
 };

+ 21 - 0
spec-main/chromium-spec.ts

@@ -1530,3 +1530,24 @@ describe('navigator.clipboard', () => {
     expect(clipboard).to.not.equal('Read permission denied.');
   });
 });
+
+describe('navigator.bluetooth', () => {
+  let w: BrowserWindow;
+  before(async () => {
+    w = new BrowserWindow({
+      show: false,
+      webPreferences: {
+        enableBlinkFeatures: 'WebBluetooth'
+      }
+    });
+    await w.loadFile(path.join(fixturesPath, 'pages', 'blank.html'));
+  });
+
+  after(closeAllWindows);
+
+  it('can request bluetooth devices', async () => {
+    const bluetooth = await w.webContents.executeJavaScript(`
+    navigator.bluetooth.requestDevice({ acceptAllDevices: true}).then(device => "Found a device!").catch(err => err.message);`, true);
+    expect(bluetooth).to.be.oneOf(['Found a device!', 'Bluetooth adapter not available.', 'User cancelled the requestDevice() chooser.']);
+  });
+});