Chromium Code Reviews| Index: components/arc/bluetooth/arc_bluetooth_bridge.cc |
| diff --git a/components/arc/bluetooth/arc_bluetooth_bridge.cc b/components/arc/bluetooth/arc_bluetooth_bridge.cc |
| index 4acf4b21cd1a565e6beca8949c8836d968a7322f..a98b7cba483de82e1aeb96f8842fc4b4d3433a67 100644 |
| --- a/components/arc/bluetooth/arc_bluetooth_bridge.cc |
| +++ b/components/arc/bluetooth/arc_bluetooth_bridge.cc |
| @@ -21,17 +21,31 @@ |
| #include "components/arc/bluetooth/bluetooth_type_converters.h" |
| #include "device/bluetooth/bluetooth_adapter_factory.h" |
| #include "device/bluetooth/bluetooth_device.h" |
| +#include "device/bluetooth/bluetooth_gatt_connection.h" |
| +#include "device/bluetooth/bluetooth_gatt_notify_session.h" |
| #include "device/bluetooth/bluetooth_remote_gatt_characteristic.h" |
| #include "device/bluetooth/bluetooth_remote_gatt_descriptor.h" |
| #include "device/bluetooth/bluetooth_remote_gatt_service.h" |
| using device::BluetoothAdapter; |
| using device::BluetoothAdapterFactory; |
| +using device::BluetoothAdvertisement; |
| using device::BluetoothDevice; |
| +using device::BluetoothDiscoveryFilter; |
| using device::BluetoothDiscoverySession; |
| +using device::BluetoothGattConnection; |
| +using device::BluetoothGattNotifySession; |
| +using device::BluetoothGattCharacteristic; |
| +using device::BluetoothGattDescriptor; |
| +using device::BluetoothGattService; |
| using device::BluetoothRemoteGattCharacteristic; |
| using device::BluetoothRemoteGattDescriptor; |
| using device::BluetoothRemoteGattService; |
| +using device::BluetoothUUID; |
| + |
| +namespace { |
| +const int kMinBtleVersion = 1; |
| +} // namespace |
| namespace arc { |
| @@ -105,6 +119,19 @@ void ArcBluetoothBridge::DeviceAdded(BluetoothAdapter* adapter, |
| arc_bridge_service()->bluetooth_instance()->OnDeviceFound( |
| std::move(properties)); |
| + |
| + if (arc_bridge_service()->bluetooth_version() < kMinBtleVersion) { |
| + LOG(WARNING) << "Bluetooth instance is too old and does not support BTLE"; |
| + return; |
| + } |
| + |
| + mojom::BluetoothAddressPtr addr = |
| + mojom::BluetoothAddress::From(device->GetAddress()); |
| + int rssi = device->GetInquiryRSSI(); |
| + mojo::Array<mojom::BluetoothAdvertisingDataPtr> adv_data = |
| + GetAdvertisingData(device); |
| + arc_bridge_service()->bluetooth_instance()->OnLEDeviceFound( |
| + std::move(addr), rssi, std::move(adv_data)); |
| } |
| void ArcBluetoothBridge::DeviceChanged(BluetoothAdapter* adapter, |
| @@ -164,7 +191,19 @@ void ArcBluetoothBridge::GattServiceRemoved( |
| void ArcBluetoothBridge::GattServicesDiscovered(BluetoothAdapter* adapter, |
| BluetoothDevice* device) { |
| - // Placeholder for GATT client functionality |
| + if (!HasBluetoothInstance()) |
| + return; |
| + |
| + if (arc_bridge_service()->bluetooth_version() < kMinBtleVersion) { |
| + LOG(WARNING) << "Bluetooth instance is too old and does not support BTLE"; |
| + return; |
| + } |
| + |
| + mojom::BluetoothAddressPtr addr = |
| + mojom::BluetoothAddress::From(device->GetAddress()); |
| + |
| + arc_bridge_service()->bluetooth_instance()->OnSearchComplete( |
| + std::move(addr), mojom::BluetoothGattStatus::GATT_SUCCESS); |
| } |
| void ArcBluetoothBridge::GattDiscoveryCompleteForService( |
| @@ -461,6 +500,540 @@ void ArcBluetoothBridge::GetConnectionState( |
| callback.Run(device->IsConnected()); |
| } |
| +void ArcBluetoothBridge::StartLEScan() { |
| + DCHECK(bluetooth_adapter_); |
| + if (discovery_session_) { |
| + LOG(WARNING) << "Discovery session already running; leaving alone"; |
| + SendCachedDevicesFound(); |
| + return; |
| + } |
| + bluetooth_adapter_->StartDiscoverySessionWithFilter( |
| + base::WrapUnique(new BluetoothDiscoveryFilter( |
| + BluetoothDiscoveryFilter::Transport::TRANSPORT_LE)), |
| + base::Bind(&ArcBluetoothBridge::OnDiscoveryStarted, |
| + weak_factory_.GetWeakPtr()), |
| + base::Bind(&ArcBluetoothBridge::OnDiscoveryError, |
| + weak_factory_.GetWeakPtr())); |
| +} |
| + |
| +void ArcBluetoothBridge::StopLEScan() { |
| + CancelDiscovery(); |
| +} |
| + |
| +void ArcBluetoothBridge::OnGattConnected( |
| + mojom::BluetoothAddressPtr addr, |
| + std::unique_ptr<BluetoothGattConnection> connection) const { |
| + if (!HasBluetoothInstance()) |
| + return; |
| + |
| + if (arc_bridge_service()->bluetooth_version() < kMinBtleVersion) { |
| + LOG(WARNING) << "Bluetooth instance is too old and does not support BTLE"; |
| + return; |
| + } |
| + |
| + DCHECK(addr); |
|
palmer
2016/06/14 23:08:25
Nit/Bikeshed: I'd rather use complete words, e.g.
puthik_chromium
2016/06/15 18:06:33
The |addr| name is used in Android side API. So I
|
| + |
| + arc_bridge_service()->bluetooth_instance()->OnLEConnectionStateChange( |
| + std::move(addr), true); |
| +} |
| + |
| +void ArcBluetoothBridge::OnGattConnectError( |
|
palmer
2016/06/14 23:08:25
The only difference between this function and |OnG
puthik_chromium
2016/06/15 18:06:34
Done.
|
| + mojom::BluetoothAddressPtr addr, |
| + BluetoothDevice::ConnectErrorCode error_code) const { |
| + if (!HasBluetoothInstance()) |
| + return; |
| + |
| + if (arc_bridge_service()->bluetooth_version() < kMinBtleVersion) { |
| + LOG(WARNING) << "Bluetooth instance is too old and does not support BTLE"; |
| + return; |
| + } |
| + |
| + DCHECK(addr); |
| + |
| + arc_bridge_service()->bluetooth_instance()->OnLEConnectionStateChange( |
| + std::move(addr), false); |
| +} |
| + |
| +void ArcBluetoothBridge::OnGattDisconnected( |
|
palmer
2016/06/14 23:08:25
This function is identical to |OnGattConnectError|
puthik_chromium
2016/06/15 18:06:33
Done.
|
| + mojom::BluetoothAddressPtr addr) const { |
| + if (!HasBluetoothInstance()) |
| + return; |
| + |
| + if (arc_bridge_service()->bluetooth_version() < kMinBtleVersion) { |
| + LOG(WARNING) << "Bluetooth instance is too old and does not support BTLE"; |
| + return; |
| + } |
| + |
| + DCHECK(addr); |
| + |
| + arc_bridge_service()->bluetooth_instance()->OnLEConnectionStateChange( |
| + std::move(addr), false); |
| +} |
| + |
| +void ArcBluetoothBridge::ConnectLEDevice( |
| + mojom::BluetoothAddressPtr remote_addr) { |
| + if (!HasBluetoothInstance()) |
| + return; |
| + |
| + BluetoothDevice* device = |
| + bluetooth_adapter_->GetDevice(remote_addr->To<std::string>()); |
| + DCHECK(device); |
| + |
| + if (device->IsConnected()) { |
| + arc_bridge_service()->bluetooth_instance()->OnLEConnectionStateChange( |
| + std::move(remote_addr), true); |
| + return; |
| + } |
| + |
| + // Also pass disconnect callback in error case |
| + // since it would be disconnected anyway. |
| + mojom::BluetoothAddressPtr remote_addr_clone = remote_addr.Clone(); |
| + device->CreateGattConnection( |
| + base::Bind(&ArcBluetoothBridge::OnGattConnected, |
| + weak_factory_.GetWeakPtr(), base::Passed(&remote_addr)), |
| + base::Bind(&ArcBluetoothBridge::OnGattConnectError, |
| + weak_factory_.GetWeakPtr(), base::Passed(&remote_addr_clone))); |
| +} |
| + |
| +void ArcBluetoothBridge::DisconnectLEDevice( |
| + mojom::BluetoothAddressPtr remote_addr) { |
| + if (!HasBluetoothInstance()) |
| + return; |
| + |
| + BluetoothDevice* device = |
| + bluetooth_adapter_->GetDevice(remote_addr->To<std::string>()); |
| + DCHECK(device); |
| + |
| + if (!device->IsConnected()) { |
| + arc_bridge_service()->bluetooth_instance()->OnLEConnectionStateChange( |
| + std::move(remote_addr), false); |
| + return; |
| + } |
| + |
| + mojom::BluetoothAddressPtr remote_addr_clone = remote_addr.Clone(); |
| + device->Disconnect( |
| + base::Bind(&ArcBluetoothBridge::OnGattDisconnected, |
| + weak_factory_.GetWeakPtr(), base::Passed(&remote_addr)), |
| + base::Bind(&ArcBluetoothBridge::OnGattDisconnected, |
| + weak_factory_.GetWeakPtr(), base::Passed(&remote_addr_clone))); |
| +} |
| + |
| +void ArcBluetoothBridge::SearchService(mojom::BluetoothAddressPtr remote_addr) { |
| + if (!HasBluetoothInstance()) |
|
palmer
2016/06/14 23:08:25
Again,
622 if (!HasBluetoothInstance())
623
puthik_chromium
2016/06/15 18:06:33
I don't agree with this. The code has very differe
rkc
2016/06/15 20:40:00
I agree with Opal. Additionally this code also ser
|
| + return; |
| + |
| + BluetoothDevice* device = |
| + bluetooth_adapter_->GetDevice(remote_addr->To<std::string>()); |
| + DCHECK(device); |
| + |
| + // Call the callback if discovery is completed |
| + if (device->IsGattServicesDiscoveryComplete()) { |
| + arc_bridge_service()->bluetooth_instance()->OnSearchComplete( |
| + std::move(remote_addr), mojom::BluetoothGattStatus::GATT_SUCCESS); |
| + return; |
| + } |
| + |
| + // Discard result. Will call the callback when discovery is completed. |
| + device->GetGattServices(); |
| +} |
| + |
| +void ArcBluetoothBridge::OnStartLEListenDone( |
| + const StartLEListenCallback& callback, |
| + scoped_refptr<BluetoothAdvertisement> adv) { |
|
palmer
2016/06/14 23:08:26
Same nit/bikeshed as before: Disprefer terse names
puthik_chromium
2016/06/15 18:06:34
Done.
|
| + advertisment_ = adv; |
| + callback.Run(mojom::BluetoothGattStatus::GATT_SUCCESS); |
| +} |
| + |
| +void ArcBluetoothBridge::OnStartLEListenError( |
| + const StartLEListenCallback& callback, |
| + BluetoothAdvertisement::ErrorCode error_code) { |
| + advertisment_ = nullptr; |
| + callback.Run(mojom::BluetoothGattStatus::GATT_FAILURE); |
| +} |
| + |
| +void ArcBluetoothBridge::StartLEListen(const StartLEListenCallback& callback) { |
| + std::unique_ptr<BluetoothAdvertisement::Data> adv_data = |
| + base::WrapUnique(new BluetoothAdvertisement::Data( |
| + BluetoothAdvertisement::ADVERTISEMENT_TYPE_BROADCAST)); |
| + bluetooth_adapter_->RegisterAdvertisement( |
| + std::move(adv_data), base::Bind(&ArcBluetoothBridge::OnStartLEListenDone, |
| + weak_factory_.GetWeakPtr(), callback), |
| + base::Bind(&ArcBluetoothBridge::OnStartLEListenError, |
| + weak_factory_.GetWeakPtr(), callback)); |
| +} |
| + |
| +void ArcBluetoothBridge::OnStopLEListenDone( |
| + const StopLEListenCallback& callback) { |
| + advertisment_ = nullptr; |
| + callback.Run(mojom::BluetoothGattStatus::GATT_SUCCESS); |
| +} |
| + |
| +void ArcBluetoothBridge::OnStopLEListenError( |
| + const StopLEListenCallback& callback, |
| + BluetoothAdvertisement::ErrorCode error_code) { |
| + advertisment_ = nullptr; |
| + callback.Run(mojom::BluetoothGattStatus::GATT_FAILURE); |
| +} |
| + |
| +void ArcBluetoothBridge::StopLEListen(const StopLEListenCallback& callback) { |
| + if (!advertisment_) { |
| + OnStopLEListenError( |
| + callback, |
| + BluetoothAdvertisement::ErrorCode::ERROR_ADVERTISEMENT_DOES_NOT_EXIST); |
| + return; |
| + } |
| + advertisment_->Unregister(base::Bind(&ArcBluetoothBridge::OnStopLEListenDone, |
| + weak_factory_.GetWeakPtr(), callback), |
| + base::Bind(&ArcBluetoothBridge::OnStopLEListenError, |
| + weak_factory_.GetWeakPtr(), callback)); |
| +} |
| + |
| +void ArcBluetoothBridge::GetGattDB(mojom::BluetoothAddressPtr remote_addr) { |
| + if (!HasBluetoothInstance()) |
| + return; |
| + |
| + BluetoothDevice* device = |
| + bluetooth_adapter_->GetDevice(remote_addr->To<std::string>()); |
| + mojo::Array<mojom::BluetoothGattDBElementPtr> db; |
| + for (auto service : device->GetGattServices()) { |
| + mojom::BluetoothGattDBElementPtr service_element = |
| + mojom::BluetoothGattDBElement::New(); |
| + |
| + // Example: /org/bluez/hci0/dev_E0_CF_65_8C_86_1A/service001a |
| + std::string id_str = service->GetIdentifier(); |
| + |
| + // Convert last digit of service id to int in base 16 |
| + int id = std::stoi(id_str.substr(id_str.size() - 4), nullptr, 16); |
| + |
| + service_element->id = id; |
| + service_element->uuid = mojom::BluetoothUUID::From(service->GetUUID()); |
| + if (service->IsPrimary()) { |
| + service_element->type = |
| + mojom::BluetoothGattDBAttributeType::BTGATT_DB_PRIMARY_SERVICE; |
| + } else { |
| + service_element->type = |
| + mojom::BluetoothGattDBAttributeType::BTGATT_DB_SECONDARY_SERVICE; |
| + } |
| + service_element->attribute_handle = id; |
| + const auto& characteristics = service->GetCharacteristics(); |
| + if (characteristics.size() > 0) { |
| + std::string first_id_str = characteristics.front()->GetIdentifier(); |
| + int first_id = |
| + std::stoi(first_id_str.substr(first_id_str.size() - 4), nullptr, 16); |
| + |
| + const auto& descriptors = characteristics.back()->GetDescriptors(); |
| + std::string last_id_str; |
|
palmer
2016/06/14 23:08:25
Nit: You could reduce these lines:
int last_i
puthik_chromium
2016/06/15 18:06:34
Done.
|
| + if (descriptors.size() > 0) { |
| + last_id_str = descriptors.back()->GetIdentifier(); |
| + } else { |
| + last_id_str = characteristics.back()->GetIdentifier(); |
| + } |
| + int last_id = |
| + std::stoi(last_id_str.substr(last_id_str.size() - 4), nullptr, 16); |
|
palmer
2016/06/14 23:08:25
This is the 3rd instance of this not-quite-obvious
puthik_chromium
2016/06/15 18:06:34
Done.
|
| + service_element->start_handle = first_id; |
| + service_element->end_handle = last_id; |
| + } |
| + db.push_back(std::move(service_element)); |
| + |
| + for (auto characteristic : characteristics) { |
|
palmer
2016/06/14 23:08:25
Lines 738 – 766 are dense and repetetive. I sugges
puthik_chromium
2016/06/15 18:06:34
I added a helper function to allocate the element
|
| + mojom::BluetoothGattDBElementPtr characteristic_element = |
| + mojom::BluetoothGattDBElement::New(); |
| + std::string id_str = characteristic->GetIdentifier(); |
| + int id = std::stoi(id_str.substr(id_str.size() - 4), nullptr, 16); |
| + characteristic_element->id = id; |
| + characteristic_element->uuid = |
| + mojom::BluetoothUUID::From(characteristic->GetUUID()); |
| + characteristic_element->type = |
| + mojom::BluetoothGattDBAttributeType::BTGATT_DB_CHARACTERISTIC; |
| + characteristic_element->attribute_handle = id; |
| + characteristic_element->properties = characteristic->GetProperties(); |
| + db.push_back(std::move(characteristic_element)); |
| + |
| + for (auto descriptor : characteristic->GetDescriptors()) { |
| + mojom::BluetoothGattDBElementPtr descriptor_element = |
| + mojom::BluetoothGattDBElement::New(); |
| + std::string id_str = descriptor->GetIdentifier(); |
| + int id = std::stoi(id_str.substr(id_str.size() - 4), nullptr, 16); |
| + descriptor_element->id = id; |
| + descriptor_element->uuid = |
| + mojom::BluetoothUUID::From(descriptor->GetUUID()); |
| + descriptor_element->type = |
| + mojom::BluetoothGattDBAttributeType::BTGATT_DB_DESCRIPTOR; |
| + descriptor_element->attribute_handle = id; |
| + db.push_back(std::move(descriptor_element)); |
| + } |
| + } |
| + } |
| + |
| + arc_bridge_service()->bluetooth_instance()->OnGetGattDB( |
| + std::move(remote_addr), std::move(db)); |
| +} |
| + |
| +BluetoothRemoteGattCharacteristic* ArcBluetoothBridge::FindGattCharacteristic( |
| + mojom::BluetoothAddressPtr remote_addr, |
| + mojom::BluetoothGattServiceIDPtr service_id, |
| + mojom::BluetoothGattIDPtr char_id) const { |
| + DCHECK(remote_addr); |
| + DCHECK(service_id); |
| + DCHECK(char_id); |
| + |
| + BluetoothDevice* device = |
| + bluetooth_adapter_->GetDevice(remote_addr->To<std::string>()); |
| + if (!device) |
| + return nullptr; |
| + |
| + BluetoothUUID serv_uuid = service_id->id->uuid.To<BluetoothUUID>(); |
| + const auto& services = device->GetGattServices(); |
| + auto service_it = std::find_if( |
| + services.begin(), services.end(), |
| + [&](BluetoothRemoteGattService* s) { return s->GetUUID() == serv_uuid; }); |
| + if (service_it == services.end()) |
| + return nullptr; |
| + |
| + BluetoothUUID char_uuid = char_id->uuid.To<BluetoothUUID>(); |
| + const auto& characteristics = (*service_it)->GetCharacteristics(); |
| + auto characteristic_it = |
| + std::find_if(characteristics.begin(), characteristics.end(), |
| + [&](BluetoothRemoteGattCharacteristic* c) { |
| + return c->GetUUID() == char_uuid; |
| + }); |
| + if (characteristic_it == characteristics.end()) |
| + return nullptr; |
| + return *characteristic_it; |
| +} |
| + |
| +BluetoothRemoteGattDescriptor* ArcBluetoothBridge::FindGattDescriptor( |
| + mojom::BluetoothAddressPtr remote_addr, |
| + mojom::BluetoothGattServiceIDPtr service_id, |
| + mojom::BluetoothGattIDPtr char_id, |
| + mojom::BluetoothGattIDPtr desc_id) const { |
| + BluetoothRemoteGattCharacteristic* characteristic = FindGattCharacteristic( |
| + std::move(remote_addr), std::move(service_id), std::move(char_id)); |
| + |
| + if (!characteristic) |
| + return nullptr; |
| + |
| + BluetoothUUID desc_uuid = desc_id->uuid.To<BluetoothUUID>(); |
| + const auto& descriptors = characteristic->GetDescriptors(); |
| + auto descriptor_it = std::find_if(descriptors.begin(), descriptors.end(), |
| + [&](BluetoothRemoteGattDescriptor* d) { |
| + return d->GetUUID() == desc_uuid; |
| + }); |
| + if (descriptor_it == descriptors.end()) |
| + return nullptr; |
| + return *descriptor_it; |
| +} |
| + |
| +// Same callback for both ReadGattCharacteristic and ReadGattDescriptor |
| +void ArcBluetoothBridge::OnGattReadDone( |
| + const GattReadCallback& callback, |
| + const std::vector<uint8_t>& result) const { |
| + mojom::BluetoothGattValuePtr gattValue = mojom::BluetoothGattValue::New(); |
| + gattValue->status = mojom::BluetoothGattStatus::GATT_SUCCESS; |
| + gattValue->value = mojo::Array<uint8_t>::From(result); |
| + callback.Run(std::move(gattValue)); |
| +} |
| + |
| +void ArcBluetoothBridge::OnGattReadError( |
| + const GattReadCallback& callback, |
| + BluetoothGattService::GattErrorCode error_code) const { |
| + mojom::BluetoothGattValuePtr gattValue = mojom::BluetoothGattValue::New(); |
| + gattValue->status = mojo::ConvertTo<mojom::BluetoothGattStatus>(error_code); |
| + gattValue->value = nullptr; |
| + |
| + callback.Run(std::move(gattValue)); |
| +} |
| + |
| +// same callback for both WriteGattCharacteristic and WriteGattDescriptor |
| +void ArcBluetoothBridge::OnGattWriteDone( |
| + const GattWriteCallback& callback) const { |
| + callback.Run(mojom::BluetoothGattStatus::GATT_SUCCESS); |
| +} |
| + |
| +void ArcBluetoothBridge::OnGattWriteError( |
| + const GattWriteCallback& callback, |
| + BluetoothGattService::GattErrorCode error_code) const { |
| + callback.Run(mojo::ConvertTo<mojom::BluetoothGattStatus>(error_code)); |
| +} |
| + |
| +void ArcBluetoothBridge::ReadGattCharacteristic( |
| + mojom::BluetoothAddressPtr remote_addr, |
| + mojom::BluetoothGattServiceIDPtr service_id, |
| + mojom::BluetoothGattIDPtr char_id, |
| + const ReadGattCharacteristicCallback& callback) { |
| + BluetoothRemoteGattCharacteristic* characteristic = FindGattCharacteristic( |
| + std::move(remote_addr), std::move(service_id), std::move(char_id)); |
| + |
| + DCHECK(characteristic); |
| + |
| + DCHECK(characteristic->GetPermissions() & |
| + (BluetoothGattCharacteristic::Permission::PERMISSION_READ | |
| + BluetoothGattCharacteristic::Permission::PERMISSION_READ_ENCRYPTED | |
| + BluetoothGattCharacteristic::Permission:: |
| + PERMISSION_READ_ENCRYPTED_AUTHENTICATED)); |
| + |
| + characteristic->ReadRemoteCharacteristic( |
| + base::Bind(&ArcBluetoothBridge::OnGattReadDone, |
| + weak_factory_.GetWeakPtr(), callback), |
| + base::Bind(&ArcBluetoothBridge::OnGattReadError, |
| + weak_factory_.GetWeakPtr(), callback)); |
| +} |
| + |
| +void ArcBluetoothBridge::WriteGattCharacteristic( |
| + mojom::BluetoothAddressPtr remote_addr, |
| + mojom::BluetoothGattServiceIDPtr service_id, |
| + mojom::BluetoothGattIDPtr char_id, |
| + mojom::BluetoothGattValuePtr value, |
| + const WriteGattCharacteristicCallback& callback) { |
| + BluetoothRemoteGattCharacteristic* characteristic = FindGattCharacteristic( |
| + std::move(remote_addr), std::move(service_id), std::move(char_id)); |
| + |
| + DCHECK(characteristic); |
| + |
| + DCHECK(characteristic->GetPermissions() & |
| + (BluetoothGattCharacteristic::Permission::PERMISSION_WRITE | |
| + BluetoothGattCharacteristic::Permission::PERMISSION_WRITE_ENCRYPTED | |
| + BluetoothGattCharacteristic::Permission:: |
| + PERMISSION_WRITE_ENCRYPTED_AUTHENTICATED)); |
| + |
| + characteristic->WriteRemoteCharacteristic( |
| + value->value.To<std::vector<uint8_t>>(), |
| + base::Bind(&ArcBluetoothBridge::OnGattWriteDone, |
| + weak_factory_.GetWeakPtr(), callback), |
| + base::Bind(&ArcBluetoothBridge::OnGattWriteError, |
| + weak_factory_.GetWeakPtr(), callback)); |
| +} |
| + |
| +void ArcBluetoothBridge::ReadGattDescriptor( |
| + mojom::BluetoothAddressPtr remote_addr, |
| + mojom::BluetoothGattServiceIDPtr service_id, |
| + mojom::BluetoothGattIDPtr char_id, |
| + mojom::BluetoothGattIDPtr desc_id, |
| + const ReadGattDescriptorCallback& callback) { |
| + BluetoothRemoteGattDescriptor* descriptor = |
| + FindGattDescriptor(std::move(remote_addr), std::move(service_id), |
| + std::move(char_id), std::move(desc_id)); |
| + DCHECK(descriptor); |
| + |
| + DCHECK(descriptor->GetPermissions() & |
| + (BluetoothGattCharacteristic::Permission::PERMISSION_READ | |
| + BluetoothGattCharacteristic::Permission::PERMISSION_READ_ENCRYPTED | |
| + BluetoothGattCharacteristic::Permission:: |
| + PERMISSION_READ_ENCRYPTED_AUTHENTICATED)); |
| + |
| + descriptor->ReadRemoteDescriptor( |
| + base::Bind(&ArcBluetoothBridge::OnGattReadDone, |
| + weak_factory_.GetWeakPtr(), callback), |
| + base::Bind(&ArcBluetoothBridge::OnGattReadError, |
| + weak_factory_.GetWeakPtr(), callback)); |
| +} |
| + |
| +void ArcBluetoothBridge::WriteGattDescriptor( |
| + mojom::BluetoothAddressPtr remote_addr, |
| + mojom::BluetoothGattServiceIDPtr service_id, |
| + mojom::BluetoothGattIDPtr char_id, |
| + mojom::BluetoothGattIDPtr desc_id, |
| + mojom::BluetoothGattValuePtr value, |
| + const WriteGattDescriptorCallback& callback) { |
| + BluetoothRemoteGattDescriptor* descriptor = |
| + FindGattDescriptor(std::move(remote_addr), std::move(service_id), |
| + std::move(char_id), std::move(desc_id)); |
| + DCHECK(descriptor); |
| + |
| + DCHECK(descriptor->GetPermissions() & |
| + (BluetoothGattCharacteristic::Permission::PERMISSION_WRITE | |
| + BluetoothGattCharacteristic::Permission::PERMISSION_WRITE_ENCRYPTED | |
| + BluetoothGattCharacteristic::Permission:: |
| + PERMISSION_WRITE_ENCRYPTED_AUTHENTICATED)); |
| + |
| + descriptor->WriteRemoteDescriptor( |
| + value->value.To<std::vector<uint8_t>>(), |
| + base::Bind(&ArcBluetoothBridge::OnGattWriteDone, |
| + weak_factory_.GetWeakPtr(), callback), |
| + base::Bind(&ArcBluetoothBridge::OnGattWriteError, |
| + weak_factory_.GetWeakPtr(), callback)); |
| +} |
| + |
| +void ArcBluetoothBridge::OnGattNotifyStartDone( |
| + const RegisterForGattNotificationCallback& callback, |
| + const std::string char_string_id, |
| + std::unique_ptr<BluetoothGattNotifySession> notify_session) { |
| + notification_session_[char_string_id] = std::move(notify_session); |
| + callback.Run(mojom::BluetoothGattStatus::GATT_SUCCESS); |
| +} |
| + |
| +void ArcBluetoothBridge::OnGattNotifyStartError( |
| + const RegisterForGattNotificationCallback& callback, |
| + BluetoothGattService::GattErrorCode error_code) const { |
| + callback.Run(mojo::ConvertTo<mojom::BluetoothGattStatus>(error_code)); |
| +} |
| + |
| +void ArcBluetoothBridge::OnGattNotifyStopDone( |
| + const DeregisterForGattNotificationCallback& callback) const { |
| + callback.Run(mojom::BluetoothGattStatus::GATT_SUCCESS); |
| +} |
| + |
| +void ArcBluetoothBridge::RegisterForGattNotification( |
| + mojom::BluetoothAddressPtr remote_addr, |
| + mojom::BluetoothGattServiceIDPtr service_id, |
| + mojom::BluetoothGattIDPtr char_id, |
| + const RegisterForGattNotificationCallback& callback) { |
| + BluetoothRemoteGattCharacteristic* characteristic = FindGattCharacteristic( |
| + std::move(remote_addr), std::move(service_id), std::move(char_id)); |
| + |
| + if (!characteristic) { |
| + LOG(WARNING) << __func__ << " Characteristic is not existed."; |
| + return; |
| + } |
| + |
| + if (characteristic->IsNotifying()) { |
| + callback.Run(mojom::BluetoothGattStatus::GATT_SUCCESS); |
| + return; |
| + } |
| + |
| + characteristic->StartNotifySession( |
| + base::Bind(&ArcBluetoothBridge::OnGattNotifyStartDone, |
| + weak_factory_.GetWeakPtr(), callback, |
| + characteristic->GetIdentifier()), |
| + base::Bind(&ArcBluetoothBridge::OnGattNotifyStartError, |
| + weak_factory_.GetWeakPtr(), callback)); |
| +} |
| + |
| +void ArcBluetoothBridge::DeregisterForGattNotification( |
| + mojom::BluetoothAddressPtr remote_addr, |
| + mojom::BluetoothGattServiceIDPtr service_id, |
| + mojom::BluetoothGattIDPtr char_id, |
| + const DeregisterForGattNotificationCallback& callback) { |
| + BluetoothRemoteGattCharacteristic* characteristic = FindGattCharacteristic( |
| + std::move(remote_addr), std::move(service_id), std::move(char_id)); |
| + |
| + if (!characteristic) { |
| + LOG(WARNING) << __func__ << " Characteristic is not existed."; |
| + return; |
| + } |
| + |
| + if (!characteristic->IsNotifying()) { |
| + callback.Run(mojom::BluetoothGattStatus::GATT_SUCCESS); |
| + return; |
| + } |
| + |
| + std::string char_id_str = characteristic->GetIdentifier(); |
| + std::unique_ptr<BluetoothGattNotifySession> notify = |
| + std::move(notification_session_[char_id_str]); |
| + notification_session_.erase(char_id_str); |
| + notify->Stop(base::Bind(&ArcBluetoothBridge::OnGattNotifyStopDone, |
| + weak_factory_.GetWeakPtr(), callback)); |
| +} |
| + |
| +void ArcBluetoothBridge::ReadRemoteRssi( |
| + mojom::BluetoothAddressPtr remote_addr, |
| + const ReadRemoteRssiCallback& callback) { |
| + BluetoothDevice* device = |
| + bluetooth_adapter_->GetDevice(remote_addr->To<std::string>()); |
| + int rssi = device->GetInquiryRSSI(); |
| + callback.Run(rssi); |
| +} |
| + |
| void ArcBluetoothBridge::OnDiscoveryError() { |
| LOG(WARNING) << "failed to change discovery state"; |
| } |
| @@ -543,12 +1116,12 @@ ArcBluetoothBridge::GetDeviceProperties(mojom::BluetoothPropertyType type, |
| if (type == mojom::BluetoothPropertyType::ALL || |
| type == mojom::BluetoothPropertyType::UUIDS) { |
| mojom::BluetoothPropertyPtr btp = mojom::BluetoothProperty::New(); |
| - std::vector<device::BluetoothUUID> uuids = device->GetUUIDs(); |
| + std::vector<BluetoothUUID> uuids = device->GetUUIDs(); |
| mojo::Array<mojom::BluetoothUUIDPtr> uuid_results = |
| mojo::Array<mojom::BluetoothUUIDPtr>::New(0); |
| - for (size_t i = 0; i < uuids.size(); i++) { |
| - uuid_results.push_back(mojom::BluetoothUUID::From(uuids[i])); |
| + for (auto& uuid : uuids) { |
| + uuid_results.push_back(mojom::BluetoothUUID::From(uuid)); |
| } |
| btp->set_uuids(std::move(uuid_results)); |
| @@ -642,12 +1215,12 @@ ArcBluetoothBridge::GetAdapterProperties( |
| mojo::Array<mojom::BluetoothAddressPtr> bonded_devices = |
| mojo::Array<mojom::BluetoothAddressPtr>::New(0); |
| - for (size_t i = 0; i < devices.size(); i++) { |
| - if (!devices[i]->IsPaired()) |
| + for (auto device : devices) { |
| + if (device->IsPaired()) |
| continue; |
| mojom::BluetoothAddressPtr addr = |
| - mojom::BluetoothAddress::From(devices[i]->GetAddress()); |
| + mojom::BluetoothAddress::From(device->GetAddress()); |
| bonded_devices.push_back(std::move(addr)); |
| } |
| @@ -664,21 +1237,82 @@ ArcBluetoothBridge::GetAdapterProperties( |
| return properties; |
| } |
| +// Android support 5 types of Advertising Data. |
| +// However Chrome didn't expose AdvertiseFlag and ManufacturerData. |
| +// So we will only expose local_name, service_uuids and service_data. |
| +// TODO(crbug.com/618442) Make Chrome expose missing data. |
| +mojo::Array<mojom::BluetoothAdvertisingDataPtr> |
| +ArcBluetoothBridge::GetAdvertisingData(BluetoothDevice* device) const { |
| + mojo::Array<mojom::BluetoothAdvertisingDataPtr> advertising_data; |
| + |
| + // LocalName |
| + mojom::BluetoothAdvertisingDataPtr local_name = |
| + mojom::BluetoothAdvertisingData::New(); |
| + local_name->set_local_name(base::UTF16ToUTF8(device->GetNameForDisplay())); |
| + advertising_data.push_back(std::move(local_name)); |
| + |
| + // ServiceUuid |
| + BluetoothDevice::UUIDList uuid_list = device->GetServiceDataUUIDs(); |
| + if (uuid_list.size() > 0) { |
| + mojom::BluetoothAdvertisingDataPtr service_uuids = |
| + mojom::BluetoothAdvertisingData::New(); |
| + service_uuids->set_service_uuids( |
| + mojo::Array<mojom::BluetoothUUIDPtr>::From(uuid_list)); |
| + advertising_data.push_back(std::move(service_uuids)); |
| + } |
| + |
| + // Service data |
| + for (auto& uuid : uuid_list) { |
| + base::BinaryValue* data = device->GetServiceData(uuid); |
| + if (data->GetSize() == 0) |
| + continue; |
| + std::string data_str; |
| + if (!data->GetAsString(&data_str)) |
| + continue; |
| + |
| + mojom::BluetoothAdvertisingDataPtr service_data_element = |
| + mojom::BluetoothAdvertisingData::New(); |
| + mojom::BluetoothServiceDataPtr service_data = |
| + mojom::BluetoothServiceData::New(); |
| + |
| + std::string uuid_str = uuid.canonical_value(); |
| + // Convert xxxxyyyy-xxxx-xxxx-xxxx-xxxxxxxxxxxx to int16 yyyy |
| + service_data->uuid_16bit = std::stoi(uuid_str.substr(4, 4), nullptr, 16); |
| + for (auto& c : data_str) { |
| + service_data->data.push_back(c); |
| + } |
| + service_data_element->set_service_data(std::move(service_data)); |
| + advertising_data.push_back(std::move(service_data_element)); |
| + } |
| + |
| + return advertising_data; |
| +} |
| + |
| void ArcBluetoothBridge::SendCachedDevicesFound() const { |
| // Send devices that have already been discovered, but aren't connected. |
| if (!HasBluetoothInstance()) |
| return; |
| BluetoothAdapter::DeviceList devices = bluetooth_adapter_->GetDevices(); |
| - for (size_t i = 0; i < devices.size(); i++) { |
| - if (devices[i]->IsPaired()) |
| + for (auto device : devices) { |
| + if (device->IsPaired()) |
| continue; |
| mojo::Array<mojom::BluetoothPropertyPtr> properties = |
| - GetDeviceProperties(mojom::BluetoothPropertyType::ALL, devices[i]); |
| + GetDeviceProperties(mojom::BluetoothPropertyType::ALL, device); |
| arc_bridge_service()->bluetooth_instance()->OnDeviceFound( |
| std::move(properties)); |
| + |
| + if (arc_bridge_service()->bluetooth_version() >= kMinBtleVersion) { |
| + mojom::BluetoothAddressPtr addr = |
| + mojom::BluetoothAddress::From(device->GetAddress()); |
| + int rssi = device->GetInquiryRSSI(); |
| + mojo::Array<mojom::BluetoothAdvertisingDataPtr> adv_data = |
| + GetAdvertisingData(device); |
| + arc_bridge_service()->bluetooth_instance()->OnLEDeviceFound( |
| + std::move(addr), rssi, std::move(adv_data)); |
| + } |
| } |
| } |
| @@ -693,9 +1327,11 @@ bool ArcBluetoothBridge::HasBluetoothInstance() const { |
| void ArcBluetoothBridge::SendCachedPairedDevices() const { |
| DCHECK(bluetooth_adapter_); |
| + if (!HasBluetoothInstance()) |
| + return; |
| BluetoothAdapter::DeviceList devices = bluetooth_adapter_->GetDevices(); |
| - for (BluetoothDevice* device : devices) { |
| + for (auto device : devices) { |
| if (!device->IsPaired()) |
| continue; |
| @@ -708,6 +1344,14 @@ void ArcBluetoothBridge::SendCachedPairedDevices() const { |
| mojom::BluetoothAddressPtr addr = |
| mojom::BluetoothAddress::From(device->GetAddress()); |
| + if (arc_bridge_service()->bluetooth_version() >= kMinBtleVersion) { |
| + int rssi = device->GetInquiryRSSI(); |
| + mojo::Array<mojom::BluetoothAdvertisingDataPtr> adv_data = |
| + GetAdvertisingData(device); |
| + arc_bridge_service()->bluetooth_instance()->OnLEDeviceFound( |
| + addr->Clone(), rssi, std::move(adv_data)); |
| + } |
| + |
| // OnBondStateChanged must be called with mojom::BluetoothBondState::BONDING |
| // to |
| // make sure the bond state machine on Android is ready to take the |