From 50818ce5049e84526cdadfe11a0ea08405b5c036 Mon Sep 17 00:00:00 2001 From: gogerald Date: Thu, 3 Mar 2016 13:55:48 -0800 Subject: Implement read & write remote GATT characteristic value for Windows This CL implements read & write remote GATT characteristic value for Windows and related unit tests. BUG=579202 Review URL: https://codereview.chromium.org/1739383002 Cr-Commit-Position: refs/heads/master@{#379103} --- .../bluetooth_gatt_characteristic_unittest.cc | 127 +++++++++++++-------- device/bluetooth/bluetooth_low_energy_win.cc | 48 ++++++++ device/bluetooth/bluetooth_low_energy_win.h | 14 +++ device/bluetooth/bluetooth_low_energy_win_fake.cc | 105 ++++++++++++++++- device/bluetooth/bluetooth_low_energy_win_fake.h | 28 +++++ .../bluetooth_remote_gatt_characteristic_win.cc | 95 ++++++++++++++- .../bluetooth_remote_gatt_characteristic_win.h | 14 +++ device/bluetooth/bluetooth_task_manager_win.cc | 62 ++++++++++ device/bluetooth/bluetooth_task_manager_win.h | 30 +++++ device/bluetooth/test/bluetooth_test_win.cc | 110 ++++++++++++++++++ device/bluetooth/test/bluetooth_test_win.h | 34 +++++- 11 files changed, 608 insertions(+), 59 deletions(-) (limited to 'device') diff --git a/device/bluetooth/bluetooth_gatt_characteristic_unittest.cc b/device/bluetooth/bluetooth_gatt_characteristic_unittest.cc index 96e3f52..d320f95 100644 --- a/device/bluetooth/bluetooth_gatt_characteristic_unittest.cc +++ b/device/bluetooth/bluetooth_gatt_characteristic_unittest.cc @@ -264,10 +264,11 @@ TEST_F(BluetoothGattCharacteristicTest, GetService) { } #endif // defined(OS_ANDROID) || defined(OS_WIN) -#if defined(OS_ANDROID) +#if defined(OS_ANDROID) || defined(OS_WIN) // Tests ReadRemoteCharacteristic and GetValue with empty value buffer. TEST_F(BluetoothGattCharacteristicTest, ReadRemoteCharacteristic_Empty) { - ASSERT_NO_FATAL_FAILURE(FakeCharacteristicBoilerplate()); + ASSERT_NO_FATAL_FAILURE(FakeCharacteristicBoilerplate( + BluetoothGattCharacteristic::PROPERTY_READ)); characteristic1_->ReadRemoteCharacteristic( GetReadValueCallback(Call::EXPECTED), @@ -282,12 +283,13 @@ TEST_F(BluetoothGattCharacteristicTest, ReadRemoteCharacteristic_Empty) { EXPECT_EQ(empty_vector, last_read_value_); EXPECT_EQ(empty_vector, characteristic1_->GetValue()); } -#endif // defined(OS_ANDROID) +#endif // defined(OS_ANDROID) || defined(OS_WIN) -#if defined(OS_ANDROID) +#if defined(OS_ANDROID) || defined(OS_WIN) // Tests WriteRemoteCharacteristic with empty value buffer. TEST_F(BluetoothGattCharacteristicTest, WriteRemoteCharacteristic_Empty) { - ASSERT_NO_FATAL_FAILURE(FakeCharacteristicBoilerplate()); + ASSERT_NO_FATAL_FAILURE(FakeCharacteristicBoilerplate( + BluetoothGattCharacteristic::PROPERTY_WRITE)); std::vector empty_vector; characteristic1_->WriteRemoteCharacteristic( @@ -298,12 +300,13 @@ TEST_F(BluetoothGattCharacteristicTest, WriteRemoteCharacteristic_Empty) { EXPECT_EQ(empty_vector, last_write_value_); } -#endif // defined(OS_ANDROID) +#endif // defined(OS_ANDROID) || defined(OS_WIN) -#if defined(OS_ANDROID) +#if defined(OS_ANDROID) || defined(OS_WIN) // Tests ReadRemoteCharacteristic completing after Chrome objects are deleted. TEST_F(BluetoothGattCharacteristicTest, ReadRemoteCharacteristic_AfterDeleted) { - ASSERT_NO_FATAL_FAILURE(FakeCharacteristicBoilerplate()); + ASSERT_NO_FATAL_FAILURE(FakeCharacteristicBoilerplate( + BluetoothGattCharacteristic::PROPERTY_READ)); characteristic1_->ReadRemoteCharacteristic( GetReadValueCallback(Call::NOT_EXPECTED), @@ -317,13 +320,14 @@ TEST_F(BluetoothGattCharacteristicTest, ReadRemoteCharacteristic_AfterDeleted) { empty_vector); EXPECT_TRUE("Did not crash!"); } -#endif // defined(OS_ANDROID) +#endif // defined(OS_ANDROID) || defined(OS_WIN) -#if defined(OS_ANDROID) +#if defined(OS_ANDROID) || defined(OS_WIN) // Tests WriteRemoteCharacteristic completing after Chrome objects are deleted. TEST_F(BluetoothGattCharacteristicTest, WriteRemoteCharacteristic_AfterDeleted) { - ASSERT_NO_FATAL_FAILURE(FakeCharacteristicBoilerplate()); + ASSERT_NO_FATAL_FAILURE(FakeCharacteristicBoilerplate( + BluetoothGattCharacteristic::PROPERTY_WRITE)); std::vector empty_vector; characteristic1_->WriteRemoteCharacteristic( @@ -336,12 +340,13 @@ TEST_F(BluetoothGattCharacteristicTest, SimulateGattCharacteristicWrite(/* use remembered characteristic */ nullptr); EXPECT_TRUE("Did not crash!"); } -#endif // defined(OS_ANDROID) +#endif // defined(OS_ANDROID) || defined(OS_WIN) -#if defined(OS_ANDROID) +#if defined(OS_ANDROID) || defined(OS_WIN) // Tests ReadRemoteCharacteristic and GetValue with non-empty value buffer. TEST_F(BluetoothGattCharacteristicTest, ReadRemoteCharacteristic) { - ASSERT_NO_FATAL_FAILURE(FakeCharacteristicBoilerplate()); + ASSERT_NO_FATAL_FAILURE(FakeCharacteristicBoilerplate( + BluetoothGattCharacteristic::PROPERTY_READ)); characteristic1_->ReadRemoteCharacteristic( GetReadValueCallback(Call::EXPECTED), @@ -359,12 +364,13 @@ TEST_F(BluetoothGattCharacteristicTest, ReadRemoteCharacteristic) { EXPECT_EQ(test_vector, last_read_value_); EXPECT_EQ(test_vector, characteristic1_->GetValue()); } -#endif // defined(OS_ANDROID) +#endif // defined(OS_ANDROID) || defined(OS_WIN) -#if defined(OS_ANDROID) +#if defined(OS_ANDROID) || defined(OS_WIN) // Tests WriteRemoteCharacteristic with non-empty value buffer. TEST_F(BluetoothGattCharacteristicTest, WriteRemoteCharacteristic) { - ASSERT_NO_FATAL_FAILURE(FakeCharacteristicBoilerplate()); + ASSERT_NO_FATAL_FAILURE(FakeCharacteristicBoilerplate( + BluetoothGattCharacteristic::PROPERTY_WRITE)); uint8_t values[] = {0, 1, 2, 3, 4, 0xf, 0xf0, 0xff}; std::vector test_vector(values, values + arraysize(values)); @@ -377,12 +383,13 @@ TEST_F(BluetoothGattCharacteristicTest, WriteRemoteCharacteristic) { EXPECT_EQ(test_vector, last_write_value_); } -#endif // defined(OS_ANDROID) +#endif // defined(OS_ANDROID) || defined(OS_WIN) -#if defined(OS_ANDROID) +#if defined(OS_ANDROID) || defined(OS_WIN) // Tests ReadRemoteCharacteristic and GetValue multiple times. TEST_F(BluetoothGattCharacteristicTest, ReadRemoteCharacteristic_Twice) { - ASSERT_NO_FATAL_FAILURE(FakeCharacteristicBoilerplate()); + ASSERT_NO_FATAL_FAILURE(FakeCharacteristicBoilerplate( + BluetoothGattCharacteristic::PROPERTY_READ)); characteristic1_->ReadRemoteCharacteristic( GetReadValueCallback(Call::EXPECTED), @@ -410,12 +417,13 @@ TEST_F(BluetoothGattCharacteristicTest, ReadRemoteCharacteristic_Twice) { EXPECT_EQ(empty_vector, last_read_value_); EXPECT_EQ(empty_vector, characteristic1_->GetValue()); } -#endif // defined(OS_ANDROID) +#endif // defined(OS_ANDROID) || defined(OS_WIN) -#if defined(OS_ANDROID) +#if defined(OS_ANDROID) || defined(OS_WIN) // Tests WriteRemoteCharacteristic multiple times. TEST_F(BluetoothGattCharacteristicTest, WriteRemoteCharacteristic_Twice) { - ASSERT_NO_FATAL_FAILURE(FakeCharacteristicBoilerplate()); + ASSERT_NO_FATAL_FAILURE(FakeCharacteristicBoilerplate( + BluetoothGattCharacteristic::PROPERTY_WRITE)); uint8_t values[] = {0, 1, 2, 3, 4, 0xf, 0xf0, 0xff}; std::vector test_vector(values, values + arraysize(values)); @@ -441,13 +449,14 @@ TEST_F(BluetoothGattCharacteristicTest, WriteRemoteCharacteristic_Twice) { EXPECT_EQ(0, error_callback_count_); EXPECT_EQ(empty_vector, last_write_value_); } -#endif // defined(OS_ANDROID) +#endif // defined(OS_ANDROID) || defined(OS_WIN) -#if defined(OS_ANDROID) +#if defined(OS_ANDROID) || defined(OS_WIN) // Tests ReadRemoteCharacteristic on two characteristics. TEST_F(BluetoothGattCharacteristicTest, ReadRemoteCharacteristic_MultipleCharacteristics) { - ASSERT_NO_FATAL_FAILURE(FakeCharacteristicBoilerplate()); + ASSERT_NO_FATAL_FAILURE(FakeCharacteristicBoilerplate( + BluetoothGattCharacteristic::PROPERTY_READ)); characteristic1_->ReadRemoteCharacteristic( GetReadValueCallback(Call::EXPECTED), @@ -474,44 +483,59 @@ TEST_F(BluetoothGattCharacteristicTest, EXPECT_EQ(test_vector1, characteristic1_->GetValue()); EXPECT_EQ(test_vector2, characteristic2_->GetValue()); } -#endif // defined(OS_ANDROID) +#endif // defined(OS_ANDROID) || defined(OS_WIN) -#if defined(OS_ANDROID) +#if defined(OS_ANDROID) || defined(OS_WIN) // Tests WriteRemoteCharacteristic on two characteristics. TEST_F(BluetoothGattCharacteristicTest, WriteRemoteCharacteristic_MultipleCharacteristics) { - ASSERT_NO_FATAL_FAILURE(FakeCharacteristicBoilerplate()); + ASSERT_NO_FATAL_FAILURE(FakeCharacteristicBoilerplate( + BluetoothGattCharacteristic::PROPERTY_WRITE)); std::vector test_vector1; test_vector1.push_back(111); characteristic1_->WriteRemoteCharacteristic( test_vector1, GetCallback(Call::EXPECTED), GetGattErrorCallback(Call::NOT_EXPECTED)); +#ifdef OS_ANDROID EXPECT_EQ(test_vector1, last_write_value_); +#endif std::vector test_vector2; test_vector2.push_back(222); characteristic2_->WriteRemoteCharacteristic( test_vector2, GetCallback(Call::EXPECTED), GetGattErrorCallback(Call::NOT_EXPECTED)); +#ifdef OS_ANDROID EXPECT_EQ(test_vector2, last_write_value_); +#endif EXPECT_EQ(2, gatt_write_characteristic_attempts_); EXPECT_EQ(0, callback_count_); EXPECT_EQ(0, error_callback_count_); SimulateGattCharacteristicWrite(characteristic1_); +#ifndef OS_ANDROID + EXPECT_EQ(test_vector1, last_write_value_); +#endif + SimulateGattCharacteristicWrite(characteristic2_); +#ifndef OS_ANDROID + EXPECT_EQ(test_vector2, last_write_value_); +#endif EXPECT_EQ(2, callback_count_); EXPECT_EQ(0, error_callback_count_); + + // TODO(crbug.com/591740): Remove if define for OS_ANDROID in this test. } -#endif // defined(OS_ANDROID) +#endif // defined(OS_ANDROID) || defined(OS_WIN) -#if defined(OS_ANDROID) +#if defined(OS_ANDROID) || defined(OS_WIN) // Tests ReadRemoteCharacteristic asynchronous error. TEST_F(BluetoothGattCharacteristicTest, ReadError) { - ASSERT_NO_FATAL_FAILURE(FakeCharacteristicBoilerplate()); + ASSERT_NO_FATAL_FAILURE(FakeCharacteristicBoilerplate( + BluetoothGattCharacteristic::PROPERTY_READ)); characteristic1_->ReadRemoteCharacteristic( GetReadValueCallback(Call::NOT_EXPECTED), @@ -523,12 +547,13 @@ TEST_F(BluetoothGattCharacteristicTest, ReadError) { EXPECT_EQ(BluetoothGattService::GATT_ERROR_INVALID_LENGTH, last_gatt_error_code_); } -#endif // defined(OS_ANDROID) +#endif // defined(OS_ANDROID) || defined(OS_WIN) -#if defined(OS_ANDROID) +#if defined(OS_ANDROID) || defined(OS_WIN) // Tests WriteRemoteCharacteristic asynchronous error. TEST_F(BluetoothGattCharacteristicTest, WriteError) { - ASSERT_NO_FATAL_FAILURE(FakeCharacteristicBoilerplate()); + ASSERT_NO_FATAL_FAILURE(FakeCharacteristicBoilerplate( + BluetoothGattCharacteristic::PROPERTY_WRITE)); std::vector empty_vector; characteristic1_->WriteRemoteCharacteristic( @@ -542,7 +567,7 @@ TEST_F(BluetoothGattCharacteristicTest, WriteError) { EXPECT_EQ(BluetoothGattService::GATT_ERROR_INVALID_LENGTH, last_gatt_error_code_); } -#endif // defined(OS_ANDROID) +#endif // defined(OS_ANDROID) || defined(OS_WIN) #if defined(OS_ANDROID) // Tests ReadRemoteCharacteristic synchronous error. @@ -600,10 +625,11 @@ TEST_F(BluetoothGattCharacteristicTest, WriteSynchronousError) { } #endif // defined(OS_ANDROID) -#if defined(OS_ANDROID) +#if defined(OS_ANDROID) || defined(OS_WIN) // Tests ReadRemoteCharacteristic error with a pending read operation. TEST_F(BluetoothGattCharacteristicTest, ReadRemoteCharacteristic_ReadPending) { - ASSERT_NO_FATAL_FAILURE(FakeCharacteristicBoilerplate()); + ASSERT_NO_FATAL_FAILURE(FakeCharacteristicBoilerplate( + BluetoothGattCharacteristic::PROPERTY_READ)); characteristic1_->ReadRemoteCharacteristic( GetReadValueCallback(Call::EXPECTED), @@ -626,13 +652,14 @@ TEST_F(BluetoothGattCharacteristicTest, ReadRemoteCharacteristic_ReadPending) { EXPECT_EQ(1, callback_count_); EXPECT_EQ(0, error_callback_count_); } -#endif // defined(OS_ANDROID) +#endif // defined(OS_ANDROID) || defined(OS_WIN) -#if defined(OS_ANDROID) +#if defined(OS_ANDROID) || defined(OS_WIN) // Tests WriteRemoteCharacteristic error with a pending write operation. TEST_F(BluetoothGattCharacteristicTest, WriteRemoteCharacteristic_WritePending) { - ASSERT_NO_FATAL_FAILURE(FakeCharacteristicBoilerplate()); + ASSERT_NO_FATAL_FAILURE(FakeCharacteristicBoilerplate( + BluetoothGattCharacteristic::PROPERTY_WRITE)); std::vector empty_vector; characteristic1_->WriteRemoteCharacteristic( @@ -655,12 +682,14 @@ TEST_F(BluetoothGattCharacteristicTest, EXPECT_EQ(1, callback_count_); EXPECT_EQ(0, error_callback_count_); } -#endif // defined(OS_ANDROID) +#endif // defined(OS_ANDROID) || defined(OS_WIN) -#if defined(OS_ANDROID) +#if defined(OS_ANDROID) || defined(OS_WIN) // Tests ReadRemoteCharacteristic error with a pending write operation. TEST_F(BluetoothGattCharacteristicTest, ReadRemoteCharacteristic_WritePending) { - ASSERT_NO_FATAL_FAILURE(FakeCharacteristicBoilerplate()); + ASSERT_NO_FATAL_FAILURE(FakeCharacteristicBoilerplate( + BluetoothGattCharacteristic::PROPERTY_READ | + BluetoothGattCharacteristic::PROPERTY_WRITE)); std::vector empty_vector; characteristic1_->WriteRemoteCharacteristic( @@ -683,12 +712,14 @@ TEST_F(BluetoothGattCharacteristicTest, ReadRemoteCharacteristic_WritePending) { EXPECT_EQ(1, callback_count_); EXPECT_EQ(0, error_callback_count_); } -#endif // defined(OS_ANDROID) +#endif // defined(OS_ANDROID) || defined(OS_WIN) -#if defined(OS_ANDROID) +#if defined(OS_ANDROID) || defined(OS_WIN) // Tests WriteRemoteCharacteristic error with a pending Read operation. TEST_F(BluetoothGattCharacteristicTest, WriteRemoteCharacteristic_ReadPending) { - ASSERT_NO_FATAL_FAILURE(FakeCharacteristicBoilerplate()); + ASSERT_NO_FATAL_FAILURE(FakeCharacteristicBoilerplate( + BluetoothGattCharacteristic::PROPERTY_READ | + BluetoothGattCharacteristic::PROPERTY_WRITE)); std::vector empty_vector; characteristic1_->ReadRemoteCharacteristic( @@ -710,7 +741,7 @@ TEST_F(BluetoothGattCharacteristicTest, WriteRemoteCharacteristic_ReadPending) { EXPECT_EQ(1, callback_count_); EXPECT_EQ(0, error_callback_count_); } -#endif // defined(OS_ANDROID) +#endif // defined(OS_ANDROID) || defined(OS_WIN) #if defined(OS_ANDROID) // StartNotifySession fails if characteristic doesn't have Notify or Indicate diff --git a/device/bluetooth/bluetooth_low_energy_win.cc b/device/bluetooth/bluetooth_low_energy_win.cc index f2830cf..92c9a97 100644 --- a/device/bluetooth/bluetooth_low_energy_win.cc +++ b/device/bluetooth/bluetooth_low_energy_win.cc @@ -789,5 +789,53 @@ HRESULT BluetoothLowEnergyWrapper::ReadDescriptorsOfACharacteristic( return hr; } +HRESULT BluetoothLowEnergyWrapper::ReadCharacteristicValue( + base::FilePath& service_path, + const PBTH_LE_GATT_CHARACTERISTIC characteristic, + scoped_ptr* out_value) { + base::File file(service_path, base::File::FLAG_OPEN | base::File::FLAG_READ); + if (!file.IsValid()) + return HRESULT_FROM_WIN32(ERROR_OPEN_FAILED); + + USHORT allocated_length = 0; + HRESULT hr = BluetoothGATTGetCharacteristicValue( + file.GetPlatformFile(), characteristic, 0, NULL, &allocated_length, + BLUETOOTH_GATT_FLAG_NONE); + if (hr != HRESULT_FROM_WIN32(ERROR_MORE_DATA)) + return hr; + + out_value->reset( + (PBTH_LE_GATT_CHARACTERISTIC_VALUE)(new UCHAR[allocated_length])); + USHORT out_length = 0; + hr = BluetoothGATTGetCharacteristicValue( + file.GetPlatformFile(), characteristic, (ULONG)allocated_length, + out_value->get(), &out_length, BLUETOOTH_GATT_FLAG_NONE); + if (SUCCEEDED(hr) && allocated_length != out_length) { + LOG(ERROR) << "Retrieved characteristic value size is not equal to expected" + << " allocated_length " << allocated_length << " got " + << out_length; + hr = HRESULT_FROM_WIN32(ERROR_INVALID_USER_BUFFER); + } + + if (FAILED(hr)) { + out_value->reset(nullptr); + } + return hr; +} + +HRESULT BluetoothLowEnergyWrapper::WriteCharacteristicValue( + base::FilePath& service_path, + const PBTH_LE_GATT_CHARACTERISTIC characteristic, + PBTH_LE_GATT_CHARACTERISTIC_VALUE new_value) { + base::File file(service_path, base::File::FLAG_OPEN | base::File::FLAG_READ | + base::File::FLAG_WRITE); + if (!file.IsValid()) + return HRESULT_FROM_WIN32(ERROR_OPEN_FAILED); + + return BluetoothGATTSetCharacteristicValue(file.GetPlatformFile(), + characteristic, new_value, NULL, + BLUETOOTH_GATT_FLAG_NONE); +} + } // namespace win } // namespace device diff --git a/device/bluetooth/bluetooth_low_energy_win.h b/device/bluetooth/bluetooth_low_energy_win.h index b7d378a..cd7150d 100644 --- a/device/bluetooth/bluetooth_low_energy_win.h +++ b/device/bluetooth/bluetooth_low_energy_win.h @@ -162,6 +162,20 @@ class DEVICE_BLUETOOTH_EXPORT BluetoothLowEnergyWrapper { scoped_ptr* out_included_descriptors, USHORT* out_counts); + // Reads |characteristic| value in service with service device path + // |service_path|. The result will be stored in |*out_value|. + virtual HRESULT ReadCharacteristicValue( + base::FilePath& service_path, + const PBTH_LE_GATT_CHARACTERISTIC characteristic, + scoped_ptr* out_value); + + // Writes |characteristic| value in service with service device path + // |service_path| to |*new_value|. + virtual HRESULT WriteCharacteristicValue( + base::FilePath& service_path, + const PBTH_LE_GATT_CHARACTERISTIC characteristic, + PBTH_LE_GATT_CHARACTERISTIC_VALUE new_value); + protected: BluetoothLowEnergyWrapper(); virtual ~BluetoothLowEnergyWrapper(); diff --git a/device/bluetooth/bluetooth_low_energy_win_fake.cc b/device/bluetooth/bluetooth_low_energy_win_fake.cc index d6fb5f0..548286d 100644 --- a/device/bluetooth/bluetooth_low_energy_win_fake.cc +++ b/device/bluetooth/bluetooth_low_energy_win_fake.cc @@ -27,7 +27,8 @@ GattCharacteristic::~GattCharacteristic() {} GattDescriptor::GattDescriptor() {} GattDescriptor::~GattDescriptor() {} -BluetoothLowEnergyWrapperFake::BluetoothLowEnergyWrapperFake() {} +BluetoothLowEnergyWrapperFake::BluetoothLowEnergyWrapperFake() + : observer_(nullptr) {} BluetoothLowEnergyWrapperFake::~BluetoothLowEnergyWrapperFake() {} bool BluetoothLowEnergyWrapperFake::IsBluetoothLowEnergySupported() { @@ -127,12 +128,14 @@ HRESULT BluetoothLowEnergyWrapperFake::ReadCharacteristicsOfAService( USHORT* out_counts) { base::string16 device_address = ExtractDeviceAddressFromDevicePath(service_path.value()); + BLEDevice* target_device = GetSimulatedBLEDevice( + std::string(device_address.begin(), device_address.end())); + if (target_device == nullptr) + return HRESULT_FROM_WIN32(ERROR_NOT_FOUND); const std::vector service_att_handles = ExtractServiceAttributeHandlesFromDevicePath(service_path.value()); - GattService* target_service = GetSimulatedGattService( - GetSimulatedBLEDevice( - std::string(device_address.begin(), device_address.end())), - service_att_handles); + GattService* target_service = + GetSimulatedGattService(target_device, service_att_handles); if (target_service == nullptr) return HRESULT_FROM_WIN32(ERROR_NOT_FOUND); @@ -177,6 +180,62 @@ HRESULT BluetoothLowEnergyWrapperFake::ReadDescriptorsOfACharacteristic( return S_OK; } +HRESULT BluetoothLowEnergyWrapperFake::ReadCharacteristicValue( + base::FilePath& service_path, + const PBTH_LE_GATT_CHARACTERISTIC characteristic, + scoped_ptr* out_value) { + GattCharacteristic* target_characteristic = + GetSimulatedGattCharacteristic(service_path, characteristic); + if (target_characteristic == nullptr) + return HRESULT_FROM_WIN32(ERROR_NOT_FOUND); + + // Return error simulated by SimulateGattCharacteristicReadError. + if (target_characteristic->read_errors.size()) { + HRESULT hr = target_characteristic->read_errors[0]; + target_characteristic->read_errors.erase( + target_characteristic->read_errors.begin()); + return hr; + } + + PBTH_LE_GATT_CHARACTERISTIC_VALUE ret_value = + (PBTH_LE_GATT_CHARACTERISTIC_VALUE)( + new UCHAR[sizeof(ULONG) + target_characteristic->value->DataSize]); + ret_value->DataSize = target_characteristic->value->DataSize; + for (ULONG i = 0; i < ret_value->DataSize; i++) + ret_value->Data[i] = target_characteristic->value->Data[i]; + out_value->reset(ret_value); + return S_OK; +} + +HRESULT BluetoothLowEnergyWrapperFake::WriteCharacteristicValue( + base::FilePath& service_path, + const PBTH_LE_GATT_CHARACTERISTIC characteristic, + PBTH_LE_GATT_CHARACTERISTIC_VALUE new_value) { + GattCharacteristic* target_characteristic = + GetSimulatedGattCharacteristic(service_path, characteristic); + if (target_characteristic == nullptr) + return ERROR_NOT_FOUND; + + // Return error simulated by SimulateGattCharacteristicWriteError. + if (target_characteristic->write_errors.size()) { + HRESULT hr = *(target_characteristic->write_errors.begin()); + target_characteristic->write_errors.erase( + target_characteristic->write_errors.begin()); + return hr; + } + + PBTH_LE_GATT_CHARACTERISTIC_VALUE win_value = + (PBTH_LE_GATT_CHARACTERISTIC_VALUE)( + new UCHAR[new_value->DataSize + sizeof(ULONG)]); + for (ULONG i = 0; i < new_value->DataSize; i++) + win_value->Data[i] = new_value->Data[i]; + win_value->DataSize = new_value->DataSize; + target_characteristic->value.reset(win_value); + if (observer_) + observer_->onWriteGattCharacteristicValue(win_value); + return S_OK; +} + BLEDevice* BluetoothLowEnergyWrapperFake::SimulateBLEDevice( std::string device_name, BLUETOOTH_ADDRESS device_address) { @@ -202,6 +261,11 @@ BLEDevice* BluetoothLowEnergyWrapperFake::GetSimulatedBLEDevice( return it_d->second.get(); } +void BluetoothLowEnergyWrapperFake::RemoveSimulatedBLEDevice( + std::string device_address) { + simulated_devices_.erase(device_address); +} + GattService* BluetoothLowEnergyWrapperFake::SimulateGattService( BLEDevice* device, GattService* parent_service, @@ -300,6 +364,33 @@ BluetoothLowEnergyWrapperFake::GetSimulatedGattCharacteristic( return nullptr; } +void BluetoothLowEnergyWrapperFake::SimulateGattCharacteristicValue( + GattCharacteristic* characteristic, + const std::vector& value) { + CHECK(characteristic); + PBTH_LE_GATT_CHARACTERISTIC_VALUE win_value = + (PBTH_LE_GATT_CHARACTERISTIC_VALUE)( + new UCHAR[value.size() + sizeof(ULONG)]); + win_value->DataSize = (ULONG)value.size(); + for (std::size_t i = 0; i < value.size(); i++) + win_value->Data[i] = value[i]; + characteristic->value.reset(win_value); +} + +void BluetoothLowEnergyWrapperFake::SimulateGattCharacteristicReadError( + GattCharacteristic* characteristic, + HRESULT error) { + CHECK(characteristic); + characteristic->read_errors.push_back(error); +} + +void BluetoothLowEnergyWrapperFake::SimulateGattCharacteristicWriteError( + GattCharacteristic* characteristic, + HRESULT error) { + CHECK(characteristic); + characteristic->write_errors.push_back(error); +} + void BluetoothLowEnergyWrapperFake::SimulateGattDescriptor( std::string device_address, GattCharacteristic* characteristic, @@ -313,6 +404,10 @@ void BluetoothLowEnergyWrapperFake::SimulateGattDescriptor( descriptor->descriptor_info->AttributeHandle)] = std::move(descriptor); } +void BluetoothLowEnergyWrapperFake::AddObserver(Observer* observer) { + observer_ = observer; +} + GattCharacteristic* BluetoothLowEnergyWrapperFake::GetSimulatedGattCharacteristic( base::FilePath& service_path, diff --git a/device/bluetooth/bluetooth_low_energy_win_fake.h b/device/bluetooth/bluetooth_low_energy_win_fake.h index f21fa5a..46b5631 100644 --- a/device/bluetooth/bluetooth_low_energy_win_fake.h +++ b/device/bluetooth/bluetooth_low_energy_win_fake.h @@ -53,6 +53,8 @@ struct GattCharacteristic { scoped_ptr characteristic_info; scoped_ptr value; GattDescriptorsMap included_descriptors; + std::vector read_errors; + std::vector write_errors; }; struct GattDescriptor { @@ -65,6 +67,15 @@ struct GattDescriptor { // Fake implementation of BluetoothLowEnergyWrapper. Used for BluetoothTestWin. class BluetoothLowEnergyWrapperFake : public BluetoothLowEnergyWrapper { public: + class Observer { + public: + Observer() {} + ~Observer() {} + + virtual void onWriteGattCharacteristicValue( + const PBTH_LE_GATT_CHARACTERISTIC_VALUE value) = 0; + }; + BluetoothLowEnergyWrapperFake(); ~BluetoothLowEnergyWrapperFake() override; @@ -89,10 +100,19 @@ class BluetoothLowEnergyWrapperFake : public BluetoothLowEnergyWrapper { const PBTH_LE_GATT_CHARACTERISTIC characteristic, scoped_ptr* out_included_descriptors, USHORT* out_counts) override; + HRESULT ReadCharacteristicValue( + base::FilePath& service_path, + const PBTH_LE_GATT_CHARACTERISTIC characteristic, + scoped_ptr* out_value) override; + HRESULT WriteCharacteristicValue( + base::FilePath& service_path, + const PBTH_LE_GATT_CHARACTERISTIC characteristic, + PBTH_LE_GATT_CHARACTERISTIC_VALUE new_value) override; BLEDevice* SimulateBLEDevice(std::string device_name, BLUETOOTH_ADDRESS device_address); BLEDevice* GetSimulatedBLEDevice(std::string device_address); + void RemoveSimulatedBLEDevice(std::string device_address); // Note: |parent_service| may be nullptr to indicate a primary service. GattService* SimulateGattService(BLEDevice* device, @@ -119,9 +139,16 @@ class BluetoothLowEnergyWrapperFake : public BluetoothLowEnergyWrapper { GattCharacteristic* GetSimulatedGattCharacteristic( GattService* parent_service, std::string attribute_handle); + void SimulateGattCharacteristicValue(GattCharacteristic* characteristic, + const std::vector& value); + void SimulateGattCharacteristicReadError(GattCharacteristic* characteristic, + HRESULT error); + void SimulateGattCharacteristicWriteError(GattCharacteristic* characteristic, + HRESULT error); void SimulateGattDescriptor(std::string device_address, GattCharacteristic* characteristic, const BTH_LE_UUID& uuid); + void AddObserver(Observer* observer); private: // Get simulated characteristic by |service_path| and |characteristic| info. @@ -158,6 +185,7 @@ class BluetoothLowEnergyWrapperFake : public BluetoothLowEnergyWrapper { // Table to store allocated attribute handle for a device. BLEAttributeHandleTable attribute_handle_table_; BLEDevicesMap simulated_devices_; + Observer* observer_; }; } // namespace win diff --git a/device/bluetooth/bluetooth_remote_gatt_characteristic_win.cc b/device/bluetooth/bluetooth_remote_gatt_characteristic_win.cc index baf4a73..d98c0ea 100644 --- a/device/bluetooth/bluetooth_remote_gatt_characteristic_win.cc +++ b/device/bluetooth/bluetooth_remote_gatt_characteristic_win.cc @@ -20,6 +20,7 @@ BluetoothRemoteGattCharacteristicWin::BluetoothRemoteGattCharacteristicWin( characteristic_info_(characteristic_info), ui_task_runner_(ui_task_runner), characteristic_added_notified_(false), + characteristic_value_read_or_write_in_progress_(false), weak_ptr_factory_(this) { DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); DCHECK(parent_service_); @@ -56,7 +57,6 @@ bool BluetoothRemoteGattCharacteristicWin::IsLocal() const { } std::vector& BluetoothRemoteGattCharacteristicWin::GetValue() const { - NOTIMPLEMENTED(); return const_cast&>(characteristic_value_); } @@ -147,16 +147,52 @@ void BluetoothRemoteGattCharacteristicWin::StartNotifySession( void BluetoothRemoteGattCharacteristicWin::ReadRemoteCharacteristic( const ValueCallback& callback, const ErrorCallback& error_callback) { - NOTIMPLEMENTED(); - error_callback.Run(BluetoothGattService::GATT_ERROR_NOT_SUPPORTED); + DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); + + if (!characteristic_info_.get()->IsReadable) { + error_callback.Run(BluetoothGattService::GATT_ERROR_NOT_PERMITTED); + return; + } + + if (characteristic_value_read_or_write_in_progress_) { + error_callback.Run(BluetoothGattService::GATT_ERROR_IN_PROGRESS); + return; + } + + characteristic_value_read_or_write_in_progress_ = true; + read_characteristic_value_callbacks_ = + std::make_pair(callback, error_callback); + task_manager_->PostReadGattCharacteristicValue( + parent_service_->GetServicePath(), characteristic_info_.get(), + base::Bind(&BluetoothRemoteGattCharacteristicWin:: + OnReadRemoteCharacteristicValueCallback, + weak_ptr_factory_.GetWeakPtr())); } void BluetoothRemoteGattCharacteristicWin::WriteRemoteCharacteristic( const std::vector& new_value, const base::Closure& callback, const ErrorCallback& error_callback) { - NOTIMPLEMENTED(); - error_callback.Run(BluetoothGattService::GATT_ERROR_NOT_SUPPORTED); + DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); + + if (!characteristic_info_.get()->IsWritable) { + error_callback.Run(BluetoothGattService::GATT_ERROR_NOT_PERMITTED); + return; + } + + if (characteristic_value_read_or_write_in_progress_) { + error_callback.Run(BluetoothGattService::GATT_ERROR_IN_PROGRESS); + return; + } + + characteristic_value_read_or_write_in_progress_ = true; + write_characteristic_value_callbacks_ = + std::make_pair(callback, error_callback); + task_manager_->PostWriteGattCharacteristicValue( + parent_service_->GetServicePath(), characteristic_info_.get(), new_value, + base::Bind(&BluetoothRemoteGattCharacteristicWin:: + OnWriteRemoteCharacteristicValueCallback, + weak_ptr_factory_.GetWeakPtr())); } void BluetoothRemoteGattCharacteristicWin::Update() { @@ -253,4 +289,53 @@ bool BluetoothRemoteGattCharacteristicWin::DoesDescriptorExist( return false; } +void BluetoothRemoteGattCharacteristicWin:: + OnReadRemoteCharacteristicValueCallback( + scoped_ptr value, + HRESULT hr) { + DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); + + std::pair callbacks; + callbacks.swap(read_characteristic_value_callbacks_); + if (FAILED(hr)) { + callbacks.second.Run(HRESULTToGattErrorCode(hr)); + } else { + characteristic_value_.clear(); + for (ULONG i = 0; i < value->DataSize; i++) + characteristic_value_.push_back(value->Data[i]); + callbacks.first.Run(characteristic_value_); + } + characteristic_value_read_or_write_in_progress_ = false; +} + +void BluetoothRemoteGattCharacteristicWin:: + OnWriteRemoteCharacteristicValueCallback(HRESULT hr) { + DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); + + std::pair callbacks; + callbacks.swap(write_characteristic_value_callbacks_); + if (FAILED(hr)) { + callbacks.second.Run(HRESULTToGattErrorCode(hr)); + } else { + callbacks.first.Run(); + } + characteristic_value_read_or_write_in_progress_ = false; +} + +BluetoothGattService::GattErrorCode +BluetoothRemoteGattCharacteristicWin::HRESULTToGattErrorCode(HRESULT hr) { + switch (hr) { + case E_BLUETOOTH_ATT_READ_NOT_PERMITTED: + case E_BLUETOOTH_ATT_WRITE_NOT_PERMITTED: + return BluetoothGattService::GATT_ERROR_NOT_PERMITTED; + case E_BLUETOOTH_ATT_UNKNOWN_ERROR: + return BluetoothGattService::GATT_ERROR_UNKNOWN; + case ERROR_INVALID_USER_BUFFER: + case E_BLUETOOTH_ATT_INVALID_ATTRIBUTE_VALUE_LENGTH: + return BluetoothGattService::GATT_ERROR_INVALID_LENGTH; + default: + return BluetoothGattService::GATT_ERROR_FAILED; + } +} + } // namespace device. diff --git a/device/bluetooth/bluetooth_remote_gatt_characteristic_win.h b/device/bluetooth/bluetooth_remote_gatt_characteristic_win.h index 9860116..bf37ccc 100644 --- a/device/bluetooth/bluetooth_remote_gatt_characteristic_win.h +++ b/device/bluetooth/bluetooth_remote_gatt_characteristic_win.h @@ -75,6 +75,12 @@ class DEVICE_BLUETOOTH_EXPORT BluetoothRemoteGattCharacteristicWin uint16_t num, BluetoothRemoteGattDescriptorWin* descriptor); + void OnReadRemoteCharacteristicValueCallback( + scoped_ptr value, + HRESULT hr); + void OnWriteRemoteCharacteristicValueCallback(HRESULT hr); + BluetoothGattService::GattErrorCode HRESULTToGattErrorCode(HRESULT hr); + BluetoothRemoteGattServiceWin* parent_service_; scoped_refptr task_manager_; @@ -96,6 +102,14 @@ class DEVICE_BLUETOOTH_EXPORT BluetoothRemoteGattCharacteristicWin // has been sent out to avoid duplicate notification. bool characteristic_added_notified_; + // ReadRemoteCharacteristic request callbacks. + std::pair read_characteristic_value_callbacks_; + + // WriteRemoteCharacteristic request callbacks. + std::pair write_characteristic_value_callbacks_; + + bool characteristic_value_read_or_write_in_progress_; + base::WeakPtrFactory weak_ptr_factory_; DISALLOW_COPY_AND_ASSIGN(BluetoothRemoteGattCharacteristicWin); }; diff --git a/device/bluetooth/bluetooth_task_manager_win.cc b/device/bluetooth/bluetooth_task_manager_win.cc index c45f022..bcb3823 100644 --- a/device/bluetooth/bluetooth_task_manager_win.cc +++ b/device/bluetooth/bluetooth_task_manager_win.cc @@ -809,6 +809,41 @@ void BluetoothTaskManagerWin::GetGattIncludedDescriptors( number_of_descriptors, hr)); } +void BluetoothTaskManagerWin::ReadGattCharacteristicValue( + base::FilePath service_path, + BTH_LE_GATT_CHARACTERISTIC characteristic, + const ReadGattCharacteristicValueCallback& callback) { + scoped_ptr win_characteristic_value; + HRESULT hr = + win::BluetoothLowEnergyWrapper::GetInstance()->ReadCharacteristicValue( + service_path, (PBTH_LE_GATT_CHARACTERISTIC)(&characteristic), + &win_characteristic_value); + + ui_task_runner_->PostTask( + FROM_HERE, + base::Bind(callback, base::Passed(&win_characteristic_value), hr)); +} + +void BluetoothTaskManagerWin::WriteGattCharacteristicValue( + base::FilePath service_path, + BTH_LE_GATT_CHARACTERISTIC characteristic, + std::vector new_value, + const HResultCallback& callback) { + ULONG length = (ULONG)(sizeof(ULONG) + new_value.size()); + scoped_ptr win_new_value( + (PBTH_LE_GATT_CHARACTERISTIC_VALUE)(new UCHAR[length])); + win_new_value->DataSize = (ULONG)new_value.size(); + for (ULONG i = 0; i < new_value.size(); i++) + win_new_value->Data[i] = new_value[i]; + + HRESULT hr = + win::BluetoothLowEnergyWrapper::GetInstance()->WriteCharacteristicValue( + service_path, (PBTH_LE_GATT_CHARACTERISTIC)(&characteristic), + win_new_value.get()); + + ui_task_runner_->PostTask(FROM_HERE, base::Bind(callback, hr)); +} + void BluetoothTaskManagerWin::PostGetGattIncludedCharacteristics( const base::FilePath& service_path, const BluetoothUUID& uuid, @@ -832,4 +867,31 @@ void BluetoothTaskManagerWin::PostGetGattIncludedDescriptors( service_path, *characteristic, callback)); } +void BluetoothTaskManagerWin::PostReadGattCharacteristicValue( + const base::FilePath& service_path, + const PBTH_LE_GATT_CHARACTERISTIC characteristic, + const ReadGattCharacteristicValueCallback& callback) { + DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); + bluetooth_task_runner_->PostTask( + FROM_HERE, + base::Bind(&BluetoothTaskManagerWin::ReadGattCharacteristicValue, this, + service_path, *characteristic, callback)); + FOR_EACH_OBSERVER(BluetoothTaskManagerWin::Observer, observers_, + OnAttemptReadGattCharacteristic()); +} + +void BluetoothTaskManagerWin::PostWriteGattCharacteristicValue( + const base::FilePath& service_path, + const PBTH_LE_GATT_CHARACTERISTIC characteristic, + const std::vector& new_value, + const HResultCallback& callback) { + DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); + bluetooth_task_runner_->PostTask( + FROM_HERE, + base::Bind(&BluetoothTaskManagerWin::WriteGattCharacteristicValue, this, + service_path, *characteristic, new_value, callback)); + FOR_EACH_OBSERVER(BluetoothTaskManagerWin::Observer, observers_, + OnAttemptWriteGattCharacteristic()); +} + } // namespace device diff --git a/device/bluetooth/bluetooth_task_manager_win.h b/device/bluetooth/bluetooth_task_manager_win.h index 35d22cd..c8356a8 100644 --- a/device/bluetooth/bluetooth_task_manager_win.h +++ b/device/bluetooth/bluetooth_task_manager_win.h @@ -99,6 +99,8 @@ class DEVICE_BLUETOOTH_EXPORT BluetoothTaskManagerWin // discovery session, the "friendly" name may initially be "unknown" before // the actual name is retrieved in subsequent poll events. virtual void DevicesPolled(const ScopedVector& devices) {} + virtual void OnAttemptReadGattCharacteristic() {} + virtual void OnAttemptWriteGattCharacteristic() {} }; explicit BluetoothTaskManagerWin( @@ -123,12 +125,16 @@ class DEVICE_BLUETOOTH_EXPORT BluetoothTaskManagerWin void PostStopDiscoveryTask(); // Callbacks of asynchronous operations of GATT service. + typedef base::Callback HResultCallback; typedef base::Callback< void(scoped_ptr, uint16_t, HRESULT)> GetGattIncludedCharacteristicsCallback; typedef base::Callback< void(scoped_ptr, uint16_t, HRESULT)> GetGattIncludedDescriptorsCallback; + typedef base::Callback, + HRESULT)> + ReadGattCharacteristicValueCallback; // Get all included characteristics of a given service. The service is // uniquely identified by its |uuid| and |attribute_handle| with service @@ -148,6 +154,22 @@ class DEVICE_BLUETOOTH_EXPORT BluetoothTaskManagerWin const PBTH_LE_GATT_CHARACTERISTIC characteristic, const GetGattIncludedDescriptorsCallback& callback); + // Post read the value of a given |characteristic| in service with + // |service_path|. The result is returned asynchronously through |callback|. + void PostReadGattCharacteristicValue( + const base::FilePath& device_path, + const PBTH_LE_GATT_CHARACTERISTIC characteristic, + const ReadGattCharacteristicValueCallback& callback); + + // Post write the value of a given |characteristic| in service with + // |service_path| to |new_value|. The operation result is returned + // asynchronously through |callback|. + void PostWriteGattCharacteristicValue( + const base::FilePath& service_path, + const PBTH_LE_GATT_CHARACTERISTIC characteristic, + const std::vector& new_value, + const HResultCallback& callback); + private: friend class base::RefCountedThreadSafe; friend class BluetoothTaskManagerWinTest; @@ -248,6 +270,14 @@ class DEVICE_BLUETOOTH_EXPORT BluetoothTaskManagerWin base::FilePath service_path, BTH_LE_GATT_CHARACTERISTIC characteristic, const GetGattIncludedDescriptorsCallback& callback); + void ReadGattCharacteristicValue( + base::FilePath device_path, + BTH_LE_GATT_CHARACTERISTIC characteristic, + const ReadGattCharacteristicValueCallback& callback); + void WriteGattCharacteristicValue(base::FilePath service_path, + BTH_LE_GATT_CHARACTERISTIC characteristic, + std::vector new_value, + const HResultCallback& callback); // UI task runner reference. scoped_refptr ui_task_runner_; diff --git a/device/bluetooth/test/bluetooth_test_win.cc b/device/bluetooth/test/bluetooth_test_win.cc index 68af547..cd852aa 100644 --- a/device/bluetooth/test/bluetooth_test_win.cc +++ b/device/bluetooth/test/bluetooth_test_win.cc @@ -5,8 +5,11 @@ #include "device/bluetooth/test/bluetooth_test_win.h" #include "base/bind.h" +#include "base/location.h" #include "base/run_loop.h" #include "base/strings/sys_string_conversions.h" +#include "base/test/test_pending_task.h" +#include "base/time/time.h" #include "device/bluetooth/bluetooth_adapter_win.h" #include "device/bluetooth/bluetooth_low_energy_win.h" #include "device/bluetooth/bluetooth_remote_gatt_characteristic_win.h" @@ -99,6 +102,7 @@ void BluetoothTestWin::InitWithoutDefaultAdapter() { void BluetoothTestWin::InitWithFakeAdapter() { fake_bt_classic_wrapper_ = new win::BluetoothClassicWrapperFake(); fake_bt_le_wrapper_ = new win::BluetoothLowEnergyWrapperFake(); + fake_bt_le_wrapper_->AddObserver(this); win::BluetoothClassicWrapper::SetInstanceForTest(fake_bt_classic_wrapper_); win::BluetoothLowEnergyWrapper::SetInstanceForTest(fake_bt_le_wrapper_); fake_bt_classic_wrapper_->SimulateARadio( @@ -109,6 +113,7 @@ void BluetoothTestWin::InitWithFakeAdapter() { &BluetoothTestWin::AdapterInitCallback, base::Unretained(this))); adapter_win_ = static_cast(adapter_.get()); adapter_win_->InitForTest(nullptr, bluetooth_task_runner_); + adapter_win_->GetWinBluetoothTaskManager()->AddObserver(this); FinishPendingTasks(); } @@ -282,6 +287,71 @@ void BluetoothTestWin::SimulateGattCharacteristicRemoved( ForceRefreshDevice(); } +void BluetoothTestWin::RememberCharacteristicForSubsequentAction( + BluetoothGattCharacteristic* characteristic) { + remembered_characteristic_ = + static_cast(characteristic); +} + +void BluetoothTestWin::SimulateGattCharacteristicRead( + BluetoothGattCharacteristic* characteristic, + const std::vector& value) { + BluetoothGattCharacteristic* target_characteristic = characteristic; + if (target_characteristic == nullptr) + target_characteristic = remembered_characteristic_; + CHECK(target_characteristic); + + win::GattCharacteristic* target_simulated_characteristic = + GetSimulatedCharacteristic(target_characteristic); + if (target_simulated_characteristic == nullptr) + return; + + fake_bt_le_wrapper_->SimulateGattCharacteristicValue( + target_simulated_characteristic, value); + + RunPendingTasksUntilCallback(); +} + +void BluetoothTestWin::SimulateGattCharacteristicReadError( + BluetoothGattCharacteristic* characteristic, + BluetoothGattService::GattErrorCode error_code) { + win::GattCharacteristic* target_characteristic = + GetSimulatedCharacteristic(characteristic); + CHECK(target_characteristic); + HRESULT hr = ERROR_SEM_TIMEOUT; + if (error_code == BluetoothGattService::GATT_ERROR_INVALID_LENGTH) + hr = E_BLUETOOTH_ATT_INVALID_ATTRIBUTE_VALUE_LENGTH; + fake_bt_le_wrapper_->SimulateGattCharacteristicReadError( + target_characteristic, hr); + + FinishPendingTasks(); +} + +void BluetoothTestWin::SimulateGattCharacteristicWrite( + BluetoothGattCharacteristic* characteristic) { + RunPendingTasksUntilCallback(); +} + +void BluetoothTestWin::SimulateGattCharacteristicWriteError( + BluetoothGattCharacteristic* characteristic, + BluetoothGattService::GattErrorCode error_code) { + win::GattCharacteristic* target_characteristic = + GetSimulatedCharacteristic(characteristic); + CHECK(target_characteristic); + HRESULT hr = ERROR_SEM_TIMEOUT; + if (error_code == BluetoothGattService::GATT_ERROR_INVALID_LENGTH) + hr = E_BLUETOOTH_ATT_INVALID_ATTRIBUTE_VALUE_LENGTH; + fake_bt_le_wrapper_->SimulateGattCharacteristicWriteError( + target_characteristic, hr); + + FinishPendingTasks(); +} + +void BluetoothTestWin::DeleteDevice(BluetoothDevice* device) { + CHECK(device); + fake_bt_le_wrapper_->RemoveSimulatedBLEDevice(device->GetAddress()); +} + void BluetoothTestWin::SimulateGattDescriptor( BluetoothGattCharacteristic* characteristic, const std::string& uuid) { @@ -294,6 +364,21 @@ void BluetoothTestWin::SimulateGattDescriptor( ForceRefreshDevice(); } +void BluetoothTestWin::OnAttemptReadGattCharacteristic() { + gatt_read_characteristic_attempts_++; +} + +void BluetoothTestWin::OnAttemptWriteGattCharacteristic() { + gatt_write_characteristic_attempts_++; +} + +void BluetoothTestWin::onWriteGattCharacteristicValue( + const PBTH_LE_GATT_CHARACTERISTIC_VALUE value) { + last_write_value_.clear(); + for (ULONG i = 0; i < value->DataSize; i++) + last_write_value_.push_back(value->Data[i]); +} + win::GattService* BluetoothTestWin::GetSimulatedService( win::BLEDevice* device, BluetoothGattService* service) { @@ -333,6 +418,31 @@ win::GattCharacteristic* BluetoothTestWin::GetSimulatedCharacteristic( target_service, std::to_string(win_characteristic->GetAttributeHandle())); } +void BluetoothTestWin::RunPendingTasksUntilCallback() { + std::deque tasks = + bluetooth_task_runner_->GetPendingTasks(); + bluetooth_task_runner_->ClearPendingTasks(); + int original_callback_count = callback_count_; + int original_error_callback_count = error_callback_count_; + do { + base::TestPendingTask task = tasks.front(); + tasks.pop_front(); + task.task.Run(); + base::RunLoop().RunUntilIdle(); + } while (tasks.size() && callback_count_ == original_callback_count && + error_callback_count_ == original_error_callback_count); + + // Put the rest of pending tasks back to Bluetooth task runner. + for (const auto& task : tasks) { + if (task.delay.is_zero()) { + bluetooth_task_runner_->PostTask(task.location, task.task); + } else { + bluetooth_task_runner_->PostDelayedTask(task.location, task.task, + task.delay); + } + } +} + void BluetoothTestWin::ForceRefreshDevice() { adapter_win_->force_update_device_for_test_ = true; FinishPendingTasks(); diff --git a/device/bluetooth/test/bluetooth_test_win.h b/device/bluetooth/test/bluetooth_test_win.h index d87bacc..459b992 100644 --- a/device/bluetooth/test/bluetooth_test_win.h +++ b/device/bluetooth/test/bluetooth_test_win.h @@ -12,12 +12,16 @@ #include "base/test/test_simple_task_runner.h" #include "device/bluetooth/bluetooth_classic_win_fake.h" #include "device/bluetooth/bluetooth_low_energy_win_fake.h" +#include "device/bluetooth/bluetooth_task_manager_win.h" namespace device { class BluetoothAdapterWin; +class BluetoothRemoteGattCharacteristicWin; // Windows implementation of BluetoothTestBase. -class BluetoothTestWin : public BluetoothTestBase { +class BluetoothTestWin : public BluetoothTestBase, + public BluetoothTaskManagerWin::Observer, + public win::BluetoothLowEnergyWrapperFake::Observer { public: BluetoothTestWin(); ~BluetoothTestWin() override; @@ -41,9 +45,31 @@ class BluetoothTestWin : public BluetoothTestBase { void SimulateGattCharacteristicRemoved( BluetoothGattService* service, BluetoothGattCharacteristic* characteristic) override; + void RememberCharacteristicForSubsequentAction( + BluetoothGattCharacteristic* characteristic) override; + void SimulateGattCharacteristicRead( + BluetoothGattCharacteristic* characteristic, + const std::vector& value) override; + void SimulateGattCharacteristicReadError( + BluetoothGattCharacteristic* characteristic, + BluetoothGattService::GattErrorCode error_code) override; + void SimulateGattCharacteristicWrite( + BluetoothGattCharacteristic* characteristic) override; + void SimulateGattCharacteristicWriteError( + BluetoothGattCharacteristic* characteristic, + BluetoothGattService::GattErrorCode error_code) override; + void DeleteDevice(BluetoothDevice* device) override; void SimulateGattDescriptor(BluetoothGattCharacteristic* characteristic, const std::string& uuid) override; + // BluetoothTaskManagerWin::Observer overrides. + void OnAttemptReadGattCharacteristic() override; + void OnAttemptWriteGattCharacteristic() override; + + // win::BluetoothLowEnergyWrapperFake::Observer overrides. + void onWriteGattCharacteristicValue( + const PBTH_LE_GATT_CHARACTERISTIC_VALUE value) override; + private: scoped_refptr ui_task_runner_; scoped_refptr bluetooth_task_runner_; @@ -52,11 +78,17 @@ class BluetoothTestWin : public BluetoothTestBase { win::BluetoothClassicWrapperFake* fake_bt_classic_wrapper_; win::BluetoothLowEnergyWrapperFake* fake_bt_le_wrapper_; + BluetoothRemoteGattCharacteristicWin* remembered_characteristic_; + void AdapterInitCallback(); win::GattService* GetSimulatedService(win::BLEDevice* device, BluetoothGattService* service); win::GattCharacteristic* GetSimulatedCharacteristic( BluetoothGattCharacteristic* characteristic); + + // Run pending Bluetooth tasks until the first callback that the test fixture + // tracks is called. + void RunPendingTasksUntilCallback(); void ForceRefreshDevice(); void FinishPendingTasks(); }; -- cgit v1.1