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 46bfa1353f11a921f28f4c92d8212a0d4294c5b3..17ddb50b4d881a08d5691f3bcc6f2cbdec0405be 100644 |
| --- a/components/arc/bluetooth/arc_bluetooth_bridge.cc |
| +++ b/components/arc/bluetooth/arc_bluetooth_bridge.cc |
| @@ -60,6 +60,83 @@ constexpr uint32_t kGattWritePermission = |
| BluetoothGattCharacteristic::Permission::PERMISSION_WRITE_ENCRYPTED | |
| BluetoothGattCharacteristic::Permission:: |
| PERMISSION_WRITE_ENCRYPTED_AUTHENTICATED; |
| +constexpr int32_t kInvalidGattAttributeHandle = -1; |
| + |
| +using GattStatusCallback = |
| + base::Callback<void(arc::mojom::BluetoothGattStatus)>; |
| +using GattReadCallback = |
| + base::Callback<void(arc::mojom::BluetoothGattValuePtr)>; |
| + |
| +// 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 |
|
palmer
2016/07/22 02:56:09
Nit: Correct the comment: "Convert the last 4 char
puthik_chromium
2016/07/22 21:48:16
Done.
|
| +int ConvertGattIdentifierToId(const std::string identifier) { |
| + return std::stoi(identifier.substr(identifier.size() - 4), nullptr, 16); |
|
palmer
2016/07/22 02:56:10
If stoi fails (e.g. because the characters were no
puthik_chromium
2016/07/22 21:48:16
We rely on BlueZ implementation that the character
|
| +} |
| + |
| +// Create GattDBElement and fill in common data for |
| +// Gatt Service/Characteristic/Descriptor. |
| +template <class RemoteGattAttribute> |
| +arc::mojom::BluetoothGattDBElementPtr CreateGattDBElement( |
| + const arc::mojom::BluetoothGattDBAttributeType type, |
| + const RemoteGattAttribute* gatt_attr) { |
|
palmer
2016/07/22 02:56:09
Style nit: Similar comment as before: My preferenc
puthik_chromium
2016/07/22 21:48:16
Done.
|
| + arc::mojom::BluetoothGattDBElementPtr element = |
| + arc::mojom::BluetoothGattDBElement::New(); |
| + element->type = type; |
| + element->uuid = arc::mojom::BluetoothUUID::From(gatt_attr->GetUUID()); |
| + element->id = element->attribute_handle = element->start_handle = |
| + element->end_handle = |
| + ConvertGattIdentifierToId(gatt_attr->GetIdentifier()); |
| + element->properties = 0; |
| + return element; |
| +} |
| + |
| +// Find Gatt Service/Characteristic/Descriptor from std::vector using UUID. |
|
palmer
2016/07/22 02:56:10
I might rewrite this comment to use the argument n
puthik_chromium
2016/07/22 21:48:16
Removed
|
| +template <class RemoteGattAttribute> |
| +RemoteGattAttribute* FindGattAttributeFromUuid( |
|
palmer
2016/07/22 02:56:09
I'd rename this to |FindGattAttributeByUuid|. (We
puthik_chromium
2016/07/22 21:48:16
Done.
|
| + const std::vector<RemoteGattAttribute*>& gatt_attrs, |
|
palmer
2016/07/22 02:56:10
Style nit: |attributes|.
puthik_chromium
2016/07/22 21:48:16
Done.
|
| + const BluetoothUUID& uuid) { |
| + auto it = std::find_if( |
| + gatt_attrs.begin(), gatt_attrs.end(), |
| + [uuid](RemoteGattAttribute* attr) { return attr->GetUUID() == uuid; }); |
| + if (it == gatt_attrs.end()) |
|
palmer
2016/07/22 02:56:09
Style nit: You could shorten this to:
return it
puthik_chromium
2016/07/22 21:48:16
Done. This is more concise.
|
| + return nullptr; |
| + return *it; |
| +} |
| + |
| +// Common success callback for GATT operations that only need to report |
| +// GattStatus back to Android. |
| +void OnGattOperationDone(const GattStatusCallback& callback) { |
| + callback.Run(arc::mojom::BluetoothGattStatus::GATT_SUCCESS); |
| +} |
| + |
| +// Common error callback for GATT operations that only need to report |
| +// GattStatus back to Android. |
| +void OnGattOperationError(const GattStatusCallback& callback, |
| + BluetoothGattService::GattErrorCode error_code) { |
| + callback.Run(mojo::ConvertTo<arc::mojom::BluetoothGattStatus>(error_code)); |
| +} |
| + |
| +// Common success callback for ReadGattCharacteristic and ReadGattDescriptor |
| +void OnGattReadDone(const GattReadCallback& callback, |
| + const std::vector<uint8_t>& result) { |
| + arc::mojom::BluetoothGattValuePtr gattValue = |
| + arc::mojom::BluetoothGattValue::New(); |
| + gattValue->status = arc::mojom::BluetoothGattStatus::GATT_SUCCESS; |
| + gattValue->value = mojo::Array<uint8_t>::From(result); |
| + callback.Run(std::move(gattValue)); |
| +} |
| + |
| +// Common error callback for ReadGattCharacteristic and ReadGattDescriptor |
| +void OnGattReadError(const GattReadCallback& callback, |
| + BluetoothGattService::GattErrorCode error_code) { |
| + arc::mojom::BluetoothGattValuePtr gattValue = |
| + arc::mojom::BluetoothGattValue::New(); |
| + gattValue->status = |
| + mojo::ConvertTo<arc::mojom::BluetoothGattStatus>(error_code); |
| + gattValue->value = nullptr; |
| + callback.Run(std::move(gattValue)); |
| +} |
| + |
| } // namespace |
| namespace arc { |
| @@ -78,6 +155,8 @@ ArcBluetoothBridge::ArcBluetoothBridge(ArcBridgeService* bridge_service) |
| } |
| ArcBluetoothBridge::~ArcBluetoothBridge() { |
| + DCHECK(CalledOnValidThread()); |
| + |
| arc_bridge_service()->bluetooth()->RemoveObserver(this); |
| if (bluetooth_adapter_) |
| @@ -86,6 +165,8 @@ ArcBluetoothBridge::~ArcBluetoothBridge() { |
| void ArcBluetoothBridge::OnAdapterInitialized( |
| scoped_refptr<BluetoothAdapter> adapter) { |
| + DCHECK(CalledOnValidThread()); |
| + |
| // We can downcast here because we are always running on Chrome OS, and |
| // so our adapter uses BlueZ. |
| bluetooth_adapter_ = |
| @@ -106,6 +187,8 @@ void ArcBluetoothBridge::OnInstanceReady() { |
| void ArcBluetoothBridge::AdapterPresentChanged(BluetoothAdapter* adapter, |
| bool present) { |
| + DCHECK(CalledOnValidThread()); |
| + |
| // If the adapter goes away, remove ourselves as an observer. |
| if (!present && adapter == bluetooth_adapter_) { |
| adapter->RemoveObserver(this); |
| @@ -695,6 +778,7 @@ void ArcBluetoothBridge::SearchService(mojom::BluetoothAddressPtr remote_addr) { |
| void ArcBluetoothBridge::OnStartLEListenDone( |
| const StartLEListenCallback& callback, |
| scoped_refptr<BluetoothAdvertisement> advertisement) { |
| + DCHECK(CalledOnValidThread()); |
| advertisment_ = advertisement; |
| callback.Run(mojom::BluetoothGattStatus::GATT_SUCCESS); |
| } |
| @@ -702,11 +786,13 @@ void ArcBluetoothBridge::OnStartLEListenDone( |
| void ArcBluetoothBridge::OnStartLEListenError( |
| const StartLEListenCallback& callback, |
| BluetoothAdvertisement::ErrorCode error_code) { |
| + DCHECK(CalledOnValidThread()); |
| advertisment_ = nullptr; |
| callback.Run(mojom::BluetoothGattStatus::GATT_FAILURE); |
| } |
| void ArcBluetoothBridge::StartLEListen(const StartLEListenCallback& callback) { |
| + DCHECK(CalledOnValidThread()); |
| std::unique_ptr<BluetoothAdvertisement::Data> adv_data = |
| base::WrapUnique(new BluetoothAdvertisement::Data( |
| BluetoothAdvertisement::ADVERTISEMENT_TYPE_BROADCAST)); |
| @@ -719,6 +805,7 @@ void ArcBluetoothBridge::StartLEListen(const StartLEListenCallback& callback) { |
| void ArcBluetoothBridge::OnStopLEListenDone( |
| const StopLEListenCallback& callback) { |
| + DCHECK(CalledOnValidThread()); |
| advertisment_ = nullptr; |
| callback.Run(mojom::BluetoothGattStatus::GATT_SUCCESS); |
| } |
| @@ -726,6 +813,7 @@ void ArcBluetoothBridge::OnStopLEListenDone( |
| void ArcBluetoothBridge::OnStopLEListenError( |
| const StopLEListenCallback& callback, |
| BluetoothAdvertisement::ErrorCode error_code) { |
| + DCHECK(CalledOnValidThread()); |
| advertisment_ = nullptr; |
| callback.Run(mojom::BluetoothGattStatus::GATT_FAILURE); |
| } |
| @@ -743,30 +831,6 @@ void ArcBluetoothBridge::StopLEListen(const StopLEListenCallback& callback) { |
| 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; |
| @@ -775,8 +839,7 @@ void ArcBluetoothBridge::GetGattDB(mojom::BluetoothAddressPtr remote_addr) { |
| 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>( |
| + mojom::BluetoothGattDBElementPtr service_element = CreateGattDBElement( |
| service->IsPrimary() |
| ? mojom::BluetoothGattDBAttributeType::BTGATT_DB_PRIMARY_SERVICE |
| : mojom::BluetoothGattDBAttributeType::BTGATT_DB_SECONDARY_SERVICE, |
| @@ -795,14 +858,14 @@ void ArcBluetoothBridge::GetGattDB(mojom::BluetoothAddressPtr remote_addr) { |
| for (auto* characteristic : characteristics) { |
| mojom::BluetoothGattDBElementPtr characteristic_element = |
| - CreateGattDBElement<device::BluetoothRemoteGattCharacteristic>( |
| + CreateGattDBElement( |
| 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>( |
| + db.push_back(CreateGattDBElement( |
| mojom::BluetoothGattDBAttributeType::BTGATT_DB_DESCRIPTOR, |
| descriptor)); |
| } |
| @@ -813,18 +876,6 @@ void ArcBluetoothBridge::GetGattDB(mojom::BluetoothAddressPtr remote_addr) { |
| 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, |
| @@ -838,14 +889,13 @@ BluetoothRemoteGattCharacteristic* ArcBluetoothBridge::FindGattCharacteristic( |
| if (!device) |
| return nullptr; |
| - BluetoothRemoteGattService* service = |
| - FindGattObjectFromUuid<BluetoothRemoteGattService>( |
| - device->GetGattServices(), service_id->id->uuid.To<BluetoothUUID>()); |
| + BluetoothRemoteGattService* service = FindGattAttributeFromUuid( |
| + device->GetGattServices(), service_id->id->uuid.To<BluetoothUUID>()); |
| if (!service) |
| return nullptr; |
| - return FindGattObjectFromUuid<BluetoothRemoteGattCharacteristic>( |
| - service->GetCharacteristics(), char_id->uuid.To<BluetoothUUID>()); |
| + return FindGattAttributeFromUuid(service->GetCharacteristics(), |
| + char_id->uuid.To<BluetoothUUID>()); |
| } |
| BluetoothRemoteGattDescriptor* ArcBluetoothBridge::FindGattDescriptor( |
| @@ -858,40 +908,8 @@ BluetoothRemoteGattDescriptor* ArcBluetoothBridge::FindGattDescriptor( |
| 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)); |
| + return FindGattAttributeFromUuid(characteristic->GetDescriptors(), |
| + desc_id->uuid.To<BluetoothUUID>()); |
| } |
| void ArcBluetoothBridge::ReadGattCharacteristic( |
| @@ -905,10 +923,8 @@ void ArcBluetoothBridge::ReadGattCharacteristic( |
| DCHECK(characteristic->GetPermissions() & kGattReadPermission); |
| characteristic->ReadRemoteCharacteristic( |
| - base::Bind(&ArcBluetoothBridge::OnGattReadDone, |
| - weak_factory_.GetWeakPtr(), callback), |
| - base::Bind(&ArcBluetoothBridge::OnGattReadError, |
| - weak_factory_.GetWeakPtr(), callback)); |
| + base::Bind(&OnGattReadDone, callback), |
| + base::Bind(&OnGattReadError, callback)); |
| } |
| void ArcBluetoothBridge::WriteGattCharacteristic( |
| @@ -924,10 +940,8 @@ void ArcBluetoothBridge::WriteGattCharacteristic( |
| 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)); |
| + base::Bind(&OnGattOperationDone, callback), |
| + base::Bind(&OnGattOperationError, callback)); |
| } |
| void ArcBluetoothBridge::ReadGattDescriptor( |
| @@ -942,11 +956,8 @@ void ArcBluetoothBridge::ReadGattDescriptor( |
| DCHECK(descriptor); |
| DCHECK(descriptor->GetPermissions() & kGattReadPermission); |
| - descriptor->ReadRemoteDescriptor( |
| - base::Bind(&ArcBluetoothBridge::OnGattReadDone, |
| - weak_factory_.GetWeakPtr(), callback), |
| - base::Bind(&ArcBluetoothBridge::OnGattReadError, |
| - weak_factory_.GetWeakPtr(), callback)); |
| + descriptor->ReadRemoteDescriptor(base::Bind(&OnGattReadDone, callback), |
| + base::Bind(&OnGattReadError, callback)); |
| } |
| void ArcBluetoothBridge::WriteGattDescriptor( |
| @@ -971,37 +982,25 @@ void ArcBluetoothBridge::WriteGattDescriptor( |
| // TODO(http://crbug.com/622832) |
| if (descriptor->GetUUID() == |
| BluetoothGattDescriptor::ClientCharacteristicConfigurationUuid()) { |
| - OnGattWriteDone(callback); |
| + OnGattOperationDone(callback); |
| return; |
| } |
| 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)); |
| + base::Bind(&OnGattOperationDone, callback), |
| + base::Bind(&OnGattOperationError, callback)); |
| } |
| void ArcBluetoothBridge::OnGattNotifyStartDone( |
| const RegisterForGattNotificationCallback& callback, |
| const std::string char_string_id, |
| std::unique_ptr<BluetoothGattNotifySession> notify_session) { |
| + DCHECK(CalledOnValidThread()); |
| 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, |
| @@ -1024,8 +1023,7 @@ void ArcBluetoothBridge::RegisterForGattNotification( |
| base::Bind(&ArcBluetoothBridge::OnGattNotifyStartDone, |
| weak_factory_.GetWeakPtr(), callback, |
| characteristic->GetIdentifier()), |
| - base::Bind(&ArcBluetoothBridge::OnGattNotifyStartError, |
| - weak_factory_.GetWeakPtr(), callback)); |
| + base::Bind(&OnGattOperationError, callback)); |
| } |
| void ArcBluetoothBridge::DeregisterForGattNotification( |
| @@ -1033,6 +1031,8 @@ void ArcBluetoothBridge::DeregisterForGattNotification( |
| mojom::BluetoothGattServiceIDPtr service_id, |
| mojom::BluetoothGattIDPtr char_id, |
| const DeregisterForGattNotificationCallback& callback) { |
| + DCHECK(CalledOnValidThread()); |
| + |
| BluetoothRemoteGattCharacteristic* characteristic = FindGattCharacteristic( |
| std::move(remote_addr), std::move(service_id), std::move(char_id)); |
| @@ -1050,8 +1050,7 @@ void ArcBluetoothBridge::DeregisterForGattNotification( |
| 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)); |
| + notify->Stop(base::Bind(&OnGattOperationDone, callback)); |
| } |
| void ArcBluetoothBridge::ReadRemoteRssi( |
| @@ -1063,30 +1062,120 @@ void ArcBluetoothBridge::ReadRemoteRssi( |
| callback.Run(rssi); |
| } |
| +template <class LocalGattAttribute> |
| +int32_t ArcBluetoothBridge::CreateGattAttributeHandle( |
| + LocalGattAttribute* gatt_attr) { |
| + DCHECK(CalledOnValidThread()); |
| + if (!gatt_attr) |
| + return kInvalidGattAttributeHandle; |
| + int32_t handle = next_gatt_server_attribute_handle(); |
| + const std::string& identifier = gatt_attr->GetIdentifier(); |
| + gatt_identifier_[handle] = identifier; |
|
palmer
2016/07/22 02:56:10
Style nit: You could just do
gatt_identifier_[h
puthik_chromium
2016/07/22 21:48:16
Won't fix.
identifier will be used in next CL.
|
| + return handle; |
| +} |
| + |
| void ArcBluetoothBridge::AddService(mojom::BluetoothGattServiceIDPtr service_id, |
| int32_t num_handles, |
| - const AddServiceCallback& callback) {} |
| + const AddServiceCallback& callback) { |
| + base::WeakPtr<BluetoothLocalGattService> service = |
| + BluetoothLocalGattService::Create( |
| + bluetooth_adapter_.get(), service_id->id->uuid.To<BluetoothUUID>(), |
| + service_id->is_primary, nullptr /* included_service */, |
| + this /* delegate */); |
| + callback.Run(CreateGattAttributeHandle(service.get())); |
| +} |
| void ArcBluetoothBridge::AddCharacteristic( |
| int32_t service_handle, |
| mojom::BluetoothUUIDPtr uuid, |
| int32_t properties, |
| int32_t permissions, |
| - const AddCharacteristicCallback& callback) {} |
| + const AddCharacteristicCallback& callback) { |
| + DCHECK(CalledOnValidThread()); |
| + DCHECK(gatt_identifier_.find(service_handle) != gatt_identifier_.end()); |
| + base::WeakPtr<BluetoothLocalGattCharacteristic> characteristic = |
| + BluetoothLocalGattCharacteristic::Create( |
| + uuid.To<BluetoothUUID>(), properties, permissions, |
| + bluetooth_adapter_->GetGattService(gatt_identifier_[service_handle])); |
| + int32_t characteristic_handle = |
| + CreateGattAttributeHandle(characteristic.get()); |
| + last_characteristic_[service_handle] = characteristic_handle; |
| + callback.Run(characteristic_handle); |
| +} |
| void ArcBluetoothBridge::AddDescriptor(int32_t service_handle, |
| mojom::BluetoothUUIDPtr uuid, |
| int32_t permissions, |
| - const AddDescriptorCallback& callback) {} |
| + const AddDescriptorCallback& callback) { |
| + DCHECK(CalledOnValidThread()); |
| + // Chrome automatically adds a CCC Descriptor to a characteristic when needed. |
| + // We will generate a bogus handle for Android. |
| + if (uuid.To<BluetoothUUID>() == |
| + BluetoothGattDescriptor::ClientCharacteristicConfigurationUuid()) { |
| + int32_t handle = next_gatt_server_attribute_handle(); |
| + callback.Run(handle); |
| + return; |
| + } |
| + |
| + DCHECK(gatt_identifier_.find(service_handle) != gatt_identifier_.end()); |
| + BluetoothLocalGattService* service = |
| + bluetooth_adapter_->GetGattService(gatt_identifier_[service_handle]); |
| + DCHECK(service); |
| + // Since the Android API does not give information about which characteristic |
| + // is the parent of the new descriptor, we assume that it would be the last |
| + // characteristic that was added to the given service. This matches the |
| + // Android framework code at android/bluetooth/BluetoothGattServer.java#594. |
| + // Link: https://goo.gl/cJZl1u |
| + DCHECK(last_characteristic_.find(service_handle) != |
| + last_characteristic_.end()); |
| + int32_t last_characteristic_handle = last_characteristic_[service_handle]; |
| + |
| + DCHECK(gatt_identifier_.find(last_characteristic_handle) != |
| + gatt_identifier_.end()); |
| + BluetoothLocalGattCharacteristic* characteristic = |
| + service->GetCharacteristic(gatt_identifier_[last_characteristic_handle]); |
| + DCHECK(characteristic); |
| + |
| + base::WeakPtr<BluetoothLocalGattDescriptor> descriptor = |
| + BluetoothLocalGattDescriptor::Create(uuid.To<BluetoothUUID>(), |
| + permissions, characteristic); |
| + callback.Run(CreateGattAttributeHandle(descriptor.get())); |
| +} |
| void ArcBluetoothBridge::StartService(int32_t service_handle, |
| - const StartServiceCallback& callback) {} |
| + const StartServiceCallback& callback) { |
| + DCHECK(CalledOnValidThread()); |
| + DCHECK(gatt_identifier_.find(service_handle) != gatt_identifier_.end()); |
| + BluetoothLocalGattService* service = |
| + bluetooth_adapter_->GetGattService(gatt_identifier_[service_handle]); |
| + DCHECK(service); |
| + service->Register(base::Bind(&OnGattOperationDone, callback), |
| + base::Bind(&OnGattOperationError, callback)); |
| +} |
| void ArcBluetoothBridge::StopService(int32_t service_handle, |
| - const StopServiceCallback& callback) {} |
| + const StopServiceCallback& callback) { |
| + DCHECK(CalledOnValidThread()); |
| + DCHECK(gatt_identifier_.find(service_handle) != gatt_identifier_.end()); |
| + BluetoothLocalGattService* service = |
| + bluetooth_adapter_->GetGattService(gatt_identifier_[service_handle]); |
| + DCHECK(service); |
| + service->Unregister(base::Bind(&OnGattOperationDone, callback), |
| + base::Bind(&OnGattOperationError, callback)); |
| +} |
| void ArcBluetoothBridge::DeleteService(int32_t service_handle, |
| - const DeleteServiceCallback& callback) {} |
| + const DeleteServiceCallback& callback) { |
| + DCHECK(CalledOnValidThread()); |
| + DCHECK(gatt_identifier_.find(service_handle) != gatt_identifier_.end()); |
| + BluetoothLocalGattService* service = |
| + bluetooth_adapter_->GetGattService(gatt_identifier_[service_handle]); |
| + DCHECK(service); |
| + |
| + service->Delete(); |
| + gatt_identifier_.erase(service_handle); |
| + OnGattOperationDone(callback); |
| +} |
| void ArcBluetoothBridge::SendIndication( |
| int32_t attribute_handle, |
| @@ -1432,4 +1521,8 @@ bool ArcBluetoothBridge::CheckBluetoothInstanceVersion( |
| return false; |
| } |
| +bool ArcBluetoothBridge::CalledOnValidThread() { |
| + return thread_checker_.CalledOnValidThread(); |
| +} |
| + |
| } // namespace arc |