blob: e628a25591b9507561c28266de92a845ca0b4408 [file] [log] [blame]
// Copyright (c) 2012 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 "device/bluetooth/bluetooth_device_win.h"
#include <memory>
#include <string>
#include "base/containers/scoped_ptr_hash_map.h"
#include "base/logging.h"
#include "base/memory/scoped_vector.h"
#include "base/sequenced_task_runner.h"
#include "base/strings/stringprintf.h"
#include "device/bluetooth/bluetooth_adapter_win.h"
#include "device/bluetooth/bluetooth_remote_gatt_service_win.h"
#include "device/bluetooth/bluetooth_service_record_win.h"
#include "device/bluetooth/bluetooth_socket_thread.h"
#include "device/bluetooth/bluetooth_socket_win.h"
#include "device/bluetooth/bluetooth_task_manager_win.h"
#include "device/bluetooth/bluetooth_uuid.h"
namespace {
const char kApiUnavailable[] = "This API is not implemented on this platform.";
} // namespace
namespace device {
BluetoothDeviceWin::BluetoothDeviceWin(
BluetoothAdapterWin* adapter,
const BluetoothTaskManagerWin::DeviceState& device_state,
const scoped_refptr<base::SequencedTaskRunner>& ui_task_runner,
const scoped_refptr<BluetoothSocketThread>& socket_thread,
net::NetLog* net_log,
const net::NetLogSource& net_log_source)
: BluetoothDevice(adapter),
ui_task_runner_(ui_task_runner),
socket_thread_(socket_thread),
net_log_(net_log),
net_log_source_(net_log_source) {
Update(device_state);
}
BluetoothDeviceWin::~BluetoothDeviceWin() {
// Explicitly take and erase GATT services one by one to ensure that calling
// GetGattService on removed service in GattServiceRemoved returns null.
std::vector<std::string> service_keys;
for (const auto& gatt_service : gatt_services_) {
service_keys.push_back(gatt_service.first);
}
for (const auto& key : service_keys) {
gatt_services_.take_and_erase(key);
}
}
uint32_t BluetoothDeviceWin::GetBluetoothClass() const {
return bluetooth_class_;
}
std::string BluetoothDeviceWin::GetAddress() const {
return address_;
}
BluetoothDevice::VendorIDSource
BluetoothDeviceWin::GetVendorIDSource() const {
return VENDOR_ID_UNKNOWN;
}
uint16_t BluetoothDeviceWin::GetVendorID() const {
return 0;
}
uint16_t BluetoothDeviceWin::GetProductID() const {
return 0;
}
uint16_t BluetoothDeviceWin::GetDeviceID() const {
return 0;
}
uint16_t BluetoothDeviceWin::GetAppearance() const {
// TODO(crbug.com/588083): Implementing GetAppearance()
// on mac, win, and android platforms for chrome
NOTIMPLEMENTED();
return 0;
}
base::Optional<std::string> BluetoothDeviceWin::GetName() const {
return name_;
}
bool BluetoothDeviceWin::IsPaired() const {
return paired_;
}
bool BluetoothDeviceWin::IsConnected() const {
return connected_;
}
bool BluetoothDeviceWin::IsGattConnected() const {
NOTIMPLEMENTED();
return false;
}
bool BluetoothDeviceWin::IsConnectable() const {
return false;
}
bool BluetoothDeviceWin::IsConnecting() const {
return false;
}
BluetoothDevice::UUIDSet BluetoothDeviceWin::GetUUIDs() const {
return uuids_;
}
base::Optional<int8_t> BluetoothDeviceWin::GetInquiryRSSI() const {
// In windows, we can only get connected devices and connected
// devices don't have an Inquiry RSSI.
return base::nullopt;
}
base::Optional<int8_t> BluetoothDeviceWin::GetInquiryTxPower() const {
// In windows, we can only get connected devices and connected
// devices don't have an Inquiry Tx Power.
return base::nullopt;
}
bool BluetoothDeviceWin::ExpectingPinCode() const {
NOTIMPLEMENTED();
return false;
}
bool BluetoothDeviceWin::ExpectingPasskey() const {
NOTIMPLEMENTED();
return false;
}
bool BluetoothDeviceWin::ExpectingConfirmation() const {
NOTIMPLEMENTED();
return false;
}
void BluetoothDeviceWin::GetConnectionInfo(
const ConnectionInfoCallback& callback) {
NOTIMPLEMENTED();
callback.Run(ConnectionInfo());
}
void BluetoothDeviceWin::Connect(
PairingDelegate* pairing_delegate,
const base::Closure& callback,
const ConnectErrorCallback& error_callback) {
NOTIMPLEMENTED();
}
void BluetoothDeviceWin::SetPinCode(const std::string& pincode) {
NOTIMPLEMENTED();
}
void BluetoothDeviceWin::SetPasskey(uint32_t passkey) {
NOTIMPLEMENTED();
}
void BluetoothDeviceWin::ConfirmPairing() {
NOTIMPLEMENTED();
}
void BluetoothDeviceWin::RejectPairing() {
NOTIMPLEMENTED();
}
void BluetoothDeviceWin::CancelPairing() {
NOTIMPLEMENTED();
}
void BluetoothDeviceWin::Disconnect(
const base::Closure& callback,
const ErrorCallback& error_callback) {
NOTIMPLEMENTED();
}
void BluetoothDeviceWin::Forget(const base::Closure& callback,
const ErrorCallback& error_callback) {
NOTIMPLEMENTED();
}
void BluetoothDeviceWin::ConnectToService(
const BluetoothUUID& uuid,
const ConnectToServiceCallback& callback,
const ConnectToServiceErrorCallback& error_callback) {
scoped_refptr<BluetoothSocketWin> socket(
BluetoothSocketWin::CreateBluetoothSocket(
ui_task_runner_, socket_thread_));
socket->Connect(this, uuid, base::Bind(callback, socket), error_callback);
}
void BluetoothDeviceWin::ConnectToServiceInsecurely(
const BluetoothUUID& uuid,
const ConnectToServiceCallback& callback,
const ConnectToServiceErrorCallback& error_callback) {
error_callback.Run(kApiUnavailable);
}
void BluetoothDeviceWin::CreateGattConnection(
const GattConnectionCallback& callback,
const ConnectErrorCallback& error_callback) {
// TODO(armansito): Implement.
error_callback.Run(ERROR_UNSUPPORTED_DEVICE);
}
const BluetoothServiceRecordWin* BluetoothDeviceWin::GetServiceRecord(
const device::BluetoothUUID& uuid) const {
for (ServiceRecordList::const_iterator iter = service_record_list_.begin();
iter != service_record_list_.end();
++iter) {
if ((*iter)->uuid() == uuid)
return *iter;
}
return NULL;
}
bool BluetoothDeviceWin::IsEqual(
const BluetoothTaskManagerWin::DeviceState& device_state) {
if (address_ != device_state.address || name_ != device_state.name ||
bluetooth_class_ != device_state.bluetooth_class ||
visible_ != device_state.visible ||
connected_ != device_state.connected ||
paired_ != device_state.authenticated) {
return false;
}
// Checks service collection
typedef base::ScopedPtrHashMap<std::string,
std::unique_ptr<BluetoothServiceRecordWin>>
ServiceRecordMap;
UUIDSet new_services;
ServiceRecordMap new_service_records;
for (ScopedVector<BluetoothTaskManagerWin::ServiceRecordState>::const_iterator
iter = device_state.service_record_states.begin();
iter != device_state.service_record_states.end(); ++iter) {
BluetoothServiceRecordWin* service_record = new BluetoothServiceRecordWin(
address_, (*iter)->name, (*iter)->sdp_bytes, (*iter)->gatt_uuid);
new_services.insert(service_record->uuid());
new_service_records.set(
service_record->uuid().canonical_value(),
std::unique_ptr<BluetoothServiceRecordWin>(service_record));
}
// Check that no new services have been added or removed.
if (uuids_ != new_services) {
return false;
}
for (ServiceRecordList::const_iterator iter = service_record_list_.begin();
iter != service_record_list_.end(); ++iter) {
BluetoothServiceRecordWin* service_record = (*iter);
BluetoothServiceRecordWin* new_service_record =
new_service_records.get((*iter)->uuid().canonical_value());
if (!service_record->IsEqual(*new_service_record))
return false;
}
return true;
}
void BluetoothDeviceWin::Update(
const BluetoothTaskManagerWin::DeviceState& device_state) {
address_ = device_state.address;
// Note: Callers are responsible for providing a canonicalized address.
DCHECK_EQ(address_, BluetoothDevice::CanonicalizeAddress(address_));
name_ = device_state.name;
bluetooth_class_ = device_state.bluetooth_class;
visible_ = device_state.visible;
connected_ = device_state.connected;
paired_ = device_state.authenticated;
UpdateServices(device_state);
}
void BluetoothDeviceWin::CreateGattConnectionImpl() {
// Windows implementation does not use the default CreateGattConnection
// implementation.
NOTIMPLEMENTED();
}
void BluetoothDeviceWin::DisconnectGatt() {
// Windows implementation does not use the default CreateGattConnection
// implementation.
NOTIMPLEMENTED();
}
void BluetoothDeviceWin::SetVisible(bool visible) {
visible_ = visible;
}
void BluetoothDeviceWin::UpdateServices(
const BluetoothTaskManagerWin::DeviceState& device_state) {
uuids_.clear();
service_record_list_.clear();
for (ScopedVector<BluetoothTaskManagerWin::ServiceRecordState>::const_iterator
iter = device_state.service_record_states.begin();
iter != device_state.service_record_states.end(); ++iter) {
BluetoothServiceRecordWin* service_record =
new BluetoothServiceRecordWin(device_state.address, (*iter)->name,
(*iter)->sdp_bytes, (*iter)->gatt_uuid);
service_record_list_.push_back(service_record);
uuids_.insert(service_record->uuid());
}
if (!device_state.is_bluetooth_classic())
UpdateGattServices(device_state.service_record_states);
}
bool BluetoothDeviceWin::IsGattServiceDiscovered(BluetoothUUID& uuid,
uint16_t attribute_handle) {
GattServiceMap::iterator it = gatt_services_.begin();
for (; it != gatt_services_.end(); it++) {
uint16_t it_att_handle =
static_cast<BluetoothRemoteGattServiceWin*>(it->second)
->GetAttributeHandle();
BluetoothUUID it_uuid = it->second->GetUUID();
if (attribute_handle == it_att_handle && uuid == it_uuid) {
return true;
}
}
return false;
}
bool BluetoothDeviceWin::DoesGattServiceExist(
const ScopedVector<BluetoothTaskManagerWin::ServiceRecordState>&
service_state,
BluetoothRemoteGattService* service) {
uint16_t attribute_handle =
static_cast<BluetoothRemoteGattServiceWin*>(service)
->GetAttributeHandle();
BluetoothUUID uuid = service->GetUUID();
ScopedVector<BluetoothTaskManagerWin::ServiceRecordState>::const_iterator it =
service_state.begin();
for (; it != service_state.end(); ++it) {
if (attribute_handle == (*it)->attribute_handle && uuid == (*it)->gatt_uuid)
return true;
}
return false;
}
void BluetoothDeviceWin::UpdateGattServices(
const ScopedVector<BluetoothTaskManagerWin::ServiceRecordState>&
service_state) {
// First, remove no longer exist GATT service.
{
std::vector<std::string> to_be_removed_services;
for (const auto& gatt_service : gatt_services_) {
if (!DoesGattServiceExist(service_state, gatt_service.second)) {
to_be_removed_services.push_back(gatt_service.first);
}
}
for (const auto& service : to_be_removed_services) {
gatt_services_.take_and_erase(service);
}
// Update previously discovered services.
for (auto gatt_service : gatt_services_) {
static_cast<BluetoothRemoteGattServiceWin*>(gatt_service.second)
->Update();
}
}
// Return if no new services have been added.
if (gatt_services_.size() == service_state.size())
return;
// Add new services.
for (ScopedVector<BluetoothTaskManagerWin::ServiceRecordState>::const_iterator
it = service_state.begin();
it != service_state.end(); ++it) {
if (!IsGattServiceDiscovered((*it)->gatt_uuid, (*it)->attribute_handle)) {
BluetoothRemoteGattServiceWin* primary_service =
new BluetoothRemoteGattServiceWin(this, (*it)->path, (*it)->gatt_uuid,
(*it)->attribute_handle, true,
nullptr, ui_task_runner_);
gatt_services_.add(
primary_service->GetIdentifier(),
std::unique_ptr<BluetoothRemoteGattService>(primary_service));
adapter_->NotifyGattServiceAdded(primary_service);
}
}
adapter_->NotifyGattServicesDiscovered(this);
}
} // namespace device