blob: 324ff4103656bfea2c6d8daa7cf0cb6bf09e1b66 [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 <utility>
#include <vector>
#include "base/bind.h"
#include "base/memory/ptr_util.h"
#include "base/strings/utf_string_conversions.h"
#include "device/bluetooth/device.h"
#include "device/bluetooth/public/mojom/gatt_result_type_converter.h"
#include "mojo/public/cpp/bindings/strong_binding.h"
namespace bluetooth {
Device::~Device() {
adapter_->RemoveObserver(this);
}
// static
void Device::Create(scoped_refptr<device::BluetoothAdapter> adapter,
std::unique_ptr<device::BluetoothGattConnection> connection,
mojom::DeviceRequest request) {
auto device_impl =
base::WrapUnique(new Device(adapter, std::move(connection)));
auto* device_ptr = device_impl.get();
device_ptr->binding_ =
mojo::MakeStrongBinding(std::move(device_impl), std::move(request));
}
// static
mojom::DeviceInfoPtr Device::ConstructDeviceInfoStruct(
const device::BluetoothDevice* device) {
mojom::DeviceInfoPtr device_info = mojom::DeviceInfo::New();
device_info->name = device->GetName();
device_info->name_for_display =
base::UTF16ToUTF8(device->GetNameForDisplay());
device_info->address = device->GetAddress();
device_info->is_gatt_connected = device->IsGattConnected();
if (device->GetInquiryRSSI()) {
device_info->rssi = mojom::RSSIWrapper::New();
device_info->rssi->value = device->GetInquiryRSSI().value();
}
return device_info;
}
void Device::DeviceChanged(device::BluetoothAdapter* adapter,
device::BluetoothDevice* device) {
if (device->GetAddress() != GetAddress()) {
return;
}
if (!device->IsGattConnected()) {
binding_->Close();
}
}
void Device::GattServicesDiscovered(device::BluetoothAdapter* adapter,
device::BluetoothDevice* device) {
if (device->GetAddress() != GetAddress()) {
return;
}
std::vector<base::Closure> requests;
requests.swap(pending_services_requests_);
for (const base::Closure& request : requests) {
request.Run();
}
}
void Device::Disconnect() {
binding_->Close();
}
void Device::GetInfo(GetInfoCallback callback) {
device::BluetoothDevice* device = adapter_->GetDevice(GetAddress());
DCHECK(device);
std::move(callback).Run(ConstructDeviceInfoStruct(device));
}
void Device::GetServices(GetServicesCallback callback) {
device::BluetoothDevice* device = adapter_->GetDevice(GetAddress());
DCHECK(device);
if (device->IsGattServicesDiscoveryComplete()) {
GetServicesImpl(std::move(callback));
return;
}
// pending_services_requests_ is owned by Device, so base::Unretained is
// safe.
pending_services_requests_.push_back(base::Bind(&Device::GetServicesImpl,
base::Unretained(this),
base::Passed(&callback)));
}
void Device::GetCharacteristics(const std::string& service_id,
GetCharacteristicsCallback callback) {
device::BluetoothDevice* device = adapter_->GetDevice(GetAddress());
DCHECK(device);
device::BluetoothRemoteGattService* service =
device->GetGattService(service_id);
if (service == nullptr) {
std::move(callback).Run(base::nullopt);
return;
}
std::vector<mojom::CharacteristicInfoPtr> characteristics;
for (const auto* characteristic : service->GetCharacteristics()) {
mojom::CharacteristicInfoPtr characteristic_info =
mojom::CharacteristicInfo::New();
characteristic_info->id = characteristic->GetIdentifier();
characteristic_info->uuid = characteristic->GetUUID();
characteristic_info->properties = characteristic->GetProperties();
characteristics.push_back(std::move(characteristic_info));
}
std::move(callback).Run(std::move(characteristics));
}
void Device::ReadValueForCharacteristic(
const std::string& service_id,
const std::string& characteristic_id,
ReadValueForCharacteristicCallback callback) {
device::BluetoothDevice* device = adapter_->GetDevice(GetAddress());
DCHECK(device);
device::BluetoothRemoteGattService* service =
device->GetGattService(service_id);
if (service == nullptr) {
std::move(callback).Run(mojom::GattResult::SERVICE_NOT_FOUND,
base::nullopt /* value */);
return;
}
device::BluetoothRemoteGattCharacteristic* characteristic =
service->GetCharacteristic(characteristic_id);
if (characteristic == nullptr) {
std::move(callback).Run(mojom::GattResult::CHARACTERISTIC_NOT_FOUND,
base::nullopt /* value */);
return;
}
auto copyable_callback = base::AdaptCallbackForRepeating(std::move(callback));
characteristic->ReadRemoteCharacteristic(
base::Bind(&Device::OnReadRemoteCharacteristic,
weak_ptr_factory_.GetWeakPtr(), copyable_callback),
base::Bind(&Device::OnReadRemoteCharacteristicError,
weak_ptr_factory_.GetWeakPtr(), copyable_callback));
}
void Device::WriteValueForCharacteristic(
const std::string& service_id,
const std::string& characteristic_id,
const std::vector<uint8_t>& value,
WriteValueForCharacteristicCallback callback) {
device::BluetoothDevice* device = adapter_->GetDevice(GetAddress());
DCHECK(device);
device::BluetoothRemoteGattService* service =
device->GetGattService(service_id);
if (service == nullptr) {
std::move(callback).Run(mojom::GattResult::SERVICE_NOT_FOUND);
return;
}
device::BluetoothRemoteGattCharacteristic* characteristic =
service->GetCharacteristic(characteristic_id);
if (characteristic == nullptr) {
std::move(callback).Run(mojom::GattResult::CHARACTERISTIC_NOT_FOUND);
return;
}
auto copyable_callback = base::AdaptCallbackForRepeating(std::move(callback));
characteristic->WriteRemoteCharacteristic(
value,
base::Bind(&Device::OnWriteRemoteCharacteristic,
weak_ptr_factory_.GetWeakPtr(), copyable_callback),
base::Bind(&Device::OnWriteRemoteCharacteristicError,
weak_ptr_factory_.GetWeakPtr(), copyable_callback));
}
void Device::GetDescriptors(const std::string& service_id,
const std::string& characteristic_id,
GetDescriptorsCallback callback) {
device::BluetoothDevice* device = adapter_->GetDevice(GetAddress());
if (!device) {
std::move(callback).Run(base::nullopt);
return;
}
device::BluetoothRemoteGattService* service =
device->GetGattService(service_id);
if (!service) {
std::move(callback).Run(base::nullopt);
return;
}
device::BluetoothRemoteGattCharacteristic* characteristic =
service->GetCharacteristic(characteristic_id);
if (!characteristic) {
std::move(callback).Run(base::nullopt);
return;
}
std::vector<mojom::DescriptorInfoPtr> descriptors;
for (const auto* descriptor : characteristic->GetDescriptors()) {
mojom::DescriptorInfoPtr descriptor_info = mojom::DescriptorInfo::New();
descriptor_info->id = descriptor->GetIdentifier();
descriptor_info->uuid = descriptor->GetUUID();
descriptor_info->last_known_value = descriptor->GetValue();
descriptors.push_back(std::move(descriptor_info));
}
std::move(callback).Run(std::move(descriptors));
}
void Device::ReadValueForDescriptor(const std::string& service_id,
const std::string& characteristic_id,
const std::string& descriptor_id,
ReadValueForDescriptorCallback callback) {
device::BluetoothDevice* device = adapter_->GetDevice(GetAddress());
DCHECK(device);
device::BluetoothRemoteGattService* service =
device->GetGattService(service_id);
if (!service) {
std::move(callback).Run(mojom::GattResult::SERVICE_NOT_FOUND,
base::nullopt /* value */);
return;
}
device::BluetoothRemoteGattCharacteristic* characteristic =
service->GetCharacteristic(characteristic_id);
if (!characteristic) {
std::move(callback).Run(mojom::GattResult::CHARACTERISTIC_NOT_FOUND,
base::nullopt /* value */);
return;
}
device::BluetoothRemoteGattDescriptor* descriptor =
characteristic->GetDescriptor(descriptor_id);
if (!descriptor) {
std::move(callback).Run(mojom::GattResult::DESCRIPTOR_NOT_FOUND,
base::nullopt /* value */);
return;
}
auto copyable_callback = base::AdaptCallbackForRepeating(std::move(callback));
descriptor->ReadRemoteDescriptor(
base::Bind(&Device::OnReadRemoteDescriptor,
weak_ptr_factory_.GetWeakPtr(), copyable_callback),
base::Bind(&Device::OnReadRemoteDescriptorError,
weak_ptr_factory_.GetWeakPtr(), copyable_callback));
}
void Device::WriteValueForDescriptor(const std::string& service_id,
const std::string& characteristic_id,
const std::string& descriptor_id,
const std::vector<uint8_t>& value,
WriteValueForDescriptorCallback callback) {
device::BluetoothDevice* device = adapter_->GetDevice(GetAddress());
DCHECK(device);
device::BluetoothRemoteGattService* service =
device->GetGattService(service_id);
if (!service) {
std::move(callback).Run(mojom::GattResult::SERVICE_NOT_FOUND);
return;
}
device::BluetoothRemoteGattCharacteristic* characteristic =
service->GetCharacteristic(characteristic_id);
if (!characteristic) {
std::move(callback).Run(mojom::GattResult::CHARACTERISTIC_NOT_FOUND);
return;
}
device::BluetoothRemoteGattDescriptor* descriptor =
characteristic->GetDescriptor(descriptor_id);
if (!descriptor) {
std::move(callback).Run(mojom::GattResult::DESCRIPTOR_NOT_FOUND);
return;
}
auto copyable_callback = base::AdaptCallbackForRepeating(std::move(callback));
descriptor->WriteRemoteDescriptor(
value,
base::Bind(&Device::OnWriteRemoteDescriptor,
weak_ptr_factory_.GetWeakPtr(), copyable_callback),
base::Bind(&Device::OnWriteRemoteDescriptorError,
weak_ptr_factory_.GetWeakPtr(), copyable_callback));
}
Device::Device(scoped_refptr<device::BluetoothAdapter> adapter,
std::unique_ptr<device::BluetoothGattConnection> connection)
: adapter_(std::move(adapter)),
connection_(std::move(connection)),
weak_ptr_factory_(this) {
adapter_->AddObserver(this);
}
void Device::GetServicesImpl(GetServicesCallback callback) {
device::BluetoothDevice* device = adapter_->GetDevice(GetAddress());
DCHECK(device);
std::vector<mojom::ServiceInfoPtr> services;
for (const device::BluetoothRemoteGattService* service :
device->GetGattServices()) {
services.push_back(ConstructServiceInfoStruct(*service));
}
std::move(callback).Run(std::move(services));
}
mojom::ServiceInfoPtr Device::ConstructServiceInfoStruct(
const device::BluetoothRemoteGattService& service) {
mojom::ServiceInfoPtr service_info = mojom::ServiceInfo::New();
service_info->id = service.GetIdentifier();
service_info->uuid = service.GetUUID();
service_info->is_primary = service.IsPrimary();
return service_info;
}
void Device::OnReadRemoteCharacteristic(
ReadValueForCharacteristicCallback callback,
const std::vector<uint8_t>& value) {
std::move(callback).Run(mojom::GattResult::SUCCESS, std::move(value));
}
void Device::OnReadRemoteCharacteristicError(
ReadValueForCharacteristicCallback callback,
device::BluetoothGattService::GattErrorCode error_code) {
std::move(callback).Run(mojo::ConvertTo<mojom::GattResult>(error_code),
base::nullopt /* value */);
}
void Device::OnWriteRemoteCharacteristic(
WriteValueForCharacteristicCallback callback) {
std::move(callback).Run(mojom::GattResult::SUCCESS);
}
void Device::OnWriteRemoteCharacteristicError(
WriteValueForCharacteristicCallback callback,
device::BluetoothGattService::GattErrorCode error_code) {
std::move(callback).Run(mojo::ConvertTo<mojom::GattResult>(error_code));
}
void Device::OnReadRemoteDescriptor(ReadValueForDescriptorCallback callback,
const std::vector<uint8_t>& value) {
std::move(callback).Run(mojom::GattResult::SUCCESS, std::move(value));
}
void Device::OnReadRemoteDescriptorError(
ReadValueForDescriptorCallback callback,
device::BluetoothGattService::GattErrorCode error_code) {
std::move(callback).Run(mojo::ConvertTo<mojom::GattResult>(error_code),
base::nullopt /* value */);
}
void Device::OnWriteRemoteDescriptor(WriteValueForDescriptorCallback callback) {
std::move(callback).Run(mojom::GattResult::SUCCESS);
}
void Device::OnWriteRemoteDescriptorError(
WriteValueForDescriptorCallback callback,
device::BluetoothGattService::GattErrorCode error_code) {
std::move(callback).Run(mojo::ConvertTo<mojom::GattResult>(error_code));
}
const std::string& Device::GetAddress() {
return connection_->GetDeviceAddress();
}
} // namespace bluetooth