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..88b32e6c9499bf34a43d2960fcc784a00b394f88 100644 |
| --- a/components/arc/bluetooth/arc_bluetooth_bridge.cc |
| +++ b/components/arc/bluetooth/arc_bluetooth_bridge.cc |
| @@ -17,6 +17,7 @@ |
| #include "base/logging.h" |
| #include "base/posix/eintr_wrapper.h" |
| #include "base/strings/string_number_conversions.h" |
| +#include "base/strings/stringprintf.h" |
| #include "base/strings/utf_string_conversions.h" |
| #include "base/threading/thread_task_runner_handle.h" |
| #include "base/time/time.h" |
| @@ -56,6 +57,7 @@ constexpr int32_t kMinBtleVersion = 1; |
| constexpr int32_t kMinBtleNotifyVersion = 2; |
| constexpr int32_t kMinGattServerVersion = 3; |
| constexpr int32_t kMinAddrChangeVersion = 4; |
| +constexpr int32_t kMinMultiAdvertisementVersion = 5; |
| constexpr uint32_t kGattReadPermission = |
| BluetoothGattCharacteristic::Permission::PERMISSION_READ | |
| BluetoothGattCharacteristic::Permission::PERMISSION_READ_ENCRYPTED | |
| @@ -67,6 +69,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 +79,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 +1394,173 @@ void ArcBluetoothBridge::SendIndication( |
| mojo::Array<uint8_t> value, |
| const SendIndicationCallback& callback) {} |
| +void ArcBluetoothBridge::EnableAdvertising( |
| + int32_t min_interval, |
| + int32_t max_interval, |
| + BluetoothAdvertisement::AdvertisementType adv_type, |
| + int32_t channel_map, |
| + int32_t tx_power, |
| + int32_t timeout_s, |
| + const EnableAdvertisingCallback& callback) { |
| + DCHECK(CalledOnValidThread()); |
| + if (!CheckBluetoothInstanceVersion(kMinMultiAdvertisementVersion)) { |
| + callback.Run(mojom::BluetoothGattStatus::GATT_FAILURE, |
| + kInvalidAdvertisementHandle); |
| + return; |
| + } |
| + |
| + // Find an empty advertisement slot. |
| + int adv_handle = -1; |
| + for (int i = 0; i < kMaxAdvertisement; i++) |
|
Luis Héctor Chávez
2016/08/18 04:29:12
nit: this needs braces
|
| + if (!advertisements_[i].in_use) |
| + adv_handle = i; |
|
Luis Héctor Chávez
2016/08/18 04:29:12
break;?
|
| + |
| + if (adv_handle == -1) { |
| + LOG(WARNING) << "Out of space for advertisement data"; |
| + callback.Run(mojom::BluetoothGattStatus::GATT_FAILURE, |
| + kInvalidAdvertisementHandle); |
| + return; |
| + } |
| + |
| + // We have a handle. Mark the advertisement record in-use and |
| + // record the advertisement type. |
| + advertisements_[adv_handle].in_use = true; |
| + advertisements_[adv_handle].adv_type = adv_type; |
| + |
| + // 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::SetAdvertisingData( |
| + int32_t adv_handle, |
| + bool include_name, |
| + bool include_tx_power, |
| + int32_t appearance, |
| + mojo::Array<mojom::BluetoothAdvertisingDataPtr> adv_data, |
| + const SetAdvertisingDataCallback& callback) { |
| + DCHECK(CalledOnValidThread()); |
| + if (!CheckBluetoothInstanceVersion(kMinMultiAdvertisementVersion)) { |
| + callback.Run(mojom::BluetoothGattStatus::GATT_FAILURE); |
| + return; |
| + } |
| + |
| + if (adv_handle < 0 || adv_handle > kMaxAdvertisement || |
|
puthik_chromium
2016/08/17 23:22:04
adv_handle >= kMaxAdvertisement
Luis Héctor Chávez
2016/08/18 04:29:12
Actually you're repeating the same snippet several
|
| + !advertisements_[adv_handle].in_use) { |
| + callback.Run(mojom::BluetoothGattStatus::GATT_FAILURE); |
| + return; |
| + } |
| + |
| + // Create BluetoothAdvertisement::Data using the adv_type we got when |
|
puthik_chromium
2016/08/17 23:27:11
Should this in the type_converter?
rkc
2016/08/18 00:06:09
What Opal said. This should be in a type converter
|
| + // advertising was enabled, and the data in adv_data. |
| + std::unique_ptr<BluetoothAdvertisement::Data> data = base::WrapUnique( |
|
Luis Héctor Chávez
2016/08/18 04:29:12
base::WrapUnique(new T(...)) is being deprecated.
|
| + new BluetoothAdvertisement::Data(advertisements_[adv_handle].adv_type)); |
| + for (const auto& adv_entry : adv_data) { |
| + if (adv_entry->is_service_uuids()) { |
| + std::vector<BluetoothUUID> adv_uuids = |
| + adv_entry->get_service_uuids().To<std::vector<BluetoothUUID>>(); |
| + |
| + std::unique_ptr<std::vector<std::string>> uuid_list = |
| + base::WrapUnique(new std::vector<std::string>()); |
| + for (const auto& uuid : adv_uuids) { |
| + uuid_list->push_back(uuid.value()); |
| + } |
| + data->set_service_uuids(std::move(uuid_list)); |
| + } else if (adv_entry->is_service_data()) { |
| + std::string service_uuid = |
| + base::StringPrintf("%04x", adv_entry->get_service_data()->uuid_16bit); |
| + std::vector<uint8_t> service_data = |
| + adv_entry->get_service_data()->data.To<std::vector<uint8_t>>(); |
| + |
| + data->set_service_data( |
| + base::WrapUnique(new std::map<std::string, std::vector<uint8_t>>{ |
| + {service_uuid, service_data}})); |
| + } else if (adv_entry->is_manufacturer_data()) { |
| + // We get manufacturer data as a big blob. The first two bytes |
| + // should be a company identifier code in little-endian. |
| + std::vector<uint8_t> blob = |
| + adv_entry->get_manufacturer_data().To<std::vector<uint8_t>>(); |
| + if (blob.size() < 2) { |
|
Luis Héctor Chávez
2016/08/18 04:29:13
nit: s/2/sizeof(uint16_t)/
|
| + LOG(WARNING) << "Received malformed manufacturer data for handle " |
| + << adv_handle; |
| + advertisements_[adv_handle].Clear(); |
| + callback.Run(mojom::BluetoothGattStatus::GATT_FAILURE); |
| + return; |
| + } |
| + |
| + uint16_t cic = blob[0] << 8 | blob[1]; |
|
Luis Héctor Chávez
2016/08/18 04:29:12
Please add the same comment about the endianness h
|
| + blob.erase(blob.begin(), blob.begin() + 2); |
| + data->set_manufacturer_data(base::WrapUnique( |
| + new std::map<uint16_t, std::vector<uint8_t>>{{cic, blob}})); |
| + } |
| + } |
| + data->set_include_tx_power(include_tx_power); |
| + |
| + 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 SetAdvertisingDataCallback& callback, |
| + int32_t adv_handle, |
| + scoped_refptr<BluetoothAdvertisement> advertisement) { |
| + advertisements_[adv_handle].advertisement = advertisement; |
| + callback.Run(mojom::BluetoothGattStatus::GATT_SUCCESS); |
| +} |
| + |
| +void ArcBluetoothBridge::OnRegisterAdvertisementError( |
| + const SetAdvertisingDataCallback& 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].Clear(); |
| + callback.Run(mojom::BluetoothGattStatus::GATT_FAILURE); |
| +} |
| + |
| +void ArcBluetoothBridge::DisableAdvertising( |
| + int32_t adv_handle, |
| + const DisableAdvertisingCallback& callback) { |
| + DCHECK(CalledOnValidThread()); |
| + if (!CheckBluetoothInstanceVersion(kMinMultiAdvertisementVersion)) { |
| + callback.Run(mojom::BluetoothGattStatus::GATT_FAILURE); |
| + return; |
| + } |
| + |
| + if (adv_handle < 0 || adv_handle > kMaxAdvertisement || |
|
rkc
2016/08/18 00:06:09
adv_handle >= kMaxAdvertisement
|
| + !advertisements_[adv_handle].in_use) { |
| + callback.Run(mojom::BluetoothGattStatus::GATT_FAILURE); |
| + return; |
| + } |
| + |
| + advertisements_[adv_handle].advertisement->Unregister( |
| + base::Bind(&ArcBluetoothBridge::OnUnregisterAdvertisementDone, |
| + weak_factory_.GetWeakPtr(), callback, adv_handle), |
| + base::Bind(&ArcBluetoothBridge::OnUnregisterAdvertisementError, |
| + weak_factory_.GetWeakPtr(), callback, adv_handle)); |
| +} |
| + |
| +void ArcBluetoothBridge::OnUnregisterAdvertisementDone( |
| + const DisableAdvertisingCallback& callback, |
| + int32_t adv_handle) { |
| + advertisements_[adv_handle].Clear(); |
| + callback.Run(mojom::BluetoothGattStatus::GATT_SUCCESS); |
| +} |
| + |
| +void ArcBluetoothBridge::OnUnregisterAdvertisementError( |
| + const DisableAdvertisingCallback& callback, |
| + int32_t adv_handle, |
| + BluetoothAdvertisement::ErrorCode error_code) { |
| + LOG(WARNING) << "Failed to disable advertising for handle " << adv_handle |
| + << ", error code = " << error_code; |
| + advertisements_[adv_handle].Clear(); |
| + callback.Run(mojom::BluetoothGattStatus::GATT_FAILURE); |
| +} |
| + |
| void ArcBluetoothBridge::OnDiscoveryError() { |
| LOG(WARNING) << "failed to change discovery state"; |
| } |