Browse Source

refactor: bluetooth in serial chooser when exclusively wireless serial ports are expected (#45671)

* refactor: bluetooth in serial chooser when exclusively wireless serial ports are expected

https://chromium-review.googlesource.com/c/chromium/src/+/5737296

* chore: review feedback
Shelley Vohr 1 month ago
parent
commit
4867b5dc75

+ 61 - 2
shell/browser/serial/serial_chooser_controller.cc

@@ -10,6 +10,8 @@
 #include "base/containers/contains.h"
 #include "base/functional/bind.h"
 #include "content/public/browser/web_contents.h"
+#include "device/bluetooth/bluetooth_adapter.h"
+#include "device/bluetooth/bluetooth_adapter_factory.h"
 #include "device/bluetooth/public/cpp/bluetooth_uuid.h"
 #include "services/device/public/cpp/bluetooth/bluetooth_utils.h"
 #include "services/device/public/mojom/serial.mojom.h"
@@ -65,6 +67,8 @@ namespace electron {
 
 namespace {
 
+using ::device::BluetoothAdapter;
+using ::device::BluetoothAdapterFactory;
 using ::device::mojom::SerialPortType;
 
 bool FilterMatchesPort(const blink::mojom::SerialPortFilter& filter,
@@ -124,8 +128,11 @@ SerialChooserController::SerialChooserController(
                          web_contents_->GetBrowserContext())
                          ->AsWeakPtr();
   DCHECK(chooser_context_);
-  chooser_context_->GetPortManager()->GetDevices(base::BindOnce(
-      &SerialChooserController::OnGetDevices, weak_factory_.GetWeakPtr()));
+
+  base::SequencedTaskRunner::GetCurrentDefault()->PostTask(
+      FROM_HERE, base::BindOnce(&SerialChooserController::GetDevices,
+                                weak_factory_.GetWeakPtr()));
+
   observation_.Observe(chooser_context_.get());
 }
 
@@ -140,6 +147,29 @@ api::Session* SerialChooserController::GetSession() {
   return api::Session::FromBrowserContext(web_contents_->GetBrowserContext());
 }
 
+void SerialChooserController::GetDevices() {
+  if (IsWirelessSerialPortOnly()) {
+    if (!adapter_) {
+      BluetoothAdapterFactory::Get()->GetAdapter(base::BindOnce(
+          &SerialChooserController::OnGetAdapter, weak_factory_.GetWeakPtr(),
+          base::BindOnce(&SerialChooserController::GetDevices,
+                         weak_factory_.GetWeakPtr())));
+      return;
+    }
+  }
+
+  chooser_context_->GetPortManager()->GetDevices(base::BindOnce(
+      &SerialChooserController::OnGetDevices, weak_factory_.GetWeakPtr()));
+}
+
+void SerialChooserController::AdapterPoweredChanged(BluetoothAdapter* adapter,
+                                                    bool powered) {
+  // TODO(codebytere): maybe emit an event here?
+  if (powered) {
+    GetDevices();
+  }
+}
+
 void SerialChooserController::OnPortAdded(
     const device::mojom::SerialPortInfo& port) {
   if (!DisplayDevice(port))
@@ -196,6 +226,7 @@ void SerialChooserController::OnGetDevices(
     return port1->path.BaseName() < port2->path.BaseName();
   });
 
+  ports_.clear();
   for (auto& port : ports) {
     if (DisplayDevice(*port))
       ports_.push_back(std::move(port));
@@ -235,5 +266,33 @@ void SerialChooserController::RunCallback(
     std::move(callback_).Run(std::move(port));
   }
 }
+void SerialChooserController::OnGetAdapter(
+    base::OnceClosure callback,
+    scoped_refptr<BluetoothAdapter> adapter) {
+  CHECK(adapter);
+  adapter_ = std::move(adapter);
+  adapter_observation_.Observe(adapter_.get());
+  std::move(callback).Run();
+}
+
+bool SerialChooserController::IsWirelessSerialPortOnly() const {
+  if (allowed_bluetooth_service_class_ids_.empty()) {
+    return false;
+  }
+
+  // The system's wired and wireless serial ports can be shown if there is no
+  // filter.
+  if (filters_.empty()) {
+    return false;
+  }
+
+  // Check if all the filters are meant for serial port from Bluetooth device.
+  for (const auto& filter : filters_) {
+    if (!filter->bluetooth_service_class_id) {
+      return false;
+    }
+  }
+  return true;
+}
 
 }  // namespace electron

+ 17 - 2
shell/browser/serial/serial_chooser_controller.h

@@ -12,6 +12,7 @@
 #include "base/scoped_observation.h"
 #include "content/public/browser/global_routing_id.h"
 #include "content/public/browser/serial_chooser.h"
+#include "device/bluetooth/bluetooth_adapter.h"
 #include "services/device/public/mojom/serial.mojom-forward.h"
 #include "shell/browser/serial/serial_chooser_context.h"
 #include "third_party/blink/public/mojom/serial/serial.mojom-forward.h"
@@ -31,7 +32,8 @@ class ElectronSerialDelegate;
 
 // SerialChooserController provides data for the Serial API permission prompt.
 class SerialChooserController final
-    : private SerialChooserContext::PortObserver {
+    : private SerialChooserContext::PortObserver,
+      private device::BluetoothAdapter::Observer {
  public:
   SerialChooserController(
       content::RenderFrameHost* render_frame_host,
@@ -55,12 +57,21 @@ class SerialChooserController final
   void OnPermissionRevoked(const url::Origin& origin) override {}
   void OnSerialChooserContextShutdown() override;
 
+  // BluetoothAdapter::Observer
+  void AdapterPoweredChanged(device::BluetoothAdapter* adapter,
+                             bool powered) override;
+
  private:
   api::Session* GetSession();
+  void GetDevices();
   void OnGetDevices(std::vector<device::mojom::SerialPortInfoPtr> ports);
   bool DisplayDevice(const device::mojom::SerialPortInfo& port) const;
   void RunCallback(device::mojom::SerialPortInfoPtr port);
   void OnDeviceChosen(const std::string& port_id);
+  void OnGetAdapter(base::OnceClosure callback,
+                    scoped_refptr<device::BluetoothAdapter> adapter);
+  // Whether it will only show ports from bluetooth devices.
+  [[nodiscard]] bool IsWirelessSerialPortOnly() const;
 
   base::WeakPtr<content::WebContents> web_contents_;
 
@@ -77,8 +88,12 @@ class SerialChooserController final
 
   std::vector<device::mojom::SerialPortInfoPtr> ports_;
 
-  base::WeakPtr<ElectronSerialDelegate> serial_delegate_;
+  scoped_refptr<device::BluetoothAdapter> adapter_;
+  base::ScopedObservation<device::BluetoothAdapter,
+                          device::BluetoothAdapter::Observer>
+      adapter_observation_{this};
 
+  base::WeakPtr<ElectronSerialDelegate> serial_delegate_;
   content::GlobalRenderFrameHostId render_frame_host_id_;
 
   base::WeakPtrFactory<SerialChooserController> weak_factory_{this};