blob: 6b8fe8fc6dcc9218e90e84c9be41c316714df6ad [file] [log] [blame]
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/bluetooth/chrome_bluetooth_delegate.h"
#include <memory>
#include "base/scoped_observer.h"
#include "base/strings/utf_string_conversions.h"
#include "build/build_config.h"
#include "chrome/browser/bluetooth/bluetooth_chooser_context.h"
#include "chrome/browser/bluetooth/bluetooth_chooser_context_factory.h"
#include "chrome/browser/profiles/profile.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/web_contents.h"
#include "device/bluetooth/bluetooth_device.h"
#include "device/bluetooth/public/cpp/bluetooth_uuid.h"
#include "third_party/blink/public/common/bluetooth/web_bluetooth_device_id.h"
#include "third_party/blink/public/mojom/bluetooth/web_bluetooth.mojom.h"
#if defined(OS_ANDROID)
#include "chrome/browser/ui/android/device_dialog/bluetooth_chooser_android.h"
#include "chrome/browser/ui/android/device_dialog/bluetooth_scanning_prompt_android.h"
#include "chrome/browser/vr/vr_tab_helper.h"
#else
#include "chrome/browser/ui/bluetooth/bluetooth_chooser_controller.h"
#include "chrome/browser/ui/bluetooth/bluetooth_chooser_desktop.h"
#include "chrome/browser/ui/bluetooth/bluetooth_scanning_prompt_controller.h"
#include "chrome/browser/ui/bluetooth/bluetooth_scanning_prompt_desktop.h"
#include "extensions/browser/app_window/app_window_registry.h"
#include "extensions/browser/extensions_browser_client.h"
#endif // OS_ANDROID
using blink::WebBluetoothDeviceId;
using content::RenderFrameHost;
using content::WebContents;
using device::BluetoothUUID;
namespace {
BluetoothChooserContext* GetBluetoothChooserContext(RenderFrameHost* frame) {
auto* profile = Profile::FromBrowserContext(frame->GetBrowserContext());
return BluetoothChooserContextFactory::GetForProfile(profile);
}
} // namespace
ChromeBluetoothDelegate::ChromeBluetoothDelegate() = default;
ChromeBluetoothDelegate::~ChromeBluetoothDelegate() = default;
std::unique_ptr<content::BluetoothChooser>
ChromeBluetoothDelegate::RunBluetoothChooser(
content::RenderFrameHost* frame,
const content::BluetoothChooser::EventHandler& event_handler) {
#if defined(OS_ANDROID)
if (vr::VrTabHelper::IsUiSuppressedInVr(
WebContents::FromRenderFrameHost(frame),
vr::UiSuppressedElement::kBluetoothChooser)) {
return nullptr;
}
return std::make_unique<BluetoothChooserAndroid>(frame, event_handler);
#else
if (extensions::AppWindowRegistry::Get(frame->GetBrowserContext())
->GetAppWindowForWebContents(
WebContents::FromRenderFrameHost(frame))) {
return extensions::ExtensionsBrowserClient::Get()->CreateBluetoothChooser(
frame, event_handler);
}
return std::make_unique<BluetoothChooserDesktop>(frame, event_handler);
#endif
}
std::unique_ptr<content::BluetoothScanningPrompt>
ChromeBluetoothDelegate::ShowBluetoothScanningPrompt(
content::RenderFrameHost* frame,
const content::BluetoothScanningPrompt::EventHandler& event_handler) {
#if defined(OS_ANDROID)
return std::make_unique<BluetoothScanningPromptAndroid>(frame, event_handler);
#else
if (extensions::AppWindowRegistry::Get(frame->GetBrowserContext())
->GetAppWindowForWebContents(
WebContents::FromRenderFrameHost(frame))) {
return nullptr;
}
return std::make_unique<BluetoothScanningPromptDesktop>(frame, event_handler);
#endif
}
WebBluetoothDeviceId ChromeBluetoothDelegate::GetWebBluetoothDeviceId(
RenderFrameHost* frame,
const std::string& device_address) {
return GetBluetoothChooserContext(frame)->GetWebBluetoothDeviceId(
frame->GetLastCommittedOrigin(),
frame->GetMainFrame()->GetLastCommittedOrigin(), device_address);
}
std::string ChromeBluetoothDelegate::GetDeviceAddress(
RenderFrameHost* frame,
const WebBluetoothDeviceId& device_id) {
return GetBluetoothChooserContext(frame)->GetDeviceAddress(
frame->GetLastCommittedOrigin(),
frame->GetMainFrame()->GetLastCommittedOrigin(), device_id);
}
WebBluetoothDeviceId ChromeBluetoothDelegate::AddScannedDevice(
RenderFrameHost* frame,
const std::string& device_address) {
return GetBluetoothChooserContext(frame)->AddScannedDevice(
frame->GetLastCommittedOrigin(),
frame->GetMainFrame()->GetLastCommittedOrigin(), device_address);
}
WebBluetoothDeviceId ChromeBluetoothDelegate::GrantServiceAccessPermission(
RenderFrameHost* frame,
const device::BluetoothDevice* device,
const blink::mojom::WebBluetoothRequestDeviceOptions* options) {
return GetBluetoothChooserContext(frame)->GrantServiceAccessPermission(
frame->GetLastCommittedOrigin(),
frame->GetMainFrame()->GetLastCommittedOrigin(), device, options);
}
bool ChromeBluetoothDelegate::HasDevicePermission(
RenderFrameHost* frame,
const WebBluetoothDeviceId& device_id) {
return GetBluetoothChooserContext(frame)->HasDevicePermission(
frame->GetLastCommittedOrigin(),
frame->GetMainFrame()->GetLastCommittedOrigin(), device_id);
}
bool ChromeBluetoothDelegate::IsAllowedToAccessService(
RenderFrameHost* frame,
const WebBluetoothDeviceId& device_id,
const BluetoothUUID& service) {
return GetBluetoothChooserContext(frame)->IsAllowedToAccessService(
frame->GetLastCommittedOrigin(),
frame->GetMainFrame()->GetLastCommittedOrigin(), device_id, service);
}
bool ChromeBluetoothDelegate::IsAllowedToAccessAtLeastOneService(
RenderFrameHost* frame,
const WebBluetoothDeviceId& device_id) {
return GetBluetoothChooserContext(frame)->IsAllowedToAccessAtLeastOneService(
frame->GetLastCommittedOrigin(),
frame->GetMainFrame()->GetLastCommittedOrigin(), device_id);
}
bool ChromeBluetoothDelegate::IsAllowedToAccessManufacturerData(
RenderFrameHost* frame,
const WebBluetoothDeviceId& device_id,
uint16_t manufacturer_code) {
return GetBluetoothChooserContext(frame)->IsAllowedToAccessManufacturerData(
frame->GetLastCommittedOrigin(),
frame->GetMainFrame()->GetLastCommittedOrigin(), device_id,
manufacturer_code);
}
void ChromeBluetoothDelegate::AddFramePermissionObserver(
FramePermissionObserver* observer) {
std::unique_ptr<ChooserContextPermissionObserver>& chooser_observer =
chooser_observers_[observer->GetRenderFrameHost()];
if (!chooser_observer) {
chooser_observer = std::make_unique<ChooserContextPermissionObserver>(
this, GetBluetoothChooserContext(observer->GetRenderFrameHost()));
}
chooser_observer->AddFramePermissionObserver(observer);
}
void ChromeBluetoothDelegate::RemoveFramePermissionObserver(
FramePermissionObserver* observer) {
auto it = chooser_observers_.find(observer->GetRenderFrameHost());
if (it == chooser_observers_.end())
return;
it->second->RemoveFramePermissionObserver(observer);
}
std::vector<blink::mojom::WebBluetoothDevicePtr>
ChromeBluetoothDelegate::GetPermittedDevices(content::RenderFrameHost* frame) {
auto* context = GetBluetoothChooserContext(frame);
std::vector<std::unique_ptr<permissions::ChooserContextBase::Object>>
objects = context->GetGrantedObjects(
frame->GetLastCommittedOrigin(),
frame->GetMainFrame()->GetLastCommittedOrigin());
std::vector<blink::mojom::WebBluetoothDevicePtr> permitted_devices;
for (const auto& object : objects) {
auto permitted_device = blink::mojom::WebBluetoothDevice::New();
permitted_device->id =
BluetoothChooserContext::GetObjectDeviceId(object->value);
permitted_device->name =
base::UTF16ToUTF8(context->GetObjectDisplayName(object->value));
permitted_devices.push_back(std::move(permitted_device));
}
return permitted_devices;
}
ChromeBluetoothDelegate::ChooserContextPermissionObserver::
ChooserContextPermissionObserver(ChromeBluetoothDelegate* owning_delegate,
permissions::ChooserContextBase* context)
: owning_delegate_(owning_delegate) {
observer_.Observe(context);
}
ChromeBluetoothDelegate::ChooserContextPermissionObserver::
~ChooserContextPermissionObserver() = default;
void ChromeBluetoothDelegate::ChooserContextPermissionObserver::
OnPermissionRevoked(const url::Origin& requesting_origin,
const url::Origin& embedding_origin) {
observers_pending_removal_.clear();
is_traversing_observers_ = true;
for (auto& observer : observer_list_)
observer.OnPermissionRevoked(requesting_origin, embedding_origin);
is_traversing_observers_ = false;
for (FramePermissionObserver* observer : observers_pending_removal_)
RemoveFramePermissionObserver(observer);
}
void ChromeBluetoothDelegate::ChooserContextPermissionObserver::
AddFramePermissionObserver(FramePermissionObserver* observer) {
observer_list_.AddObserver(observer);
}
void ChromeBluetoothDelegate::ChooserContextPermissionObserver::
RemoveFramePermissionObserver(FramePermissionObserver* observer) {
if (is_traversing_observers_) {
observers_pending_removal_.emplace_back(observer);
return;
}
observer_list_.RemoveObserver(observer);
if (!observer_list_.might_have_observers())
owning_delegate_->chooser_observers_.erase(observer->GetRenderFrameHost());
// Previous call destructed this instance. Don't add code after this.
}