| // 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 |