blob: 7187609453ccdabce09be39b060ad456eceadbfe [file] [log] [blame]
// Copyright 2016 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 "content/browser/bluetooth/frame_connected_bluetooth_devices.h"
#include "base/optional.h"
#include "base/strings/string_util.h"
#include "content/browser/web_contents/web_contents_impl.h"
#include "content/public/browser/web_contents.h"
#include "device/bluetooth/bluetooth_gatt_connection.h"
namespace content {
FrameConnectedBluetoothDevices::FrameConnectedBluetoothDevices(
RenderFrameHost* rfh)
: web_contents_impl_(static_cast<WebContentsImpl*>(
WebContents::FromRenderFrameHost(rfh))) {}
FrameConnectedBluetoothDevices::~FrameConnectedBluetoothDevices() {
for (size_t i = 0; i < device_id_to_connection_map_.size(); i++) {
DecrementDevicesConnectedCount();
}
}
bool FrameConnectedBluetoothDevices::IsConnectedToDeviceWithId(
const WebBluetoothDeviceId& device_id) {
auto connection_iter = device_id_to_connection_map_.find(device_id);
if (connection_iter == device_id_to_connection_map_.end()) {
return false;
}
// Owners of FrameConnectedBluetoothDevices should notify it when a device
// disconnects but currently Android and Mac don't notify of disconnection,
// so the map could get into a state where it's holding a stale connection.
// For this reason we return the value of IsConnected for the connection.
// TODO(ortuno): Always return true once Android and Mac notify of
// disconnection.
// http://crbug.com/607273
return connection_iter->second->IsConnected();
}
void FrameConnectedBluetoothDevices::Insert(
const WebBluetoothDeviceId& device_id,
std::unique_ptr<device::BluetoothGattConnection> connection) {
auto connection_iter = device_id_to_connection_map_.find(device_id);
if (connection_iter != device_id_to_connection_map_.end()) {
// Owners of FrameConnectedBluetoothDevices should notify it when a device
// disconnects but currently Android and Mac don't notify of disconnection,
// so the map could get into a state where it's holding a stale connection.
// For this reason we check if the current connection is active and if
// not we remove it.
// TODO(ortuno): Remove once Android and Mac notify of disconnection.
// http://crbug.com/607273
if (!connection_iter->second->IsConnected()) {
device_address_to_id_map_.erase(
connection_iter->second->GetDeviceAddress());
device_id_to_connection_map_.erase(connection_iter);
DecrementDevicesConnectedCount();
} else {
// It's possible for WebBluetoothServiceImpl to issue two successive
// connection requests for which it would get two successive responses
// and consequently try to insert two BluetoothGattConnections for the
// same device. WebBluetoothServiceImpl should reject or queue connection
// requests if there is a pending connection already, but the platform
// abstraction doesn't currently support checking for pending connections.
// TODO(ortuno): CHECK that this never happens once the platform
// abstraction allows to check for pending connections.
// http://crbug.com/583544
return;
}
}
device_address_to_id_map_[connection->GetDeviceAddress()] = device_id;
device_id_to_connection_map_[device_id] = std::move(connection);
IncrementDevicesConnectedCount();
}
void FrameConnectedBluetoothDevices::CloseConnectionToDeviceWithId(
const WebBluetoothDeviceId& device_id) {
auto connection_iter = device_id_to_connection_map_.find(device_id);
if (connection_iter == device_id_to_connection_map_.end()) {
return;
}
CHECK(device_address_to_id_map_.erase(
connection_iter->second->GetDeviceAddress()));
device_id_to_connection_map_.erase(connection_iter);
DecrementDevicesConnectedCount();
}
base::Optional<WebBluetoothDeviceId>
FrameConnectedBluetoothDevices::CloseConnectionToDeviceWithAddress(
const std::string& device_address) {
auto device_address_iter = device_address_to_id_map_.find(device_address);
if (device_address_iter == device_address_to_id_map_.end()) {
return base::nullopt;
}
WebBluetoothDeviceId device_id = device_address_iter->second;
CHECK(device_address_to_id_map_.erase(device_address));
CHECK(device_id_to_connection_map_.erase(device_id));
DecrementDevicesConnectedCount();
return base::make_optional(device_id);
}
void FrameConnectedBluetoothDevices::IncrementDevicesConnectedCount() {
web_contents_impl_->IncrementBluetoothConnectedDeviceCount();
}
void FrameConnectedBluetoothDevices::DecrementDevicesConnectedCount() {
web_contents_impl_->DecrementBluetoothConnectedDeviceCount();
}
} // namespace content