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 ba97d46403beb9e2fa4d16031ccc4b4f58cca2d2..1e011410379d55d8de78f2ecda32cb6dfe3f11b2 100644 |
| --- a/components/arc/bluetooth/arc_bluetooth_bridge.cc |
| +++ b/components/arc/bluetooth/arc_bluetooth_bridge.cc |
| @@ -67,6 +67,7 @@ constexpr uint32_t kGattWritePermission = |
| BluetoothGattCharacteristic::Permission:: |
| PERMISSION_WRITE_ENCRYPTED_AUTHENTICATED; |
| constexpr int32_t kInvalidGattAttributeHandle = -1; |
| +constexpr int32_t kInvalidAdvertisementHandle = -1; |
| // Bluetooth Specification Version 4.2 Vol 3 Part F Section 3.2.2 |
| // An attribute handle of value 0xFFFF is known as the maximum attribute handle. |
| constexpr int32_t kMaxGattAttributeHandle = 0xFFFF; |
| @@ -76,7 +77,6 @@ constexpr int kMaxGattAttributeLength = 512; |
| // Copied from Android at system/bt/stack/btm/btm_ble_int.h |
| // https://goo.gl/k7PM6u |
| constexpr uint16_t kAndroidMBluetoothVersionNumber = 95; |
| -constexpr uint16_t kMaxAdvertisement = 5; |
| using GattStatusCallback = |
| base::Callback<void(arc::mojom::BluetoothGattStatus)>; |
| @@ -1392,6 +1392,137 @@ void ArcBluetoothBridge::SendIndication( |
| mojo::Array<uint8_t> value, |
| const SendIndicationCallback& callback) {} |
| +bool ArcBluetoothBridge::GetAdvertisementHandle(int32_t* adv_handle) { |
| + for (int i = 0; i < kMaxAdvertisements; i++) { |
| + if (advertisements_.find(i) == advertisements_.end()) { |
| + *adv_handle = i; |
| + return true; |
| + } |
| + } |
| + return false; |
| +} |
| + |
| +void ArcBluetoothBridge::ReserveAdvertisementHandle( |
| + const ReserveAdvertisementHandleCallback& callback) { |
| + DCHECK(CalledOnValidThread()); |
| + // Find an empty advertisement slot. |
| + int32_t adv_handle; |
| + if (!GetAdvertisementHandle(&adv_handle)) { |
| + LOG(WARNING) << "Out of space for advertisement data"; |
| + callback.Run(mojom::BluetoothGattStatus::GATT_FAILURE, |
| + kInvalidAdvertisementHandle); |
| + return; |
| + } |
| + |
| + // We have a handle. Put an entry in the map to reserve it. |
| + advertisements_[adv_handle] = scoped_refptr<device::BluetoothAdvertisement>(); |
|
rickyz (no longer on Chrome)
2016/08/29 01:09:23
nit: = nullptr for consistency with below
|
| + |
| + // The advertisement will be registered when we get the call |
| + // to SetAdvertisingData. For now, just return the adv_handle. |
| + callback.Run(mojom::BluetoothGattStatus::GATT_SUCCESS, adv_handle); |
| +} |
| + |
| +void ArcBluetoothBridge::BroadcastAdvertisement( |
| + int32_t adv_handle, |
| + mojom::BluetoothAdvertisementPtr advertisement, |
| + const BroadcastAdvertisementCallback& callback) { |
| + DCHECK(CalledOnValidThread()); |
| + if (advertisements_.find(adv_handle) == advertisements_.end()) { |
| + callback.Run(mojom::BluetoothGattStatus::GATT_FAILURE); |
| + return; |
| + } |
| + |
| + auto adv_data = |
| + advertisement.To<std::unique_ptr<device::BluetoothAdvertisement::Data>>(); |
| + if (!adv_data) { |
| + LOG(WARNING) << "Tried to broadcast malformed advertisement data for " |
| + << "handle " << adv_handle; |
| + callback.Run(mojom::BluetoothGattStatus::GATT_FAILURE); |
| + return; |
| + } |
| + |
| + if (!advertisements_[adv_handle]) { |
| + OnReadyToRegisterAdvertisement(callback, adv_handle, std::move(adv_data)); |
| + return; |
| + } |
| + |
| + advertisements_[adv_handle]->Unregister( |
| + base::Bind(&ArcBluetoothBridge::OnReadyToRegisterAdvertisement, |
| + weak_factory_.GetWeakPtr(), callback, adv_handle, |
| + base::Passed(std::move(adv_data))), |
| + base::Bind(&ArcBluetoothBridge::OnRegisterAdvertisementError, |
| + weak_factory_.GetWeakPtr(), callback, adv_handle)); |
| +} |
| + |
| +void ArcBluetoothBridge::ReleaseAdvertisementHandle( |
| + int32_t adv_handle, |
| + const ReleaseAdvertisementHandleCallback& callback) { |
| + DCHECK(CalledOnValidThread()); |
| + if (advertisements_.find(adv_handle) == advertisements_.end()) { |
| + callback.Run(mojom::BluetoothGattStatus::GATT_FAILURE); |
| + return; |
| + } |
| + |
| + if (!advertisements_[adv_handle]) { |
| + advertisements_.erase(adv_handle); |
| + callback.Run(mojom::BluetoothGattStatus::GATT_SUCCESS); |
| + return; |
| + } |
| + |
| + advertisements_[adv_handle]->Unregister( |
| + base::Bind(&ArcBluetoothBridge::OnUnregisterAdvertisementDone, |
| + weak_factory_.GetWeakPtr(), callback, adv_handle), |
| + base::Bind(&ArcBluetoothBridge::OnUnregisterAdvertisementError, |
| + weak_factory_.GetWeakPtr(), callback, adv_handle)); |
| +} |
| + |
| +void ArcBluetoothBridge::OnReadyToRegisterAdvertisement( |
| + const BroadcastAdvertisementCallback& callback, |
| + int32_t adv_handle, |
| + std::unique_ptr<device::BluetoothAdvertisement::Data> data) { |
| + bluetooth_adapter_->RegisterAdvertisement( |
| + std::move(data), |
| + base::Bind(&ArcBluetoothBridge::OnRegisterAdvertisementDone, |
| + weak_factory_.GetWeakPtr(), callback, adv_handle), |
| + base::Bind(&ArcBluetoothBridge::OnRegisterAdvertisementError, |
| + weak_factory_.GetWeakPtr(), callback, adv_handle)); |
| +} |
| + |
| +void ArcBluetoothBridge::OnRegisterAdvertisementDone( |
| + const BroadcastAdvertisementCallback& callback, |
| + int32_t adv_handle, |
| + scoped_refptr<BluetoothAdvertisement> advertisement) { |
| + advertisements_[adv_handle] = advertisement; |
|
rickyz (no longer on Chrome)
2016/08/24 21:47:30
Can std::move advertisement
Eric Caruso
2016/08/24 22:24:42
Since it's a scoped_refptr, it seems kind of super
Eric Caruso
2016/08/24 22:26:11
(Do we do this with std::move elsewhere?)
rickyz (no longer on Chrome)
2016/08/29 01:09:23
Yeah, we do - it's a minor optimization (avoids an
|
| + callback.Run(mojom::BluetoothGattStatus::GATT_SUCCESS); |
| +} |
| + |
| +void ArcBluetoothBridge::OnRegisterAdvertisementError( |
| + const BroadcastAdvertisementCallback& callback, |
| + int32_t adv_handle, |
| + BluetoothAdvertisement::ErrorCode error_code) { |
| + LOG(WARNING) << "Failed to register advertisement for handle " << adv_handle |
| + << ", error code = " << error_code; |
| + advertisements_[adv_handle] = nullptr; |
| + callback.Run(mojom::BluetoothGattStatus::GATT_FAILURE); |
| +} |
| + |
| +void ArcBluetoothBridge::OnUnregisterAdvertisementDone( |
| + const ReleaseAdvertisementHandleCallback& callback, |
| + int32_t adv_handle) { |
| + advertisements_.erase(adv_handle); |
| + callback.Run(mojom::BluetoothGattStatus::GATT_SUCCESS); |
| +} |
| + |
| +void ArcBluetoothBridge::OnUnregisterAdvertisementError( |
| + const ReleaseAdvertisementHandleCallback& callback, |
| + int32_t adv_handle, |
| + BluetoothAdvertisement::ErrorCode error_code) { |
| + LOG(WARNING) << "Failed to unregister advertisement for handle " << adv_handle |
| + << ", error code = " << error_code; |
| + advertisements_.erase(adv_handle); |
| + callback.Run(mojom::BluetoothGattStatus::GATT_FAILURE); |
| +} |
| + |
| void ArcBluetoothBridge::OnDiscoveryError() { |
| LOG(WARNING) << "failed to change discovery state"; |
| } |
| @@ -1596,7 +1727,7 @@ ArcBluetoothBridge::GetAdapterProperties( |
| mojom::BluetoothLocalLEFeatures::New(); |
| le_features->version_supported = kAndroidMBluetoothVersionNumber; |
| le_features->local_privacy_enabled = 0; |
| - le_features->max_adv_instance = kMaxAdvertisement; |
| + le_features->max_adv_instance = kMaxAdvertisements; |
| le_features->rpa_offload_supported = 0; |
| le_features->max_irk_list_size = 0; |
| le_features->max_adv_filter_supported = 0; |