// 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 #include "base/logging.h" #include "base/memory/ptr_util.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& ui_task_runner, const scoped_refptr& 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 service_keys; for (const auto& gatt_service : gatt_services_) { service_keys.push_back(gatt_service.first); } for (const auto& key : service_keys) { std::unique_ptr service = std::move(gatt_services_[key]); gatt_services_.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 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 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 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 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 (const auto& record : service_record_list_) if (record->uuid() == uuid) return record.get(); return nullptr; } 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 UUIDSet new_services; std::unordered_map> new_service_records; for (auto iter = device_state.service_record_states.begin(); iter != device_state.service_record_states.end(); ++iter) { auto service_record = base::MakeUnique( address_, (*iter)->name, (*iter)->sdp_bytes, (*iter)->gatt_uuid); new_services.insert(service_record->uuid()); new_service_records[service_record->uuid().canonical_value()] = std::move(service_record); } // Check that no new services have been added or removed. if (uuids_ != new_services) { return false; } for (const auto& service_record : service_record_list_) { BluetoothServiceRecordWin* new_service_record = new_service_records[service_record->uuid().canonical_value()].get(); 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 (const auto& record_state : device_state.service_record_states) { auto service_record = base::MakeUnique( device_state.address, record_state->name, record_state->sdp_bytes, record_state->gatt_uuid); uuids_.insert(service_record->uuid()); service_record_list_.push_back(std::move(service_record)); } if (!device_state.is_bluetooth_classic()) UpdateGattServices(device_state.service_record_states); } bool BluetoothDeviceWin::IsGattServiceDiscovered(BluetoothUUID& uuid, uint16_t attribute_handle) { for (const auto& gatt_service : gatt_services_) { uint16_t it_att_handle = static_cast(gatt_service.second.get()) ->GetAttributeHandle(); BluetoothUUID it_uuid = gatt_service.second->GetUUID(); if (attribute_handle == it_att_handle && uuid == it_uuid) { return true; } } return false; } bool BluetoothDeviceWin::DoesGattServiceExist( const std::vector>& service_state, BluetoothRemoteGattService* service) { uint16_t attribute_handle = static_cast(service) ->GetAttributeHandle(); BluetoothUUID uuid = service->GetUUID(); for (const auto& record_state : service_state) { if (attribute_handle == record_state->attribute_handle && uuid == record_state->gatt_uuid) { return true; } } return false; } void BluetoothDeviceWin::UpdateGattServices( const std::vector< std::unique_ptr>& service_state) { // First, remove no longer exist GATT service. { std::vector to_be_removed_services; for (const auto& gatt_service : gatt_services_) { if (!DoesGattServiceExist(service_state, gatt_service.second.get())) { to_be_removed_services.push_back(gatt_service.first); } } for (const auto& service : to_be_removed_services) { std::unique_ptr service_ptr = std::move(gatt_services_[service]); gatt_services_.erase(service); } // Update previously discovered services. for (const auto& gatt_service : gatt_services_) { static_cast(gatt_service.second.get()) ->Update(); } } // Return if no new services have been added. if (gatt_services_.size() == service_state.size()) return; // Add new services. for (const auto& record_state : service_state) { if (!IsGattServiceDiscovered(record_state->gatt_uuid, record_state->attribute_handle)) { BluetoothRemoteGattServiceWin* primary_service = new BluetoothRemoteGattServiceWin( this, record_state->path, record_state->gatt_uuid, record_state->attribute_handle, true, nullptr, ui_task_runner_); gatt_services_[primary_service->GetIdentifier()] = base::WrapUnique(primary_service); adapter_->NotifyGattServiceAdded(primary_service); } } adapter_->NotifyGattServicesDiscovered(this); } } // namespace device