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 c42b471d2c27956d82fa84e7210665d85079541f..13ff088ab7040dada7a4be0e377ff1e8039f0eab 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,507 @@ 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::OnGattConnectStateChanged( |
| + mojom::BluetoothAddressPtr addr, |
| + bool connected) 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), connected); |
| +} |
| + |
| +void ArcBluetoothBridge::OnGattConnected( |
| + mojom::BluetoothAddressPtr addr, |
| + std::unique_ptr<BluetoothGattConnection> connection) const { |
| + OnGattConnectStateChanged(std::move(addr), true); |
| +} |
| + |
| +void ArcBluetoothBridge::OnGattConnectError( |
| + mojom::BluetoothAddressPtr addr, |
| + BluetoothDevice::ConnectErrorCode error_code) const { |
| + OnGattConnectStateChanged(std::move(addr), false); |
| +} |
| + |
| +void ArcBluetoothBridge::OnGattDisconnected( |
| + mojom::BluetoothAddressPtr addr) const { |
| + OnGattConnectStateChanged(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()) |
| + 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> advertisement) { |
| + advertisment_ = advertisement; |
| + 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)); |
| +} |
| + |
| +// Example of identifier: /org/bluez/hci0/dev_E0_CF_65_8C_86_1A/service001a |
| +// We want to convert last digit of the identifier to int in base 16 |
| +int ArcBluetoothBridge::ConvertGattIdentifierToId( |
| + const std::string identifier) const { |
| + return std::stoi(identifier.substr(identifier.size() - 4), nullptr, 16); |
| +} |
| + |
| +// Create GattDBElement and fill in common data for |
| +// Gatt Service/Characteristic/Descriptor. |
| +template <class T> |
| +mojom::BluetoothGattDBElementPtr ArcBluetoothBridge::CreateGattDBElement( |
| + const mojom::BluetoothGattDBAttributeType type, |
| + const T* gattObject) const { |
| + mojom::BluetoothGattDBElementPtr element = |
| + mojom::BluetoothGattDBElement::New(); |
| + element->type = type; |
| + element->uuid = mojom::BluetoothUUID::From(gattObject->GetUUID()); |
| + element->id = element->attribute_handle = element->start_handle = |
| + element->end_handle = |
| + ConvertGattIdentifierToId(gattObject->GetIdentifier()); |
| + element->properties = 0; |
| + return element; |
| +} |
| + |
| +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 = CreateGattDBElement< |
| + device::BluetoothRemoteGattService>( |
| + service->IsPrimary() |
| + ? mojom::BluetoothGattDBAttributeType::BTGATT_DB_PRIMARY_SERVICE |
| + : mojom::BluetoothGattDBAttributeType::BTGATT_DB_SECONDARY_SERVICE, |
| + service); |
| + |
| + const auto& characteristics = service->GetCharacteristics(); |
| + if (characteristics.size() > 0) { |
| + const auto& descriptors = characteristics.back()->GetDescriptors(); |
| + service_element->start_handle = |
| + ConvertGattIdentifierToId(characteristics.front()->GetIdentifier()); |
| + service_element->end_handle = ConvertGattIdentifierToId( |
| + descriptors.size() > 0 ? descriptors.back()->GetIdentifier() |
| + : characteristics.back()->GetIdentifier()); |
| + } |
| + db.push_back(std::move(service_element)); |
| + |
| + for (auto characteristic : characteristics) { |
|
palmer
2016/06/15 23:10:16
Nit: Could this (And line 733) be const auto&?
puthik_chromium
2016/06/16 00:03:34
There is no need. |characteristics| is already a v
|
| + mojom::BluetoothGattDBElementPtr characteristic_element = |
| + CreateGattDBElement<device::BluetoothRemoteGattCharacteristic>( |
| + mojom::BluetoothGattDBAttributeType::BTGATT_DB_CHARACTERISTIC, |
| + characteristic); |
| + characteristic_element->properties = characteristic->GetProperties(); |
| + db.push_back(std::move(characteristic_element)); |
| + |
| + for (auto descriptor : characteristic->GetDescriptors()) { |
| + db.push_back(CreateGattDBElement<device::BluetoothRemoteGattDescriptor>( |
| + mojom::BluetoothGattDBAttributeType::BTGATT_DB_DESCRIPTOR, |
| + descriptor)); |
| + } |
| + } |
| + } |
| + |
| + arc_bridge_service()->bluetooth_instance()->OnGetGattDB( |
| + std::move(remote_addr), std::move(db)); |
| +} |
| + |
| +// Find Gatt Service/Characteristic/Descriptor from std::vector from UUID. |
| +template <class T> |
| +T* ArcBluetoothBridge::FindGattObjectFromUuid( |
| + const std::vector<T*> gatt_objs, |
| + const device::BluetoothUUID uuid) const { |
| + auto it = std::find_if(gatt_objs.begin(), gatt_objs.end(), |
| + [&](T* obj) { return obj->GetUUID() == uuid; }); |
| + if (it == gatt_objs.end()) |
| + return nullptr; |
| + return *it; |
| +} |
| + |
| +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; |
| + |
| + BluetoothRemoteGattService* service = |
| + FindGattObjectFromUuid<BluetoothRemoteGattService>( |
| + device->GetGattServices(), service_id->id->uuid.To<BluetoothUUID>()); |
| + if (!service) |
| + return nullptr; |
| + |
| + return FindGattObjectFromUuid<BluetoothRemoteGattCharacteristic>( |
| + service->GetCharacteristics(), char_id->uuid.To<BluetoothUUID>()); |
| +} |
| + |
| +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; |
| + |
| + return FindGattObjectFromUuid<BluetoothRemoteGattDescriptor>( |
| + characteristic->GetDescriptors(), desc_id->uuid.To<BluetoothUUID>()); |
| +} |
| + |
| +// 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() & |
|
palmer
2016/06/15 23:10:16
This is another repeated chunk of code could would
puthik_chromium
2016/06/16 00:03:33
I refactor the permission to be a const. This shou
|
| + (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( |
|
palmer
2016/06/15 23:10:16
So, a total of 4 functions that are all identical
puthik_chromium
2016/06/16 00:03:33
What this 4 functions do is just passing the reque
|
| + 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 +1083,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 +1182,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 +1204,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 +1294,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 +1311,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 |