blob: 620e2a463a82d07c24422e65d41ab6d9396e3884 [file] [log] [blame]
// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "content/web_test/browser/fake_bluetooth_delegate.h"
#include "base/containers/contains.h"
#include "content/public/browser/web_contents.h"
#include "content/web_test/browser/web_test_control_host.h"
#include "device/bluetooth/bluetooth_device.h"
#include "third_party/blink/public/common/bluetooth/web_bluetooth_device_id.h"
#include "third_party/blink/public/mojom/bluetooth/web_bluetooth.mojom.h"
#include "url/origin.h"
using blink::WebBluetoothDeviceId;
using device::BluetoothDevice;
using device::BluetoothUUID;
namespace content {
namespace {
class AlwaysAllowBluetoothScanning : public BluetoothScanningPrompt {
public:
explicit AlwaysAllowBluetoothScanning(const EventHandler& event_handler) {
event_handler.Run(BluetoothScanningPrompt::Event::kAllow);
}
};
} // namespace
// public
FakeBluetoothDelegate::FakeBluetoothDelegate() = default;
FakeBluetoothDelegate::~FakeBluetoothDelegate() = default;
std::unique_ptr<BluetoothChooser> FakeBluetoothDelegate::RunBluetoothChooser(
RenderFrameHost* frame,
const BluetoothChooser::EventHandler& event_handler) {
if (auto* web_test_control_host = WebTestControlHost::Get())
return web_test_control_host->RunBluetoothChooser(frame, event_handler);
return nullptr;
}
std::unique_ptr<BluetoothScanningPrompt>
FakeBluetoothDelegate::ShowBluetoothScanningPrompt(
RenderFrameHost* frame,
const BluetoothScanningPrompt::EventHandler& event_handler) {
return std::make_unique<AlwaysAllowBluetoothScanning>(event_handler);
}
void FakeBluetoothDelegate::ShowDevicePairPrompt(
RenderFrameHost* frame,
const std::u16string& device_identifier,
PairPromptCallback callback,
PairingKind pairing_kind,
const std::optional<std::u16string>& pin) {
std::move(callback).Run(content::BluetoothDelegate::PairPromptResult(
content::BluetoothDelegate::PairPromptStatus::kCancelled));
}
WebBluetoothDeviceId FakeBluetoothDelegate::GetWebBluetoothDeviceId(
RenderFrameHost* frame,
const std::string& device_address) {
auto& device_address_to_id_map = GetAddressToIdMapForOrigin(frame);
auto it = device_address_to_id_map.find(device_address);
if (it != device_address_to_id_map.end())
return it->second;
return {};
}
std::string FakeBluetoothDelegate::GetDeviceAddress(
RenderFrameHost* frame,
const WebBluetoothDeviceId& device_id) {
auto& device_address_to_id_map = GetAddressToIdMapForOrigin(frame);
for (auto& entry : device_address_to_id_map) {
if (entry.second == device_id)
return entry.first;
}
return std::string();
}
blink::WebBluetoothDeviceId FakeBluetoothDelegate::AddScannedDevice(
RenderFrameHost* frame,
const std::string& device_address) {
return GetOrCreateDeviceIdForDeviceAddress(frame, device_address);
}
WebBluetoothDeviceId FakeBluetoothDelegate::GrantServiceAccessPermission(
RenderFrameHost* frame,
const BluetoothDevice* device,
const blink::mojom::WebBluetoothRequestDeviceOptions* options) {
WebBluetoothDeviceId device_id =
GetOrCreateDeviceIdForDeviceAddress(frame, device->GetAddress());
device_id_to_name_map_[device_id] =
device->GetName() ? *device->GetName() : std::string();
GrantUnionOfServicesAndManufacturerDataForDevice(device_id, options);
return device_id;
}
bool FakeBluetoothDelegate::HasDevicePermission(
RenderFrameHost* frame,
const WebBluetoothDeviceId& device_id) {
return base::Contains(device_id_to_services_map_, device_id);
}
void FakeBluetoothDelegate::RevokeDevicePermissionWebInitiated(
RenderFrameHost* frame,
const WebBluetoothDeviceId& device_id) {
device_id_to_services_map_.erase(device_id);
device_id_to_name_map_.erase(device_id);
device_id_to_manufacturer_code_map_.erase(device_id);
auto& device_address_to_id_map = GetAddressToIdMapForOrigin(frame);
base::EraseIf(device_address_to_id_map,
[device_id](auto& entry) { return entry.second == device_id; });
}
bool FakeBluetoothDelegate::IsAllowedToAccessService(
RenderFrameHost* frame,
const WebBluetoothDeviceId& device_id,
const BluetoothUUID& service) {
auto id_to_services_it = device_id_to_services_map_.find(device_id);
if (id_to_services_it == device_id_to_services_map_.end())
return false;
return base::Contains(id_to_services_it->second, service);
}
bool FakeBluetoothDelegate::IsAllowedToAccessAtLeastOneService(
RenderFrameHost* frame,
const WebBluetoothDeviceId& device_id) {
auto id_to_services_it = device_id_to_services_map_.find(device_id);
if (id_to_services_it == device_id_to_services_map_.end())
return false;
return !id_to_services_it->second.empty();
}
bool FakeBluetoothDelegate::IsAllowedToAccessManufacturerData(
RenderFrameHost* frame,
const blink::WebBluetoothDeviceId& device_id,
const uint16_t manufacturer_code) {
auto id_to_manufacturer_data_it =
device_id_to_manufacturer_code_map_.find(device_id);
if (id_to_manufacturer_data_it == device_id_to_manufacturer_code_map_.end())
return false;
return base::Contains(id_to_manufacturer_data_it->second, manufacturer_code);
}
void FakeBluetoothDelegate::AddFramePermissionObserver(
FramePermissionObserver* observer) {}
void FakeBluetoothDelegate::RemoveFramePermissionObserver(
FramePermissionObserver* observer) {}
std::vector<blink::mojom::WebBluetoothDevicePtr>
FakeBluetoothDelegate::GetPermittedDevices(RenderFrameHost* frame) {
std::vector<blink::mojom::WebBluetoothDevicePtr> permitted_devices;
auto& device_address_to_id_map = GetAddressToIdMapForOrigin(frame);
for (const auto& entry : device_address_to_id_map) {
auto permitted_device = blink::mojom::WebBluetoothDevice::New();
WebBluetoothDeviceId device_id = entry.second;
permitted_device->id = device_id;
permitted_device->name = device_id_to_name_map_[device_id];
permitted_devices.push_back(std::move(permitted_device));
}
return permitted_devices;
}
WebBluetoothDeviceId FakeBluetoothDelegate::GetOrCreateDeviceIdForDeviceAddress(
RenderFrameHost* frame,
const std::string& device_address) {
WebBluetoothDeviceId device_id;
auto& device_address_to_id_map = GetAddressToIdMapForOrigin(frame);
auto it = device_address_to_id_map.find(device_address);
if (it != device_address_to_id_map.end()) {
device_id = it->second;
} else {
device_id = WebBluetoothDeviceId::Create();
device_address_to_id_map[device_address] = device_id;
}
return device_id;
}
void FakeBluetoothDelegate::GrantUnionOfServicesAndManufacturerDataForDevice(
const WebBluetoothDeviceId& device_id,
const blink::mojom::WebBluetoothRequestDeviceOptions* options) {
if (!options)
return;
// Create an entry for |device_id| in |device_id_to_services_map_| to indicate
// that the site can attempt to GATT connect even if |options| does not
// contain any services.
base::flat_set<BluetoothUUID>& granted_services =
device_id_to_services_map_[device_id];
if (options->filters) {
for (const blink::mojom::WebBluetoothLeScanFilterPtr& filter :
options->filters.value()) {
if (!filter->services)
continue;
for (const BluetoothUUID& uuid : filter->services.value())
granted_services.insert(uuid);
}
}
for (const BluetoothUUID& uuid : options->optional_services)
granted_services.insert(uuid);
base::flat_set<uint16_t>& granted_manufacturer_data =
device_id_to_manufacturer_code_map_[device_id];
for (const uint16_t manufacturer_code : options->optional_manufacturer_data)
granted_manufacturer_data.insert(manufacturer_code);
}
FakeBluetoothDelegate::AddressToIdMap&
FakeBluetoothDelegate::GetAddressToIdMapForOrigin(RenderFrameHost* frame) {
auto* web_contents = WebContents::FromRenderFrameHost(frame);
auto origin_pair = std::make_pair(
frame->GetLastCommittedOrigin(),
web_contents->GetPrimaryMainFrame()->GetLastCommittedOrigin());
return device_address_to_id_map_for_origin_[origin_pair];
}
} // namespace content