chromium/device/bluetooth/bluetooth_device_win.cc

// Copyright 2012 The Chromium Authors
// 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 <string>
#include <unordered_map>

#include "base/check_op.h"
#include "base/functional/bind.h"
#include "base/memory/ptr_util.h"
#include "base/notreached.h"
#include "base/task/sequenced_task_runner.h"
#include "device/bluetooth/bluetooth_adapter_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/public/cpp/bluetooth_address.h"
#include "device/bluetooth/public/cpp/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,
    scoped_refptr<base::SequencedTaskRunner> ui_task_runner,
    scoped_refptr<BluetoothSocketThread> socket_thread)
    : BluetoothDevice(adapter),
      ui_task_runner_(std::move(ui_task_runner)),
      socket_thread_(std::move(socket_thread)) {
  Update(device_state);
}

BluetoothDeviceWin::~BluetoothDeviceWin() = default;

uint32_t BluetoothDeviceWin::GetBluetoothClass() const {
  return bluetooth_class_;
}

std::string BluetoothDeviceWin::GetAddress() const {
  return address_;
}

BluetoothDevice::AddressType BluetoothDeviceWin::GetAddressType() const {
  NOTIMPLEMENTED();
  return ADDR_TYPE_UNKNOWN;
}

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/41240161): Implementing GetAppearance()
  // on mac, win, and android platforms for chrome
  NOTIMPLEMENTED();
  return 0;
}

std::optional<std::string> BluetoothDeviceWin::GetName() const {
  return name_;
}

bool BluetoothDeviceWin::IsPaired() const {
  return paired_;
}

bool BluetoothDeviceWin::IsConnected() const {
  return connected_;
}

bool BluetoothDeviceWin::IsGattConnected() const {
  return false;
}

bool BluetoothDeviceWin::IsConnectable() const {
  return false;
}

bool BluetoothDeviceWin::IsConnecting() const {
  return false;
}

BluetoothDevice::UUIDSet BluetoothDeviceWin::GetUUIDs() const {
  return uuids_;
}

std::optional<int8_t> BluetoothDeviceWin::GetInquiryRSSI() const {
  // In windows, we can only get connected devices and connected
  // devices don't have an Inquiry RSSI.
  return std::nullopt;
}

std::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 std::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(ConnectionInfoCallback callback) {
  NOTIMPLEMENTED();
  std::move(callback).Run(ConnectionInfo());
}

void BluetoothDeviceWin::SetConnectionLatency(
    ConnectionLatency connection_latency,
    base::OnceClosure callback,
    ErrorCallback error_callback) {
  NOTIMPLEMENTED();
}

void BluetoothDeviceWin::Connect(PairingDelegate* pairing_delegate,
                                 ConnectCallback 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(base::OnceClosure callback,
                                    ErrorCallback error_callback) {
  NOTIMPLEMENTED();
}

void BluetoothDeviceWin::Forget(base::OnceClosure callback,
                                ErrorCallback error_callback) {
  NOTIMPLEMENTED();
}

void BluetoothDeviceWin::ConnectToService(
    const BluetoothUUID& uuid,
    ConnectToServiceCallback callback,
    ConnectToServiceErrorCallback error_callback) {
  scoped_refptr<BluetoothSocketWin> socket(
      BluetoothSocketWin::CreateBluetoothSocket(
          ui_task_runner_, socket_thread_));
  socket->Connect(this, uuid, base::BindOnce(std::move(callback), socket),
                  std::move(error_callback));
}

void BluetoothDeviceWin::ConnectToServiceInsecurely(
    const BluetoothUUID& uuid,
    ConnectToServiceCallback callback,
    ConnectToServiceErrorCallback error_callback) {
  std::move(error_callback).Run(kApiUnavailable);
}

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<std::string, std::unique_ptr<BluetoothServiceRecordWin>>
      new_service_records;
  for (auto iter = device_state.service_record_states.begin();
       iter != device_state.service_record_states.end(); ++iter) {
    auto service_record = std::make_unique<BluetoothServiceRecordWin>(
        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_, CanonicalizeBluetoothAddress(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(
    std::optional<BluetoothUUID> service_uuid) {
  // Windows will create the Gatt connection as needed.  See:
  // https://docs.microsoft.com/en-us/windows/uwp/devices-sensors/gatt-client#connecting-to-the-device
}

void BluetoothDeviceWin::DisconnectGatt() {
  // On Windows, the adapter cannot force a disconnection.
}

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 = std::make_unique<BluetoothServiceRecordWin>(
        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));
  }
}

}  // namespace device