|
@@ -9,6 +9,7 @@
|
|
|
|
|
|
#include "base/command_line.h"
|
|
|
#include "base/containers/contains.h"
|
|
|
+#include "base/scoped_observation.h"
|
|
|
#include "chrome/common/chrome_features.h"
|
|
|
#include "content/public/browser/web_contents.h"
|
|
|
#include "electron/buildflags/buildflags.h"
|
|
@@ -36,6 +37,70 @@ electron::HidChooserContext* GetChooserContext(
|
|
|
|
|
|
namespace electron {
|
|
|
|
|
|
+// Manages the HidDelegate observers for a single browser context.
|
|
|
+class ElectronHidDelegate::ContextObservation
|
|
|
+ : public HidChooserContext::DeviceObserver {
|
|
|
+ public:
|
|
|
+ ContextObservation(ElectronHidDelegate* parent,
|
|
|
+ content::BrowserContext* browser_context)
|
|
|
+ : parent_(parent), browser_context_(browser_context) {
|
|
|
+ auto* chooser_context = GetChooserContext(browser_context_);
|
|
|
+ device_observation_.Observe(chooser_context);
|
|
|
+ }
|
|
|
+
|
|
|
+ ContextObservation(ContextObservation&) = delete;
|
|
|
+ ContextObservation& operator=(ContextObservation&) = delete;
|
|
|
+ ~ContextObservation() override = default;
|
|
|
+
|
|
|
+ // HidChooserContext::DeviceObserver:
|
|
|
+ void OnDeviceAdded(const device::mojom::HidDeviceInfo& device_info) override {
|
|
|
+ for (auto& observer : observer_list_)
|
|
|
+ observer.OnDeviceAdded(device_info);
|
|
|
+ }
|
|
|
+
|
|
|
+ void OnDeviceRemoved(
|
|
|
+ const device::mojom::HidDeviceInfo& device_info) override {
|
|
|
+ for (auto& observer : observer_list_)
|
|
|
+ observer.OnDeviceRemoved(device_info);
|
|
|
+ }
|
|
|
+
|
|
|
+ void OnDeviceChanged(
|
|
|
+ const device::mojom::HidDeviceInfo& device_info) override {
|
|
|
+ for (auto& observer : observer_list_)
|
|
|
+ observer.OnDeviceChanged(device_info);
|
|
|
+ }
|
|
|
+
|
|
|
+ void OnHidManagerConnectionError() override {
|
|
|
+ for (auto& observer : observer_list_)
|
|
|
+ observer.OnHidManagerConnectionError();
|
|
|
+ }
|
|
|
+
|
|
|
+ void OnHidChooserContextShutdown() override {
|
|
|
+ parent_->observations_.erase(browser_context_);
|
|
|
+ // Return since `this` is now deleted.
|
|
|
+ }
|
|
|
+
|
|
|
+ void AddObserver(content::HidDelegate::Observer* observer) {
|
|
|
+ observer_list_.AddObserver(observer);
|
|
|
+ }
|
|
|
+
|
|
|
+ void RemoveObserver(content::HidDelegate::Observer* observer) {
|
|
|
+ observer_list_.RemoveObserver(observer);
|
|
|
+ }
|
|
|
+
|
|
|
+ private:
|
|
|
+ // Safe because `parent_` owns `this`.
|
|
|
+ const raw_ptr<ElectronHidDelegate> parent_;
|
|
|
+
|
|
|
+ // Safe because `this` is destroyed when the context is lost.
|
|
|
+ const raw_ptr<content::BrowserContext> browser_context_;
|
|
|
+
|
|
|
+ base::ScopedObservation<HidChooserContext, HidChooserContext::DeviceObserver>
|
|
|
+ device_observation_{this};
|
|
|
+
|
|
|
+ base::ObserverList<content::HidDelegate::Observer> observer_list_;
|
|
|
+};
|
|
|
+
|
|
|
ElectronHidDelegate::ElectronHidDelegate() = default;
|
|
|
|
|
|
ElectronHidDelegate::~ElectronHidDelegate() = default;
|
|
@@ -45,11 +110,11 @@ std::unique_ptr<content::HidChooser> ElectronHidDelegate::RunChooser(
|
|
|
std::vector<blink::mojom::HidDeviceFilterPtr> filters,
|
|
|
std::vector<blink::mojom::HidDeviceFilterPtr> exclusion_filters,
|
|
|
content::HidChooser::Callback callback) {
|
|
|
- DCHECK(render_frame_host);
|
|
|
- auto* chooser_context =
|
|
|
- GetChooserContext(render_frame_host->GetBrowserContext());
|
|
|
- if (!device_observation_.IsObserving())
|
|
|
- device_observation_.Observe(chooser_context);
|
|
|
+ auto* browser_context = render_frame_host->GetBrowserContext();
|
|
|
+
|
|
|
+ // Start observing HidChooserContext for permission and device events.
|
|
|
+ GetContextObserver(browser_context);
|
|
|
+ DCHECK(base::Contains(observations_, browser_context));
|
|
|
|
|
|
HidChooserController* controller = ControllerForFrame(render_frame_host);
|
|
|
if (controller) {
|
|
@@ -101,16 +166,14 @@ device::mojom::HidManager* ElectronHidDelegate::GetHidManager(
|
|
|
|
|
|
void ElectronHidDelegate::AddObserver(content::BrowserContext* browser_context,
|
|
|
Observer* observer) {
|
|
|
- observer_list_.AddObserver(observer);
|
|
|
- auto* chooser_context = GetChooserContext(browser_context);
|
|
|
- if (!device_observation_.IsObserving())
|
|
|
- device_observation_.Observe(chooser_context);
|
|
|
+ GetContextObserver(browser_context)->AddObserver(observer);
|
|
|
}
|
|
|
|
|
|
void ElectronHidDelegate::RemoveObserver(
|
|
|
content::BrowserContext* browser_context,
|
|
|
content::HidDelegate::Observer* observer) {
|
|
|
- observer_list_.RemoveObserver(observer);
|
|
|
+ DCHECK(base::Contains(observations_, browser_context));
|
|
|
+ GetContextObserver(browser_context)->RemoveObserver(observer);
|
|
|
}
|
|
|
|
|
|
const device::mojom::HidDeviceInfo* ElectronHidDelegate::GetDeviceInfo(
|
|
@@ -140,33 +203,14 @@ bool ElectronHidDelegate::IsServiceWorkerAllowedForOrigin(
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
-void ElectronHidDelegate::OnDeviceAdded(
|
|
|
- const device::mojom::HidDeviceInfo& device_info) {
|
|
|
- for (auto& observer : observer_list_)
|
|
|
- observer.OnDeviceAdded(device_info);
|
|
|
-}
|
|
|
-
|
|
|
-void ElectronHidDelegate::OnDeviceRemoved(
|
|
|
- const device::mojom::HidDeviceInfo& device_info) {
|
|
|
- for (auto& observer : observer_list_)
|
|
|
- observer.OnDeviceRemoved(device_info);
|
|
|
-}
|
|
|
-
|
|
|
-void ElectronHidDelegate::OnDeviceChanged(
|
|
|
- const device::mojom::HidDeviceInfo& device_info) {
|
|
|
- for (auto& observer : observer_list_)
|
|
|
- observer.OnDeviceChanged(device_info);
|
|
|
-}
|
|
|
-
|
|
|
-void ElectronHidDelegate::OnHidManagerConnectionError() {
|
|
|
- device_observation_.Reset();
|
|
|
-
|
|
|
- for (auto& observer : observer_list_)
|
|
|
- observer.OnHidManagerConnectionError();
|
|
|
-}
|
|
|
-
|
|
|
-void ElectronHidDelegate::OnHidChooserContextShutdown() {
|
|
|
- device_observation_.Reset();
|
|
|
+ElectronHidDelegate::ContextObservation*
|
|
|
+ElectronHidDelegate::GetContextObserver(
|
|
|
+ content::BrowserContext* browser_context) {
|
|
|
+ if (!base::Contains(observations_, browser_context)) {
|
|
|
+ observations_.emplace(browser_context, std::make_unique<ContextObservation>(
|
|
|
+ this, browser_context));
|
|
|
+ }
|
|
|
+ return observations_[browser_context].get();
|
|
|
}
|
|
|
|
|
|
HidChooserController* ElectronHidDelegate::ControllerForFrame(
|