diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2020-10-12 14:27:29 +0200 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2020-10-13 09:35:20 +0000 |
commit | c30a6232df03e1efbd9f3b226777b07e087a1122 (patch) | |
tree | e992f45784689f373bcc38d1b79a239ebe17ee23 /chromium/device/bluetooth | |
parent | 7b5b123ac58f58ffde0f4f6e488bcd09aa4decd3 (diff) | |
download | qtwebengine-chromium-85-based.tar.gz |
BASELINE: Update Chromium to 85.0.4183.14085-based
Change-Id: Iaa42f4680837c57725b1344f108c0196741f6057
Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
Diffstat (limited to 'chromium/device/bluetooth')
74 files changed, 2660 insertions, 747 deletions
diff --git a/chromium/device/bluetooth/android/java/src/org/chromium/device/bluetooth/ChromeBluetoothRemoteGattCharacteristic.java b/chromium/device/bluetooth/android/java/src/org/chromium/device/bluetooth/ChromeBluetoothRemoteGattCharacteristic.java index 41344a1b708..39156474261 100644 --- a/chromium/device/bluetooth/android/java/src/org/chromium/device/bluetooth/ChromeBluetoothRemoteGattCharacteristic.java +++ b/chromium/device/bluetooth/android/java/src/org/chromium/device/bluetooth/ChromeBluetoothRemoteGattCharacteristic.java @@ -130,11 +130,14 @@ final class ChromeBluetoothRemoteGattCharacteristic { // Implements BluetoothRemoteGattCharacteristicAndroid::WriteRemoteCharacteristic. @CalledByNative - private boolean writeRemoteCharacteristic(byte[] value) { + private boolean writeRemoteCharacteristic(byte[] value, int writeType) { if (!mCharacteristic.setValue(value)) { Log.i(TAG, "writeRemoteCharacteristic setValue failed."); return false; } + if (writeType != 0) { + mCharacteristic.setWriteType(writeType); + } if (!mChromeDevice.mBluetoothGatt.writeCharacteristic(mCharacteristic)) { Log.i(TAG, "writeRemoteCharacteristic writeCharacteristic failed."); return false; diff --git a/chromium/device/bluetooth/android/java/src/org/chromium/device/bluetooth/Wrappers.java b/chromium/device/bluetooth/android/java/src/org/chromium/device/bluetooth/Wrappers.java index 14984469ca1..3829a8ff345 100644 --- a/chromium/device/bluetooth/android/java/src/org/chromium/device/bluetooth/Wrappers.java +++ b/chromium/device/bluetooth/android/java/src/org/chromium/device/bluetooth/Wrappers.java @@ -605,6 +605,10 @@ class Wrappers { public boolean setValue(byte[] value) { return mCharacteristic.setValue(value); } + + public void setWriteType(int writeType) { + mCharacteristic.setWriteType(writeType); + } } /** diff --git a/chromium/device/bluetooth/bluetooth_adapter.cc b/chromium/device/bluetooth/bluetooth_adapter.cc index 02207f53fc7..34d5ac03ac5 100644 --- a/chromium/device/bluetooth/bluetooth_adapter.cc +++ b/chromium/device/bluetooth/bluetooth_adapter.cc @@ -10,6 +10,7 @@ #include "base/bind.h" #include "base/bind_helpers.h" +#include "base/logging.h" #include "base/memory/ptr_util.h" #include "base/metrics/histogram_macros.h" #include "base/single_thread_task_runner.h" diff --git a/chromium/device/bluetooth/bluetooth_adapter_mac.mm b/chromium/device/bluetooth/bluetooth_adapter_mac.mm index 0b2c4e6d169..b29b68be6fa 100644 --- a/chromium/device/bluetooth/bluetooth_adapter_mac.mm +++ b/chromium/device/bluetooth/bluetooth_adapter_mac.mm @@ -15,6 +15,7 @@ #include "base/bind.h" #include "base/compiler_specific.h" #include "base/location.h" +#include "base/logging.h" #include "base/mac/mac_util.h" #include "base/memory/ptr_util.h" #include "base/numerics/safe_conversions.h" diff --git a/chromium/device/bluetooth/bluetooth_adapter_mac_metrics.mm b/chromium/device/bluetooth/bluetooth_adapter_mac_metrics.mm index a9cd7606177..36eb4a0c23e 100644 --- a/chromium/device/bluetooth/bluetooth_adapter_mac_metrics.mm +++ b/chromium/device/bluetooth/bluetooth_adapter_mac_metrics.mm @@ -9,6 +9,7 @@ #include "base/mac/mac_util.h" #include "base/metrics/histogram_functions.h" +#include "base/notreached.h" namespace { diff --git a/chromium/device/bluetooth/bluetooth_adapter_mac_metrics_unittest.mm b/chromium/device/bluetooth/bluetooth_adapter_mac_metrics_unittest.mm index 00d17c175be..974e3128fd0 100644 --- a/chromium/device/bluetooth/bluetooth_adapter_mac_metrics_unittest.mm +++ b/chromium/device/bluetooth/bluetooth_adapter_mac_metrics_unittest.mm @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "base/logging.h" #include "base/test/metrics/histogram_tester.h" #include "device/bluetooth/test/bluetooth_test_mac.h" diff --git a/chromium/device/bluetooth/bluetooth_adapter_unittest.cc b/chromium/device/bluetooth/bluetooth_adapter_unittest.cc index 55f6b2d8333..593c5782a30 100644 --- a/chromium/device/bluetooth/bluetooth_adapter_unittest.cc +++ b/chromium/device/bluetooth/bluetooth_adapter_unittest.cc @@ -14,6 +14,7 @@ #include "base/barrier_closure.h" #include "base/bind.h" #include "base/bind_helpers.h" +#include "base/logging.h" #include "base/memory/ref_counted.h" #include "base/run_loop.h" #include "base/test/bind_test_util.h" @@ -131,12 +132,6 @@ class TestBluetoothAdapter final : public BluetoothAdapter { void TestErrorCallback() {} - void TestOnStartDiscoverySession( - std::unique_ptr<device::BluetoothDiscoverySession> discovery_session) { - ++callback_count_; - discovery_sessions_holder_.push(std::move(discovery_session)); - } - void OnStartDiscoverySessionQuitLoop( base::Closure run_loop_quit, std::unique_ptr<device::BluetoothDiscoverySession> discovery_session) { @@ -723,7 +718,7 @@ TEST_F(BluetoothTest, MAYBE_ConstructDefaultAdapter) { EXPECT_EQ(adapter_->IsPowered(), adapter_->IsPowered()); EXPECT_FALSE(adapter_->IsDiscoverable()); EXPECT_FALSE(adapter_->IsDiscovering()); -} +} // namespace device // TODO(scheib): Enable BluetoothTest fixture tests on all platforms. #if defined(OS_ANDROID) || defined(OS_MACOSX) @@ -1420,6 +1415,34 @@ TEST_F(BluetoothTest, MAYBE_TogglePowerBeforeScan) { EXPECT_TRUE(discovery_sessions_[0]->IsActive()); } +#if defined(OS_WIN) +TEST_P(BluetoothTestWinrtOnly, DiscoverySessionFailure) { + if (!PlatformSupportsLowEnergy()) { + LOG(WARNING) << "Low Energy Bluetooth unavailable, skipping unit test."; + return; + } + + InitWithFakeAdapter(); + TestBluetoothAdapterObserver observer(adapter_); + EXPECT_FALSE(adapter_->IsDiscovering()); + + StartLowEnergyDiscoverySession(); + EXPECT_EQ(1, callback_count_); + EXPECT_EQ(0, error_callback_count_); + EXPECT_TRUE(adapter_->IsDiscovering()); + EXPECT_EQ(1, observer.discovering_changed_count()); + EXPECT_TRUE(observer.last_discovering()); + ASSERT_EQ((size_t)1, discovery_sessions_.size()); + EXPECT_TRUE(discovery_sessions_[0]->IsActive()); + + SimulateLowEnergyDiscoveryFailure(); + EXPECT_FALSE(adapter_->IsDiscovering()); + EXPECT_FALSE(discovery_sessions_[0]->IsActive()); + EXPECT_EQ(2, observer.discovering_changed_count()); + EXPECT_FALSE(observer.last_discovering()); +} +#endif // defined(OS_WIN) + #if defined(OS_MACOSX) #define MAYBE_TurnOffAdapterWithConnectedDevice \ TurnOffAdapterWithConnectedDevice @@ -2093,9 +2116,15 @@ TEST_F(BluetoothTest, DiscoverConnectedLowEnergyDeviceTwice) { #endif // defined(OS_MACOSX) #if defined(OS_WIN) -INSTANTIATE_TEST_SUITE_P(All, BluetoothTestWinrt, ::testing::Bool()); +INSTANTIATE_TEST_SUITE_P(All, + BluetoothTestWinrt, + ::testing::ValuesIn(kBluetoothTestWinrtParamAll)); + +INSTANTIATE_TEST_SUITE_P( + All, + BluetoothTestWinrtOnly, + ::testing::ValuesIn(kBluetoothTestWinrtParamWinrtOnly)); -INSTANTIATE_TEST_SUITE_P(All, BluetoothTestWinrtOnly, ::testing::Values(true)); #endif // defined(OS_WIN) } // namespace device diff --git a/chromium/device/bluetooth/bluetooth_adapter_winrt.cc b/chromium/device/bluetooth/bluetooth_adapter_winrt.cc index 0fd2637cd33..1b380be9c80 100644 --- a/chromium/device/bluetooth/bluetooth_adapter_winrt.cc +++ b/chromium/device/bluetooth/bluetooth_adapter_winrt.cc @@ -51,6 +51,7 @@ namespace { namespace uwp { using ABI::Windows::Devices::Bluetooth::BluetoothAdapter; } // namespace uwp +using ABI::Windows::Devices::Bluetooth::BluetoothError; using ABI::Windows::Devices::Bluetooth::IBluetoothAdapter; using ABI::Windows::Devices::Bluetooth::IBluetoothAdapterStatics; using ABI::Windows::Devices::Bluetooth::IID_IBluetoothAdapterStatics; @@ -64,7 +65,6 @@ using ABI::Windows::Devices::Bluetooth::Advertisement:: BluetoothLEAdvertisementWatcherStatus_Aborted; using ABI::Windows::Devices::Bluetooth::Advertisement:: BluetoothLEManufacturerData; -using ABI::Windows::Devices::Bluetooth::Advertisement::BluetoothLEScanningMode; using ABI::Windows::Devices::Bluetooth::Advertisement:: BluetoothLEScanningMode_Active; using ABI::Windows::Devices::Bluetooth::Advertisement:: @@ -72,8 +72,6 @@ using ABI::Windows::Devices::Bluetooth::Advertisement:: using ABI::Windows::Devices::Bluetooth::Advertisement:: IBluetoothLEAdvertisementDataSection; using ABI::Windows::Devices::Bluetooth::Advertisement:: - IBluetoothLEAdvertisementPublisherFactory; -using ABI::Windows::Devices::Bluetooth::Advertisement:: IBluetoothLEAdvertisementReceivedEventArgs; using ABI::Windows::Devices::Bluetooth::Advertisement:: IBluetoothLEAdvertisementWatcher; @@ -463,26 +461,6 @@ base::Optional<std::string> ExtractDeviceName( return base::win::ScopedHString(local_name).GetAsUTF8(); } -void ExtractAndUpdateAdvertisementData( - IBluetoothLEAdvertisementReceivedEventArgs* received, - BluetoothDevice* device) { - int16_t rssi = 0; - HRESULT hr = received->get_RawSignalStrengthInDBm(&rssi); - if (FAILED(hr)) { - BLUETOOTH_LOG(ERROR) << "get_RawSignalStrengthInDBm() failed: " - << logging::SystemErrorCodeToString(hr); - } - - ComPtr<IBluetoothLEAdvertisement> advertisement = GetAdvertisement(received); - static_cast<BluetoothDeviceWinrt*>(device)->UpdateLocalName( - ExtractDeviceName(advertisement.Get())); - device->UpdateAdvertisementData(rssi, ExtractFlags(advertisement.Get()), - ExtractAdvertisedUUIDs(advertisement.Get()), - ExtractTxPower(advertisement.Get()), - ExtractServiceData(advertisement.Get()), - ExtractManufacturerData(advertisement.Get())); -} - RadioState GetState(IRadio* radio) { RadioState state; HRESULT hr = radio->get_State(&state); @@ -951,12 +929,12 @@ void BluetoothAdapterWinrt::StartScanWithFilter( return; } - auto advertisement_received_token = AddTypedEventHandler( + advertisement_received_token_ = AddTypedEventHandler( ble_advertisement_watcher_.Get(), &IBluetoothLEAdvertisementWatcher::add_Received, base::BindRepeating(&BluetoothAdapterWinrt::OnAdvertisementReceived, weak_ptr_factory_.GetWeakPtr())); - if (!advertisement_received_token) { + if (!advertisement_received_token_) { ui_task_runner_->PostTask( FROM_HERE, base::BindOnce(std::move(callback), /*is_error=*/true, @@ -964,13 +942,25 @@ void BluetoothAdapterWinrt::StartScanWithFilter( return; } - advertisement_received_token_ = *advertisement_received_token; + advertisement_watcher_stopped_token_ = AddTypedEventHandler( + ble_advertisement_watcher_.Get(), + &IBluetoothLEAdvertisementWatcher::add_Stopped, + base::BindRepeating(&BluetoothAdapterWinrt::OnAdvertisementWatcherStopped, + weak_ptr_factory_.GetWeakPtr())); + if (!advertisement_watcher_stopped_token_) { + RemoveAdvertisementWatcherEventHandlers(); + ui_task_runner_->PostTask( + FROM_HERE, + base::BindOnce(std::move(callback), /*is_error=*/true, + UMABluetoothDiscoverySessionOutcome::UNKNOWN)); + return; + } hr = ble_advertisement_watcher_->Start(); if (FAILED(hr)) { BLUETOOTH_LOG(ERROR) << "Starting the Advertisement Watcher failed: " << logging::SystemErrorCodeToString(hr); - RemoveAdvertisementReceivedHandler(); + RemoveAdvertisementWatcherEventHandlers(); ui_task_runner_->PostTask( FROM_HERE, base::BindOnce(std::move(callback), /*is_error=*/true, @@ -987,7 +977,7 @@ void BluetoothAdapterWinrt::StartScanWithFilter( BLUETOOTH_LOG(ERROR) << "Starting Advertisement Watcher failed, it is in the Aborted " "state."; - RemoveAdvertisementReceivedHandler(); + RemoveAdvertisementWatcherEventHandlers(); ui_task_runner_->PostTask( FROM_HERE, base::BindOnce(std::move(callback), /*is_error=*/true, @@ -995,6 +985,10 @@ void BluetoothAdapterWinrt::StartScanWithFilter( return; } + for (auto& observer : observers_) { + observer.AdapterDiscoveringChanged(this, /*discovering=*/true); + } + ui_task_runner_->PostTask( FROM_HERE, base::BindOnce(std::move(callback), false, UMABluetoothDiscoverySessionOutcome::SUCCESS)); @@ -1003,7 +997,7 @@ void BluetoothAdapterWinrt::StartScanWithFilter( void BluetoothAdapterWinrt::StopScan(DiscoverySessionResultCallback callback) { DCHECK_EQ(NumDiscoverySessions(), 0); - RemoveAdvertisementReceivedHandler(); + RemoveAdvertisementWatcherEventHandlers(); HRESULT hr = ble_advertisement_watcher_->Stop(); if (FAILED(hr)) { BLUETOOTH_LOG(ERROR) << "Stopped the Advertisement Watcher failed: " @@ -1015,8 +1009,14 @@ void BluetoothAdapterWinrt::StopScan(DiscoverySessionResultCallback callback) { return; } - for (auto& device : devices_) + for (auto& device : devices_) { device.second->ClearAdvertisementData(); + } + + for (auto& observer : observers_) { + observer.AdapterDiscoveringChanged(this, /*discovering=*/false); + } + ble_advertisement_watcher_.Reset(); ui_task_runner_->PostTask( FROM_HERE, base::BindOnce(std::move(callback), /*is_error=*/false, @@ -1329,14 +1329,58 @@ void BluetoothAdapterWinrt::OnAdvertisementReceived( } BluetoothDevice* const device = it->second.get(); - ExtractAndUpdateAdvertisementData(received, device); + + int16_t rssi = 0; + hr = received->get_RawSignalStrengthInDBm(&rssi); + if (FAILED(hr)) { + BLUETOOTH_LOG(ERROR) << "get_RawSignalStrengthInDBm() failed: " + << logging::SystemErrorCodeToString(hr); + } + + // Extract the remaining advertisement data. + ComPtr<IBluetoothLEAdvertisement> advertisement = GetAdvertisement(received); + base::Optional<std::string> device_name = + ExtractDeviceName(advertisement.Get()); + base::Optional<int8_t> tx_power = ExtractTxPower(advertisement.Get()); + BluetoothDevice::UUIDList advertised_uuids = + ExtractAdvertisedUUIDs(advertisement.Get()); + BluetoothDevice::ServiceDataMap service_data_map = + ExtractServiceData(advertisement.Get()); + BluetoothDevice::ManufacturerDataMap manufacturer_data_map = + ExtractManufacturerData(advertisement.Get()); + + static_cast<BluetoothDeviceWinrt*>(device)->UpdateLocalName(device_name); + device->UpdateAdvertisementData(rssi, ExtractFlags(advertisement.Get()), + advertised_uuids, tx_power, service_data_map, + manufacturer_data_map); for (auto& observer : observers_) { + observer.DeviceAdvertisementReceived( + bluetooth_address, device->GetName(), + /*advertisement_name=*/device_name, rssi, tx_power, + device->GetAppearance(), advertised_uuids, service_data_map, + manufacturer_data_map); is_new_device ? observer.DeviceAdded(this, device) : observer.DeviceChanged(this, device); } } +void BluetoothAdapterWinrt::OnAdvertisementWatcherStopped( + ABI::Windows::Devices::Bluetooth::Advertisement:: + IBluetoothLEAdvertisementWatcher* watcher, + ABI::Windows::Devices::Bluetooth::Advertisement:: + IBluetoothLEAdvertisementWatcherStoppedEventArgs* args) { + BluetoothError error; + HRESULT hr = args->get_Error(&error); + if (FAILED(hr)) { + BLUETOOTH_LOG(ERROR) << "get_Error() failed: " << hr; + return; + } + BLUETOOTH_LOG(DEBUG) << "OnAdvertisementWatcherStopped() error=" << error; + + MarkDiscoverySessionsAsInactive(); +} + void BluetoothAdapterWinrt::OnRegisterAdvertisement( BluetoothAdvertisement* advertisement, const CreateAdvertisementCallback& callback) { @@ -1409,13 +1453,23 @@ void BluetoothAdapterWinrt::TryRemovePoweredRadioEventHandlers() { } } -void BluetoothAdapterWinrt::RemoveAdvertisementReceivedHandler() { +void BluetoothAdapterWinrt::RemoveAdvertisementWatcherEventHandlers() { DCHECK(ble_advertisement_watcher_); - HRESULT hr = ble_advertisement_watcher_->remove_Received( - advertisement_received_token_); - if (FAILED(hr)) { - BLUETOOTH_LOG(ERROR) << "Removing the Received Handler failed: " - << logging::SystemErrorCodeToString(hr); + if (advertisement_received_token_) { + HRESULT hr = ble_advertisement_watcher_->remove_Received( + *advertisement_received_token_); + if (FAILED(hr)) { + BLUETOOTH_LOG(ERROR) << "Removing the Received Handler failed: " + << logging::SystemErrorCodeToString(hr); + } + } + if (advertisement_watcher_stopped_token_) { + HRESULT hr = ble_advertisement_watcher_->remove_Stopped( + *advertisement_watcher_stopped_token_); + if (FAILED(hr)) { + BLUETOOTH_LOG(ERROR) << "Removing the Stopped Handler failed: " + << logging::SystemErrorCodeToString(hr); + } } } diff --git a/chromium/device/bluetooth/bluetooth_adapter_winrt.h b/chromium/device/bluetooth/bluetooth_adapter_winrt.h index 9bb463abbf9..fbb47308d9d 100644 --- a/chromium/device/bluetooth/bluetooth_adapter_winrt.h +++ b/chromium/device/bluetooth/bluetooth_adapter_winrt.h @@ -198,7 +198,13 @@ class DEVICE_BLUETOOTH_EXPORT BluetoothAdapterWinrt : public BluetoothAdapter { ABI::Windows::Devices::Bluetooth::Advertisement:: IBluetoothLEAdvertisementWatcher* watcher, ABI::Windows::Devices::Bluetooth::Advertisement:: - IBluetoothLEAdvertisementReceivedEventArgs* received); + IBluetoothLEAdvertisementReceivedEventArgs* args); + + void OnAdvertisementWatcherStopped( + ABI::Windows::Devices::Bluetooth::Advertisement:: + IBluetoothLEAdvertisementWatcher* watcher, + ABI::Windows::Devices::Bluetooth::Advertisement:: + IBluetoothLEAdvertisementWatcherStoppedEventArgs* args); void OnRegisterAdvertisement(BluetoothAdvertisement* advertisement, const CreateAdvertisementCallback& callback); @@ -212,7 +218,7 @@ class DEVICE_BLUETOOTH_EXPORT BluetoothAdapterWinrt : public BluetoothAdapter { void TryRemovePoweredRadioEventHandlers(); - void RemoveAdvertisementReceivedHandler(); + void RemoveAdvertisementWatcherEventHandlers(); bool is_initialized_ = false; bool radio_access_allowed_ = false; @@ -237,7 +243,8 @@ class DEVICE_BLUETOOTH_EXPORT BluetoothAdapterWinrt : public BluetoothAdapter { std::vector<scoped_refptr<BluetoothAdvertisement>> pending_advertisements_; - EventRegistrationToken advertisement_received_token_; + base::Optional<EventRegistrationToken> advertisement_received_token_; + base::Optional<EventRegistrationToken> advertisement_watcher_stopped_token_; Microsoft::WRL::ComPtr<ABI::Windows::Devices::Bluetooth::Advertisement:: IBluetoothLEAdvertisementWatcher> ble_advertisement_watcher_; diff --git a/chromium/device/bluetooth/bluetooth_device.cc b/chromium/device/bluetooth/bluetooth_device.cc index a567ff6d9db..c5cbedcc978 100644 --- a/chromium/device/bluetooth/bluetooth_device.cc +++ b/chromium/device/bluetooth/bluetooth_device.cc @@ -10,6 +10,7 @@ #include <string> #include <utility> +#include "base/logging.h" #include "base/memory/ptr_util.h" #include "base/stl_util.h" #include "base/strings/string_number_conversions.h" diff --git a/chromium/device/bluetooth/bluetooth_device_unittest.cc b/chromium/device/bluetooth/bluetooth_device_unittest.cc index e2f11788406..d46bfd80480 100644 --- a/chromium/device/bluetooth/bluetooth_device_unittest.cc +++ b/chromium/device/bluetooth/bluetooth_device_unittest.cc @@ -7,6 +7,7 @@ #include <stddef.h> #include "base/bind.h" +#include "base/logging.h" #include "base/run_loop.h" #include "base/stl_util.h" #include "base/strings/utf_string_conversions.h" @@ -584,10 +585,20 @@ TEST_F(BluetoothTest, MAYBE_AdvertisementData_Discovery) { EXPECT_EQ(ToInt8(TestTxPower::LOWEST), device->GetInquiryTxPower().value()); } -#if defined(OS_ANDROID) || defined(OS_MACOSX) // TODO(dougt) As I turn on new platforms for WebBluetooth Scanning, // I will relax this #ifdef -TEST_F(BluetoothTest, DeviceAdvertisementReceived) { +#if defined(OS_ANDROID) || defined(OS_MACOSX) || defined(OS_WIN) +#define MAYBE_DeviceAdvertisementReceived DeviceAdvertisementReceived +#else +#define MAYBE_DeviceAdvertisementReceived DISABLED_DeviceAdvertisementReceived +#endif +// Tests that the Bluetooth adapter observer is notified when a device +// advertisement is received. +#if defined(OS_WIN) +TEST_P(BluetoothTestWinrtOnly, DeviceAdvertisementReceived) { +#else +TEST_F(BluetoothTest, MAYBE_DeviceAdvertisementReceived) { +#endif if (!PlatformSupportsLowEnergy()) { LOG(WARNING) << "Low Energy Bluetooth unavailable, skipping unit test."; return; @@ -599,28 +610,34 @@ TEST_F(BluetoothTest, DeviceAdvertisementReceived) { StartLowEnergyDiscoverySession(); SimulateLowEnergyDevice(1); - EXPECT_EQ(1, observer.device_advertisement_raw_received_count()); - EXPECT_EQ(kTestDeviceAddress1, - observer.device_last_device_name().value_or("")); - EXPECT_EQ(kTestDeviceName, - observer.device_last_advertisement_name().value_or("")); + ASSERT_EQ(1, observer.device_advertisement_raw_received_count()); + EXPECT_EQ(kTestDeviceName, observer.last_device_name().value_or("")); + EXPECT_EQ(kTestDeviceName, observer.last_advertisement_name().value_or("")); + EXPECT_EQ(static_cast<int>(TestRSSI::LOWEST), + observer.last_rssi().value_or(-1)); + EXPECT_EQ(static_cast<int>(TestTxPower::LOWEST), + observer.last_tx_power().value_or(-1)); - // TestRSSI::LOWEST - EXPECT_EQ(-81, observer.device_last_rssi().value_or(-1)); + // BluetoothDevice::GetAppearance() is not implemented on all platforms. + // TODO(crbug.com/588083): Check this property when it is implemented. - // TestTxPower::LOWEST - EXPECT_EQ(-40, observer.device_last_tx_power().value_or(-1)); + const device::BluetoothDevice::UUIDList kTestAdvertisedUUIDs = { + BluetoothUUID(kTestUUIDGenericAccess), + BluetoothUUID(kTestUUIDGenericAttribute)}; + EXPECT_EQ(kTestAdvertisedUUIDs, observer.last_advertised_uuids()); - // TODO(crbug.com/588083) - // EXPECT_EQ(0x04, observer.device_last_appearance()); + const device::BluetoothDevice::ServiceDataMap kTestServiceDataMap = { + {BluetoothUUID(kTestUUIDHeartRate), {1}}}; + EXPECT_EQ(kTestServiceDataMap, observer.last_service_data_map()); - // TODO(dougt): Service Data, ManufacturerData, Advertised UUID + const device::BluetoothDevice::ManufacturerDataMap kTestManufacturerDataMap = + {{kTestManufacturerId, {1, 2, 3, 4}}}; + EXPECT_EQ(kTestManufacturerDataMap, observer.last_manufacturer_data_map()); // Double check that we can receive another advertisement. SimulateLowEnergyDevice(2); EXPECT_EQ(2, observer.device_advertisement_raw_received_count()); } -#endif #if defined(OS_ANDROID) || defined(OS_MACOSX) #define MAYBE_GetUUIDs_Connection GetUUIDs_Connection diff --git a/chromium/device/bluetooth/bluetooth_device_winrt.cc b/chromium/device/bluetooth/bluetooth_device_winrt.cc index b1785fa92e6..bdb2afdc94c 100644 --- a/chromium/device/bluetooth/bluetooth_device_winrt.cc +++ b/chromium/device/bluetooth/bluetooth_device_winrt.cc @@ -32,26 +32,30 @@ namespace { using ABI::Windows::Devices::Bluetooth::BluetoothConnectionStatus; using ABI::Windows::Devices::Bluetooth::BluetoothConnectionStatus_Connected; +using ABI::Windows::Devices::Bluetooth::BluetoothError; +using ABI::Windows::Devices::Bluetooth::BluetoothError_Success; using ABI::Windows::Devices::Bluetooth::BluetoothLEDevice; +using ABI::Windows::Devices::Bluetooth::IBluetoothDeviceId; +using ABI::Windows::Devices::Bluetooth::IBluetoothDeviceIdStatics; +using ABI::Windows::Devices::Bluetooth::IBluetoothLEDevice; +using ABI::Windows::Devices::Bluetooth::IBluetoothLEDevice2; +using ABI::Windows::Devices::Bluetooth::IBluetoothLEDevice4; +using ABI::Windows::Devices::Bluetooth::IBluetoothLEDeviceStatics; +using ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::GattSession; using ABI::Windows::Devices::Bluetooth::GenericAttributeProfile:: - GattCommunicationStatus; + GattSessionStatus; using ABI::Windows::Devices::Bluetooth::GenericAttributeProfile:: - GattCommunicationStatus_Success; + GattSessionStatus_Active; using ABI::Windows::Devices::Bluetooth::GenericAttributeProfile:: - GattDeviceServicesResult; + GattSessionStatus_Closed; +using ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::IGattSession; using ABI::Windows::Devices::Bluetooth::GenericAttributeProfile:: - IGattDeviceServicesResult; -using ABI::Windows::Devices::Bluetooth::IBluetoothLEDevice2; -using ABI::Windows::Devices::Bluetooth::IBluetoothLEDevice3; -using ABI::Windows::Devices::Bluetooth::IBluetoothLEDevice; -using ABI::Windows::Devices::Bluetooth::IBluetoothLEDeviceStatics; -using ABI::Windows::Devices::Enumeration::DevicePairingResultStatus; -using ABI::Windows::Devices::Enumeration::IDeviceInformation2; + IGattSessionStatics; using ABI::Windows::Devices::Enumeration::IDeviceInformation; +using ABI::Windows::Devices::Enumeration::IDeviceInformation2; using ABI::Windows::Devices::Enumeration::IDeviceInformationCustomPairing; -using ABI::Windows::Devices::Enumeration::IDeviceInformationPairing2; using ABI::Windows::Devices::Enumeration::IDeviceInformationPairing; -using ABI::Windows::Devices::Enumeration::IDevicePairingRequestedEventArgs; +using ABI::Windows::Devices::Enumeration::IDeviceInformationPairing2; using ABI::Windows::Foundation::IAsyncOperation; using ABI::Windows::Foundation::IClosable; using Microsoft::WRL::ComPtr; @@ -118,7 +122,26 @@ void CloseDevice(ComPtr<IBluetoothLEDevice> ble_device) { hr = closable->Close(); if (FAILED(hr)) { - BLUETOOTH_LOG(DEBUG) << "IClosable::close() failed: " + BLUETOOTH_LOG(DEBUG) << "IClosable::Close() failed: " + << logging::SystemErrorCodeToString(hr); + } +} + +void CloseGattSession(ComPtr<IGattSession> gatt_session) { + if (!gatt_session) + return; + + ComPtr<IClosable> closable; + HRESULT hr = gatt_session.As(&closable); + if (FAILED(hr)) { + BLUETOOTH_LOG(DEBUG) << "As IClosable failed: " + << logging::SystemErrorCodeToString(hr); + return; + } + + hr = closable->Close(); + if (FAILED(hr)) { + BLUETOOTH_LOG(DEBUG) << "IClosable::Close() failed: " << logging::SystemErrorCodeToString(hr); } } @@ -132,6 +155,15 @@ void RemoveConnectionStatusHandler(IBluetoothLEDevice* ble_device, } } +void RemoveGattSessionStatusHandler(IGattSession* gatt_session, + EventRegistrationToken token) { + HRESULT hr = gatt_session->remove_SessionStatusChanged(token); + if (FAILED(hr)) { + BLUETOOTH_LOG(DEBUG) << "Removing ConnectionStatus Handler failed: " + << logging::SystemErrorCodeToString(hr); + } +} + void RemoveGattServicesChangedHandler(IBluetoothLEDevice* ble_device, EventRegistrationToken token) { HRESULT hr = ble_device->remove_GattServicesChanged(token); @@ -161,6 +193,7 @@ BluetoothDeviceWinrt::BluetoothDeviceWinrt(BluetoothAdapterWinrt* adapter, } BluetoothDeviceWinrt::~BluetoothDeviceWinrt() { + CloseGattSession(gatt_session_); CloseDevice(ble_device_); ClearEventRegistrations(); } @@ -241,14 +274,15 @@ bool BluetoothDeviceWinrt::IsPaired() const { } bool BluetoothDeviceWinrt::IsConnected() const { - return IsGattConnected(); + return ble_device_ && + connection_status_ == BluetoothConnectionStatus_Connected; } bool BluetoothDeviceWinrt::IsGattConnected() const { - if (!ble_device_) - return false; + if (!observe_gatt_session_status_change_events_) + return IsConnected(); - return connection_status_; + return gatt_session_ && gatt_session_status_ == GattSessionStatus_Active; } bool BluetoothDeviceWinrt::IsConnectable() const { @@ -426,10 +460,7 @@ void BluetoothDeviceWinrt::CreateGattConnectionImpl( BLUETOOTH_LOG(DEBUG) << "GetBluetoothLEDeviceStaticsActivationFactory failed: " << logging::SystemErrorCodeToString(hr); - base::ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, base::BindOnce(&BluetoothDeviceWinrt::DidFailToConnectGatt, - weak_ptr_factory_.GetWeakPtr(), - ConnectErrorCode::ERROR_FAILED)); + NotifyGattConnectFailure(); return; } @@ -444,45 +475,53 @@ void BluetoothDeviceWinrt::CreateGattConnectionImpl( BLUETOOTH_LOG(DEBUG) << "BluetoothLEDevice::FromBluetoothAddressAsync failed: " << logging::SystemErrorCodeToString(hr); - base::ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, base::BindOnce(&BluetoothDeviceWinrt::DidFailToConnectGatt, - weak_ptr_factory_.GetWeakPtr(), - ConnectErrorCode::ERROR_FAILED)); + NotifyGattConnectFailure(); return; } - target_uuid_ = std::move(service_uuid); hr = base::win::PostAsyncResults( std::move(from_bluetooth_address_op), - base::BindOnce(&BluetoothDeviceWinrt::OnFromBluetoothAddress, - weak_ptr_factory_.GetWeakPtr())); + base::BindOnce( + &BluetoothDeviceWinrt::OnBluetoothLEDeviceFromBluetoothAddress, + weak_ptr_factory_.GetWeakPtr())); if (FAILED(hr)) { BLUETOOTH_LOG(DEBUG) << "PostAsyncResults failed: " << logging::SystemErrorCodeToString(hr); - base::ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, base::BindOnce(&BluetoothDeviceWinrt::DidFailToConnectGatt, - weak_ptr_factory_.GetWeakPtr(), - ConnectErrorCode::ERROR_FAILED)); + NotifyGattConnectFailure(); return; } - pending_on_from_bluetooth_address_ = true; + target_uuid_ = std::move(service_uuid); + pending_gatt_service_discovery_start_ = true; +} + +void BluetoothDeviceWinrt::NotifyGattConnectFailure() { + // Reset |pending_gatt_service_discovery_start_| so that + // UpgradeToFullDiscovery() doesn't mistakenly believe GATT discovery is + // imminent and therefore avoids starting one itself. + pending_gatt_service_discovery_start_ = false; + base::ThreadTaskRunnerHandle::Get()->PostTask( + FROM_HERE, base::BindOnce(&BluetoothDeviceWinrt::DidFailToConnectGatt, + weak_ptr_factory_.GetWeakPtr(), + ConnectErrorCode::ERROR_FAILED)); } void BluetoothDeviceWinrt::UpgradeToFullDiscovery() { // |CreateGattConnectionImpl| has been called previously but having a specific // |target_uuid_| was too optimistic and now a complete enumeration of // services is needed. - DCHECK(pending_on_from_bluetooth_address_ || connection_status_); target_uuid_.reset(); - if (pending_on_from_bluetooth_address_) { - // |OnFromBluetoothAddress| hasn't been called yet. Updating |target_uuid_| - // will be sufficient to change the discovery that will be started. + if (pending_gatt_service_discovery_start_) { + // There is an imminent call to StartDiscovery(). Resetting |target_uuid_| + // now will be sufficient to change the discovery that will be started. return; } + DCHECK(ble_device_); + DCHECK(!observe_gatt_session_status_change_events_ || IsGattConnected()); + // Restart discovery. StartGattDiscovery(); } @@ -494,6 +533,7 @@ void BluetoothDeviceWinrt::DisconnectGatt() { // remaining references, so that the OS disconnects. // Reference: // - https://docs.microsoft.com/en-us/windows/uwp/devices-sensors/gatt-client + CloseGattSession(gatt_session_); CloseDevice(ble_device_); ClearGattServices(); @@ -511,13 +551,20 @@ HRESULT BluetoothDeviceWinrt::GetBluetoothLEDeviceStaticsActivationFactory( RuntimeClass_Windows_Devices_Bluetooth_BluetoothLEDevice>(statics); } -void BluetoothDeviceWinrt::OnFromBluetoothAddress( +HRESULT BluetoothDeviceWinrt::GetGattSessionStaticsActivationFactory( + IGattSessionStatics** statics) const { + return base::win::GetActivationFactory< + IGattSessionStatics, + RuntimeClass_Windows_Devices_Bluetooth_GenericAttributeProfile_GattSession>( + statics); +} + +void BluetoothDeviceWinrt::OnBluetoothLEDeviceFromBluetoothAddress( ComPtr<IBluetoothLEDevice> ble_device) { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - pending_on_from_bluetooth_address_ = false; if (!ble_device) { BLUETOOTH_LOG(DEBUG) << "Getting Device From Bluetooth Address failed."; - DidFailToConnectGatt(ConnectErrorCode::ERROR_FAILED); + NotifyGattConnectFailure(); return; } @@ -532,40 +579,168 @@ void BluetoothDeviceWinrt::OnFromBluetoothAddress( base::BindRepeating(&BluetoothDeviceWinrt::OnConnectionStatusChanged, weak_ptr_factory_.GetWeakPtr())); - // For paired devices the OS immediately establishes a GATT connection after - // the first advertisement. In this case our handler is registered too late to - // catch the initial connection changed event, and we need to perform an - // explicit check ourselves. - if (IsGattConnected()) - DidConnectGatt(); - - gatt_services_changed_token_ = AddTypedEventHandler( - ble_device_.Get(), &IBluetoothLEDevice::add_GattServicesChanged, - base::BindRepeating(&BluetoothDeviceWinrt::OnGattServicesChanged, - weak_ptr_factory_.GetWeakPtr())); - - // Initiating the GATT discovery will result in a GATT connection attempt as - // well and triggers OnConnectionStatusChanged on success. - StartGattDiscovery(); - name_changed_token_ = AddTypedEventHandler( ble_device_.Get(), &IBluetoothLEDevice::add_NameChanged, base::BindRepeating(&BluetoothDeviceWinrt::OnNameChanged, weak_ptr_factory_.GetWeakPtr())); + + if (!observe_gatt_session_status_change_events_) { + // GattSession SessionStatusChanged events can not be observed on + // 1703 (RS2) because BluetoothLEDevice::GetDeviceId() is not + // available. Instead, initiate GATT discovery which should result + // in a GATT connection attempt as well and trigger + // OnConnectionStatusChanged on success. + if (IsGattConnected()) { + DidConnectGatt(); + } + StartGattDiscovery(); + return; + } + + // Next, obtain a GattSession so we can tell the OS to maintain a GATT + // connection with |ble_device_|. + + // BluetoothLEDevice::GetDeviceId() + ComPtr<IBluetoothLEDevice4> ble_device_4; + HRESULT hr = ble_device_.As(&ble_device_4); + if (FAILED(hr)) { + BLUETOOTH_LOG(DEBUG) << "Obtaining IBluetoothLEDevice4 failed: " + << logging::SystemErrorCodeToString(hr); + NotifyGattConnectFailure(); + return; + } + ComPtr<IBluetoothDeviceId> bluetooth_device_id; + hr = ble_device_4->get_BluetoothDeviceId(&bluetooth_device_id); + if (FAILED(hr)) { + BLUETOOTH_LOG(DEBUG) << "BluetoothDeviceId::FromId failed: " + << logging::SystemErrorCodeToString(hr); + NotifyGattConnectFailure(); + return; + } + + // GattSession::FromDeviceIdAsync() + IGattSessionStatics* gatt_session_statics = nullptr; + hr = GetGattSessionStaticsActivationFactory(&gatt_session_statics); + if (FAILED(hr)) { + BLUETOOTH_LOG(DEBUG) << "GetGattSessionStaticsActivationFactory() failed: " + << logging::SystemErrorCodeToString(hr); + NotifyGattConnectFailure(); + return; + } + ComPtr<IAsyncOperation<GattSession*>> gatt_session_from_device_id_async_op; + hr = gatt_session_statics->FromDeviceIdAsync( + bluetooth_device_id.Get(), &gatt_session_from_device_id_async_op); + if (FAILED(hr)) { + BLUETOOTH_LOG(DEBUG) << "GattSession::FromDeviceId failed: " + << logging::SystemErrorCodeToString(hr); + NotifyGattConnectFailure(); + return; + } + hr = base::win::PostAsyncResults( + std::move(gatt_session_from_device_id_async_op), + base::BindOnce(&BluetoothDeviceWinrt::OnGattSessionFromDeviceId, + weak_ptr_factory_.GetWeakPtr())); + if (FAILED(hr)) { + BLUETOOTH_LOG(DEBUG) << "PostAsyncResults failed: " + << logging::SystemErrorCodeToString(hr); + NotifyGattConnectFailure(); + return; + } +} + +void BluetoothDeviceWinrt::OnGattSessionFromDeviceId( + ComPtr<IGattSession> gatt_session) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + DCHECK(observe_gatt_session_status_change_events_); + + if (!gatt_session) { + BLUETOOTH_LOG(DEBUG) << "Getting GattSession failed"; + NotifyGattConnectFailure(); + return; + } + + gatt_session_ = std::move(gatt_session); + + // Tell the OS to automatically establish and maintain a GATT connection. + HRESULT hr = gatt_session_->put_MaintainConnection(true); + if (FAILED(hr)) { + BLUETOOTH_LOG(DEBUG) << "Setting GattSession.MaintainConnection failed: " + << logging::SystemErrorCodeToString(hr); + NotifyGattConnectFailure(); + return; + } + + // Observe GattSessionStatus changes. + gatt_session_->get_SessionStatus(&gatt_session_status_); + gatt_session_status_changed_token_ = AddTypedEventHandler( + gatt_session_.Get(), &IGattSession::add_SessionStatusChanged, + base::BindRepeating(&BluetoothDeviceWinrt::OnGattSessionStatusChanged, + weak_ptr_factory_.GetWeakPtr())); + + // Check whether we missed the initial GattSessionStatus change notification + // because the OS had already established a connection. + if (IsGattConnected()) { + DidConnectGatt(); + StartGattDiscovery(); + } +} + +void BluetoothDeviceWinrt::OnGattSessionStatusChanged( + IGattSession* gatt_session, + ABI::Windows::Devices::Bluetooth::GenericAttributeProfile:: + IGattSessionStatusChangedEventArgs* event_args) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + DCHECK(observe_gatt_session_status_change_events_); + DCHECK_EQ(gatt_session_.Get(), gatt_session); + + GattSessionStatus old_status = gatt_session_status_; + event_args->get_Status(&gatt_session_status_); + + BluetoothError error; + event_args->get_Error(&error); + BLUETOOTH_LOG(DEBUG) << "OnGattSessionStatusChanged() status=" + << gatt_session_status_ << ", error=" << error; + + if (pending_gatt_service_discovery_start_ && + error != BluetoothError_Success) { + NotifyGattConnectFailure(); + return; + } + + // Spurious status change notifications may occur. + if (old_status == gatt_session_status_) { + return; + } + + if (IsGattConnected()) { + DidConnectGatt(); + StartGattDiscovery(); + } else { + gatt_discoverer_.reset(); + ClearGattServices(); + DidDisconnectGatt(); + } } void BluetoothDeviceWinrt::OnConnectionStatusChanged( IBluetoothLEDevice* ble_device, IInspectable* object) { - BluetoothConnectionStatus new_status; - ble_device->get_ConnectionStatus(&new_status); - // Windows sometimes returns a status changed event with a status that has - // not changed. - if (new_status == connection_status_) + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + + BluetoothConnectionStatus old_status = connection_status_; + ble_device->get_ConnectionStatus(&connection_status_); + BLUETOOTH_LOG(DEBUG) << "OnConnectionStatusChanged() status=" + << connection_status_; + + // Spurious status change notifications may occur. + if (old_status == connection_status_) { return; + } + + if (observe_gatt_session_status_change_events_) { + return; + } - connection_status_ = new_status; - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); if (IsGattConnected()) { DidConnectGatt(); } else { @@ -577,15 +752,23 @@ void BluetoothDeviceWinrt::OnConnectionStatusChanged( void BluetoothDeviceWinrt::OnGattServicesChanged(IBluetoothLEDevice* ble_device, IInspectable* object) { + BLUETOOTH_LOG(DEBUG) << "OnGattServicesChanged()"; DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - // Note: We don't clear out |gatt_services_| here, as we don't want to break + // TODO(crbug/1085596): This event fires once for every newly discovered GATT + // service. Hence, the initial GATT service discovery aborts and restarts + // itself here once for every service discovered, which is unnecessary and + // slow. + + // We don't clear out |gatt_services_| here, as we don't want to break // existing references to Gatt Services that did not change. device_uuids_.ClearServiceUUIDs(); + SetGattServicesDiscoveryComplete(false); adapter_->NotifyDeviceChanged(this); if (IsGattConnected()) { // In order to stop a potential ongoing GATT discovery, the GattDiscoverer // is reset and a new discovery is initiated. + BLUETOOTH_LOG(DEBUG) << "Discovering GATT services anew"; StartGattDiscovery(); } } @@ -597,6 +780,14 @@ void BluetoothDeviceWinrt::OnNameChanged(IBluetoothLEDevice* ble_device, } void BluetoothDeviceWinrt::StartGattDiscovery() { + BLUETOOTH_LOG(DEBUG) << "StartGattDiscovery()"; + pending_gatt_service_discovery_start_ = false; + if (!gatt_services_changed_token_) { + gatt_services_changed_token_ = AddTypedEventHandler( + ble_device_.Get(), &IBluetoothLEDevice::add_GattServicesChanged, + base::BindRepeating(&BluetoothDeviceWinrt::OnGattServicesChanged, + weak_ptr_factory_.GetWeakPtr())); + } gatt_discoverer_ = std::make_unique<BluetoothGattDiscovererWinrt>(ble_device_, target_uuid_); gatt_discoverer_->StartGattDiscovery( @@ -605,9 +796,11 @@ void BluetoothDeviceWinrt::StartGattDiscovery() { } void BluetoothDeviceWinrt::OnGattDiscoveryComplete(bool success) { + BLUETOOTH_LOG(DEBUG) << "OnGattDiscoveryComplete() success=" << success; if (!success) { - if (!IsGattConnected()) - DidFailToConnectGatt(ConnectErrorCode::ERROR_FAILED); + if (!IsGattConnected()) { + NotifyGattConnectFailure(); + } gatt_discoverer_.reset(); return; } @@ -661,6 +854,11 @@ void BluetoothDeviceWinrt::ClearEventRegistrations() { *connection_changed_token_); } + if (gatt_session_status_changed_token_) { + RemoveGattSessionStatusHandler(gatt_session_.Get(), + *gatt_session_status_changed_token_); + } + if (gatt_services_changed_token_) { RemoveGattServicesChangedHandler(ble_device_.Get(), *gatt_services_changed_token_); diff --git a/chromium/device/bluetooth/bluetooth_device_winrt.h b/chromium/device/bluetooth/bluetooth_device_winrt.h index 94b4b7140fb..d29c2890028 100644 --- a/chromium/device/bluetooth/bluetooth_device_winrt.h +++ b/chromium/device/bluetooth/bluetooth_device_winrt.h @@ -5,6 +5,7 @@ #ifndef DEVICE_BLUETOOTH_BLUETOOTH_DEVICE_WINRT_H_ #define DEVICE_BLUETOOTH_BLUETOOTH_DEVICE_WINRT_H_ +#include <windows.devices.bluetooth.genericattributeprofile.h> #include <windows.devices.bluetooth.h> #include <wrl/client.h> @@ -14,10 +15,13 @@ #include <string> #include "base/callback_forward.h" +#include "base/feature_list.h" #include "base/macros.h" #include "base/memory/weak_ptr.h" #include "base/optional.h" #include "base/threading/thread_checker.h" +#include "base/win/windows_version.h" +#include "device/base/features.h" #include "device/bluetooth/bluetooth_device.h" #include "device/bluetooth/bluetooth_export.h" @@ -100,19 +104,38 @@ class DEVICE_BLUETOOTH_EXPORT BluetoothDeviceWinrt : public BluetoothDevice { void UpgradeToFullDiscovery() override; void DisconnectGatt() override; - // This is declared virtual so that they can be overridden by tests. + // Declared virtual so that it can be overridden by tests. virtual HRESULT GetBluetoothLEDeviceStaticsActivationFactory( ABI::Windows::Devices::Bluetooth::IBluetoothLEDeviceStatics** statics) const; + // Declared virtual so that it can be overridden by tests. + virtual HRESULT GetGattSessionStaticsActivationFactory( + ABI::Windows::Devices::Bluetooth::GenericAttributeProfile:: + IGattSessionStatics** statics) const; + Microsoft::WRL::ComPtr<ABI::Windows::Devices::Bluetooth::IBluetoothLEDevice> ble_device_; + Microsoft::WRL::ComPtr< + ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::IGattSession> + gatt_session_; private: - void OnFromBluetoothAddress( + void OnBluetoothLEDeviceFromBluetoothAddress( Microsoft::WRL::ComPtr< ABI::Windows::Devices::Bluetooth::IBluetoothLEDevice> ble_device); + void OnGattSessionFromDeviceId( + Microsoft::WRL::ComPtr<ABI::Windows::Devices::Bluetooth:: + GenericAttributeProfile::IGattSession> + gatt_session); + + void OnGattSessionStatusChanged( + ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::IGattSession* + gatt_session, + ABI::Windows::Devices::Bluetooth::GenericAttributeProfile:: + IGattSessionStatusChangedEventArgs* event_args); + void OnConnectionStatusChanged( ABI::Windows::Devices::Bluetooth::IBluetoothLEDevice* ble_device, IInspectable* object); @@ -127,23 +150,42 @@ class DEVICE_BLUETOOTH_EXPORT BluetoothDeviceWinrt : public BluetoothDevice { void StartGattDiscovery(); void OnGattDiscoveryComplete(bool success); + void NotifyGattConnectFailure(); void ClearGattServices(); void ClearEventRegistrations(); ABI::Windows::Devices::Bluetooth::BluetoothConnectionStatus connection_status_; + ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::GattSessionStatus + gatt_session_status_; uint64_t raw_address_; std::string address_; base::Optional<std::string> local_name_; std::unique_ptr<BluetoothPairingWinrt> pairing_; - bool pending_on_from_bluetooth_address_ = false; + // Indicates whether the device should subscribe to GattSession + // SessionStatusChanged events. Doing so requires calling + // BluetoothLEDevice::GetDeviceId() which is only available on 1709 + // (RS3) or newer. If false, GATT connection reliability may be + // degraded. + bool observe_gatt_session_status_change_events_ = + base::FeatureList::IsEnabled(kNewBLEGattSessionHandling) && + base::win::GetVersion() >= base::win::Version::WIN10_RS3; + + // Indicates whether a GATT service discovery is imminent. Discovery + // begins once GattSessionStatus for the device changes to |Active| + // if |observe_gatt_session_status_change_events_| is true, or once + // the BluetoothLEDevice has been obtained from + // FromBluetoothAddressAsync() otherwise. + bool pending_gatt_service_discovery_start_ = false; + base::Optional<BluetoothUUID> target_uuid_; std::unique_ptr<BluetoothGattDiscovererWinrt> gatt_discoverer_; base::Optional<EventRegistrationToken> connection_changed_token_; + base::Optional<EventRegistrationToken> gatt_session_status_changed_token_; base::Optional<EventRegistrationToken> gatt_services_changed_token_; base::Optional<EventRegistrationToken> name_changed_token_; diff --git a/chromium/device/bluetooth/bluetooth_discovery_manager_mac.mm b/chromium/device/bluetooth/bluetooth_discovery_manager_mac.mm index caa09ebd376..3331f05ba8e 100644 --- a/chromium/device/bluetooth/bluetooth_discovery_manager_mac.mm +++ b/chromium/device/bluetooth/bluetooth_discovery_manager_mac.mm @@ -7,6 +7,7 @@ #import <IOBluetooth/objc/IOBluetoothDevice.h> #import <IOBluetooth/objc/IOBluetoothDeviceInquiry.h> +#include "base/check_op.h" #include "base/logging.h" #include "base/mac/scoped_nsobject.h" #include "base/macros.h" diff --git a/chromium/device/bluetooth/bluetooth_discovery_session.cc b/chromium/device/bluetooth/bluetooth_discovery_session.cc index 9830d6c33a5..7f09a1eee21 100644 --- a/chromium/device/bluetooth/bluetooth_discovery_session.cc +++ b/chromium/device/bluetooth/bluetooth_discovery_session.cc @@ -8,6 +8,7 @@ #include "base/bind.h" #include "base/bind_helpers.h" +#include "base/logging.h" #include "device/bluetooth/bluetooth_adapter.h" #include "device/bluetooth/bluetooth_discovery_filter.h" diff --git a/chromium/device/bluetooth/bluetooth_discovery_session.h b/chromium/device/bluetooth/bluetooth_discovery_session.h index 2f94f3324b4..1d1ac97efbc 100644 --- a/chromium/device/bluetooth/bluetooth_discovery_session.h +++ b/chromium/device/bluetooth/bluetooth_discovery_session.h @@ -47,12 +47,10 @@ class DEVICE_BLUETOOTH_EXPORT BluetoothDiscoverySession { INACTIVE }; - // Destructor automatically terminates the discovery session. If this - // results in a call to the underlying system to stop device discovery - // (i.e. this instance represents the last active discovery session), - // the call may not always succeed. To be notified of such failures, - // users are highly encouraged to call BluetoothDiscoverySession::Stop, - // instead of relying on the destructor. + // Terminates the discovery session. If this is the last active discovery + // session, a call to the underlying system to stop device discovery is made. + // Users may call BluetoothDiscoverySession::Stop() if they need to observe + // the result of that operation, but this is usually unnecessary. virtual ~BluetoothDiscoverySession(); // Returns true if the session is active, false otherwise. If false, the @@ -63,14 +61,11 @@ class DEVICE_BLUETOOTH_EXPORT BluetoothDiscoverySession { // discovery continues. virtual bool IsActive() const; - // Requests this discovery session instance to stop. If this instance is - // active, the session will stop. On success, |callback| is called and - // on error |error_callback| is called. After a successful invocation, the - // adapter may or may not stop device discovery, depending on whether or not - // other active discovery sessions are present. Users are highly encouraged - // to call this method to end a discovery session, instead of relying on the - // destructor, so that they can be notified of the result via the callback - // arguments. + // Requests this discovery session instance to stop. If this is the last + // active discovery session, a call to the underlying system to stop device + // discovery is made, and |error_callback| will be invoked if such a call + // fails. Typically, users can ignore this and simply destroy the instance + // instead of calling Stop(). virtual void Stop(base::Closure callback = base::DoNothing(), ErrorCallback error_callback = base::DoNothing()); diff --git a/chromium/device/bluetooth/bluetooth_init_win.cc b/chromium/device/bluetooth/bluetooth_init_win.cc index ab41d47174b..c623f10e6c1 100644 --- a/chromium/device/bluetooth/bluetooth_init_win.cc +++ b/chromium/device/bluetooth/bluetooth_init_win.cc @@ -4,7 +4,7 @@ #include "device/bluetooth/bluetooth_init_win.h" -#include "base/threading/scoped_blocking_call.h" +#include "base/threading/scoped_thread_priority.h" namespace { @@ -28,8 +28,10 @@ bool HasBluetoothStack() { } has_bluetooth_stack = HBS_UNKNOWN; if (has_bluetooth_stack == HBS_UNKNOWN) { - base::ScopedBlockingCall scoped_blocking_call( - FROM_HERE, base::BlockingType::MAY_BLOCK); + // Mitigate the issues caused by loading DLLs on a background thread + // (http://crbug/973868). + SCOPED_MAY_LOAD_LIBRARY_AT_BACKGROUND_PRIORITY_REPEATEDLY(); + HRESULT hr = E_FAIL; __try { hr = __HrLoadAllImportsForDll("bthprops.cpl"); diff --git a/chromium/device/bluetooth/bluetooth_low_energy_advertisement_manager_mac.mm b/chromium/device/bluetooth/bluetooth_low_energy_advertisement_manager_mac.mm index a7b03c84975..e78ca6b190f 100644 --- a/chromium/device/bluetooth/bluetooth_low_energy_advertisement_manager_mac.mm +++ b/chromium/device/bluetooth/bluetooth_low_energy_advertisement_manager_mac.mm @@ -5,6 +5,7 @@ #include "device/bluetooth/bluetooth_low_energy_advertisement_manager_mac.h" #include "base/bind.h" +#include "base/logging.h" #include "base/mac/scoped_nsobject.h" #include "base/optional.h" #include "base/strings/sys_string_conversions.h" diff --git a/chromium/device/bluetooth/bluetooth_low_energy_device_mac.mm b/chromium/device/bluetooth/bluetooth_low_energy_device_mac.mm index 6f343a774b2..93a4ba716f2 100644 --- a/chromium/device/bluetooth/bluetooth_low_energy_device_mac.mm +++ b/chromium/device/bluetooth/bluetooth_low_energy_device_mac.mm @@ -7,6 +7,7 @@ #import <CoreFoundation/CoreFoundation.h> #include <stddef.h> +#include "base/logging.h" #include "base/mac/mac_util.h" #include "base/mac/scoped_cftyperef.h" #include "base/memory/ptr_util.h" diff --git a/chromium/device/bluetooth/bluetooth_low_energy_device_watcher_mac.mm b/chromium/device/bluetooth/bluetooth_low_energy_device_watcher_mac.mm index 955d36777f8..ad46a81a983 100644 --- a/chromium/device/bluetooth/bluetooth_low_energy_device_watcher_mac.mm +++ b/chromium/device/bluetooth/bluetooth_low_energy_device_watcher_mac.mm @@ -8,6 +8,7 @@ #include "base/bind.h" #include "base/files/file_util.h" +#include "base/logging.h" #include "base/strings/sys_string_conversions.h" #include "base/task/task_traits.h" #include "device/bluetooth/bluetooth_adapter_mac.h" diff --git a/chromium/device/bluetooth/bluetooth_low_energy_discovery_manager_mac.mm b/chromium/device/bluetooth/bluetooth_low_energy_discovery_manager_mac.mm index a128699d9ae..e9ca28150ff 100644 --- a/chromium/device/bluetooth/bluetooth_low_energy_discovery_manager_mac.mm +++ b/chromium/device/bluetooth/bluetooth_low_energy_discovery_manager_mac.mm @@ -6,6 +6,7 @@ #include <memory> +#include "base/logging.h" #include "base/mac/mac_util.h" #include "base/strings/sys_string_conversions.h" #include "device/bluetooth/bluetooth_adapter_mac.h" diff --git a/chromium/device/bluetooth/bluetooth_low_energy_win.cc b/chromium/device/bluetooth/bluetooth_low_energy_win.cc index c2a4ae29246..013e0574972 100644 --- a/chromium/device/bluetooth/bluetooth_low_energy_win.cc +++ b/chromium/device/bluetooth/bluetooth_low_energy_win.cc @@ -801,20 +801,15 @@ HRESULT BluetoothLowEnergyWrapper::ReadCharacteristicValue( HRESULT BluetoothLowEnergyWrapper::WriteCharacteristicValue( base::FilePath& service_path, const PBTH_LE_GATT_CHARACTERISTIC characteristic, - PBTH_LE_GATT_CHARACTERISTIC_VALUE new_value) { + PBTH_LE_GATT_CHARACTERISTIC_VALUE new_value, + ULONG flags) { 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); - ULONG flag = BLUETOOTH_GATT_FLAG_NONE; - if (!characteristic->IsWritable) { - DCHECK(characteristic->IsWritableWithoutResponse); - flag |= BLUETOOTH_GATT_FLAG_WRITE_WITHOUT_RESPONSE; - } - return BluetoothGATTSetCharacteristicValue( - file.GetPlatformFile(), characteristic, new_value, NULL, flag); + file.GetPlatformFile(), characteristic, new_value, {}, flags); } HRESULT BluetoothLowEnergyWrapper::RegisterGattEvents( diff --git a/chromium/device/bluetooth/bluetooth_low_energy_win.h b/chromium/device/bluetooth/bluetooth_low_energy_win.h index e582d4cbaa8..e248c97c8b8 100644 --- a/chromium/device/bluetooth/bluetooth_low_energy_win.h +++ b/chromium/device/bluetooth/bluetooth_low_energy_win.h @@ -188,7 +188,8 @@ class DEVICE_BLUETOOTH_EXPORT BluetoothLowEnergyWrapper { virtual HRESULT WriteCharacteristicValue( base::FilePath& service_path, const PBTH_LE_GATT_CHARACTERISTIC characteristic, - PBTH_LE_GATT_CHARACTERISTIC_VALUE new_value); + PBTH_LE_GATT_CHARACTERISTIC_VALUE new_value, + ULONG flags); // Register GATT events of |event_type| in the service with service device // path |service_path|. |event_parameter| is the event's parameter. |callback| diff --git a/chromium/device/bluetooth/bluetooth_low_energy_win_fake.cc b/chromium/device/bluetooth/bluetooth_low_energy_win_fake.cc index dcf4db10232..b25021dd531 100644 --- a/chromium/device/bluetooth/bluetooth_low_energy_win_fake.cc +++ b/chromium/device/bluetooth/bluetooth_low_energy_win_fake.cc @@ -216,7 +216,15 @@ HRESULT BluetoothLowEnergyWrapperFake::ReadCharacteristicValue( HRESULT BluetoothLowEnergyWrapperFake::WriteCharacteristicValue( base::FilePath& service_path, const PBTH_LE_GATT_CHARACTERISTIC characteristic, - PBTH_LE_GATT_CHARACTERISTIC_VALUE new_value) { + PBTH_LE_GATT_CHARACTERISTIC_VALUE new_value, + ULONG flags) { + // Web Bluetooth implementation currently only supports no flags or write + // without response flag even if Windows supports other flags + if (flags != BLUETOOTH_GATT_FLAG_NONE && + flags != BLUETOOTH_GATT_FLAG_WRITE_WITHOUT_RESPONSE) { + return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED); + } + GattCharacteristic* target_characteristic = GetSimulatedGattCharacteristic(service_path, characteristic); if (target_characteristic == nullptr) diff --git a/chromium/device/bluetooth/bluetooth_low_energy_win_fake.h b/chromium/device/bluetooth/bluetooth_low_energy_win_fake.h index 9f0e2c0e0c6..01c482dd35d 100644 --- a/chromium/device/bluetooth/bluetooth_low_energy_win_fake.h +++ b/chromium/device/bluetooth/bluetooth_low_energy_win_fake.h @@ -130,7 +130,8 @@ class BluetoothLowEnergyWrapperFake : public BluetoothLowEnergyWrapper { HRESULT WriteCharacteristicValue( base::FilePath& service_path, const PBTH_LE_GATT_CHARACTERISTIC characteristic, - PBTH_LE_GATT_CHARACTERISTIC_VALUE new_value) override; + PBTH_LE_GATT_CHARACTERISTIC_VALUE new_value, + ULONG flags) override; HRESULT RegisterGattEvents( base::FilePath& service_path, BTH_LE_GATT_EVENT_TYPE type, diff --git a/chromium/device/bluetooth/bluetooth_remote_gatt_characteristic.cc b/chromium/device/bluetooth/bluetooth_remote_gatt_characteristic.cc index 3d1252dc2d6..9cc33c1135c 100644 --- a/chromium/device/bluetooth/bluetooth_remote_gatt_characteristic.cc +++ b/chromium/device/bluetooth/bluetooth_remote_gatt_characteristic.cc @@ -107,12 +107,6 @@ void BluetoothRemoteGattCharacteristic::StartNotifySession( } #endif -bool BluetoothRemoteGattCharacteristic::WriteWithoutResponse( - base::span<const uint8_t> value) { - NOTIMPLEMENTED(); - return false; -} - bool BluetoothRemoteGattCharacteristic::AddDescriptor( std::unique_ptr<BluetoothRemoteGattDescriptor> descriptor) { if (!descriptor) diff --git a/chromium/device/bluetooth/bluetooth_remote_gatt_characteristic.h b/chromium/device/bluetooth/bluetooth_remote_gatt_characteristic.h index 64b0875ded6..75996110686 100644 --- a/chromium/device/bluetooth/bluetooth_remote_gatt_characteristic.h +++ b/chromium/device/bluetooth/bluetooth_remote_gatt_characteristic.h @@ -42,6 +42,12 @@ class BluetoothRemoteGattDescriptor; class DEVICE_BLUETOOTH_EXPORT BluetoothRemoteGattCharacteristic : public virtual BluetoothGattCharacteristic { public: + // Parameter for WriteRemoteCharacteristic + enum class WriteType { + kWithResponse, + kWithoutResponse, + }; + // The ValueCallback is used to return the value of a remote characteristic // upon a read request. using ValueCallback = base::OnceCallback<void(const std::vector<uint8_t>&)>; @@ -136,13 +142,25 @@ class DEVICE_BLUETOOTH_EXPORT BluetoothRemoteGattCharacteristic virtual void ReadRemoteCharacteristic(ValueCallback callback, ErrorCallback error_callback) = 0; + // Sends a write request to a remote characteristic with the value |value| + // using the specified |write_type|. |callback| is called to signal success + // and |error_callback| for failures. This method only applies to remote + // characteristics and will fail for those that are locally hosted. + virtual void WriteRemoteCharacteristic(const std::vector<uint8_t>& value, + WriteType write_type, + base::OnceClosure callback, + ErrorCallback error_callback) = 0; + + // DEPRECATED: Use WriteRemoteCharacteristic instead. This method remains + // for backward compatibility. // Sends a write request to a remote characteristic with the value |value|. // |callback| is called to signal success and |error_callback| for failures. // This method only applies to remote characteristics and will fail for those // that are locally hosted. - virtual void WriteRemoteCharacteristic(const std::vector<uint8_t>& value, - base::OnceClosure callback, - ErrorCallback error_callback) = 0; + virtual void DeprecatedWriteRemoteCharacteristic( + const std::vector<uint8_t>& value, + base::OnceClosure callback, + ErrorCallback error_callback) = 0; #if defined(OS_CHROMEOS) // Sends a prepare write request to a remote characteristic with the value @@ -157,15 +175,6 @@ class DEVICE_BLUETOOTH_EXPORT BluetoothRemoteGattCharacteristic ErrorCallback error_callback) = 0; #endif - // Sends a write request to a remote characteristic with the value |value| - // without waiting for a response. This method returns false to signal - // failures. When attempting to write the remote characteristic true is - // returned without a guarantee of success. This method only applies to remote - // characteristics and will fail for those that are locally hosted. - // This method is currently implemented only on macOS. - // TODO(https://crbug.com/831524): Implement it on other platforms as well. - virtual bool WriteWithoutResponse(base::span<const uint8_t> value); - protected: using DescriptorMap = base::flat_map<std::string, diff --git a/chromium/device/bluetooth/bluetooth_remote_gatt_characteristic_android.cc b/chromium/device/bluetooth/bluetooth_remote_gatt_characteristic_android.cc index 395d1dbe209..fe92a2b85c8 100644 --- a/chromium/device/bluetooth/bluetooth_remote_gatt_characteristic_android.cc +++ b/chromium/device/bluetooth/bluetooth_remote_gatt_characteristic_android.cc @@ -152,6 +152,7 @@ void BluetoothRemoteGattCharacteristicAndroid::ReadRemoteCharacteristic( void BluetoothRemoteGattCharacteristicAndroid::WriteRemoteCharacteristic( const std::vector<uint8_t>& value, + WriteType write_type, base::OnceClosure callback, ErrorCallback error_callback) { if (read_pending_ || write_pending_) { @@ -162,9 +163,48 @@ void BluetoothRemoteGattCharacteristicAndroid::WriteRemoteCharacteristic( return; } + AndroidWriteType android_write_type; + switch (write_type) { + case WriteType::kWithResponse: + android_write_type = AndroidWriteType::kDefault; + break; + case WriteType::kWithoutResponse: + android_write_type = AndroidWriteType::kNoResponse; + break; + } + + JNIEnv* env = AttachCurrentThread(); + if (!Java_ChromeBluetoothRemoteGattCharacteristic_writeRemoteCharacteristic( + env, j_characteristic_, base::android::ToJavaByteArray(env, value), + static_cast<int>(android_write_type))) { + base::ThreadTaskRunnerHandle::Get()->PostTask( + FROM_HERE, + base::BindOnce(std::move(error_callback), + BluetoothRemoteGattService::GATT_ERROR_FAILED)); + return; + } + + write_pending_ = true; + write_callback_ = std::move(callback); + write_error_callback_ = std::move(error_callback); +} + +void BluetoothRemoteGattCharacteristicAndroid:: + DeprecatedWriteRemoteCharacteristic(const std::vector<uint8_t>& value, + base::OnceClosure callback, + ErrorCallback error_callback) { + if (read_pending_ || write_pending_) { + base::ThreadTaskRunnerHandle::Get()->PostTask( + FROM_HERE, + base::BindOnce(std::move(error_callback), + BluetoothRemoteGattService::GATT_ERROR_IN_PROGRESS)); + return; + } + JNIEnv* env = AttachCurrentThread(); if (!Java_ChromeBluetoothRemoteGattCharacteristic_writeRemoteCharacteristic( - env, j_characteristic_, base::android::ToJavaByteArray(env, value))) { + env, j_characteristic_, base::android::ToJavaByteArray(env, value), + static_cast<int>(AndroidWriteType::kNone))) { base::ThreadTaskRunnerHandle::Get()->PostTask( FROM_HERE, base::BindOnce(std::move(error_callback), diff --git a/chromium/device/bluetooth/bluetooth_remote_gatt_characteristic_android.h b/chromium/device/bluetooth/bluetooth_remote_gatt_characteristic_android.h index 63811345a6e..7710e77ce2a 100644 --- a/chromium/device/bluetooth/bluetooth_remote_gatt_characteristic_android.h +++ b/chromium/device/bluetooth/bluetooth_remote_gatt_characteristic_android.h @@ -66,8 +66,13 @@ class DEVICE_BLUETOOTH_EXPORT BluetoothRemoteGattCharacteristicAndroid void ReadRemoteCharacteristic(ValueCallback callback, ErrorCallback error_callback) override; void WriteRemoteCharacteristic(const std::vector<uint8_t>& value, + WriteType write_type, base::OnceClosure callback, ErrorCallback error_callback) override; + void DeprecatedWriteRemoteCharacteristic( + const std::vector<uint8_t>& value, + base::OnceClosure callback, + ErrorCallback error_callback) override; // Called when value changed event occurs. void OnChanged(JNIEnv* env, @@ -108,6 +113,15 @@ class DEVICE_BLUETOOTH_EXPORT BluetoothRemoteGattCharacteristicAndroid ErrorCallback error_callback) override; private: + // Android API characteristic write type flags. + // https://developer.android.com/reference/android/bluetooth/BluetoothGattCharacteristic.html + enum class AndroidWriteType { + kNone = 0, + kNoResponse = 1 << 0, + kDefault = 1 << 1, + kSigned = 1 << 2, + }; + BluetoothRemoteGattCharacteristicAndroid( BluetoothAdapterAndroid* adapter, BluetoothRemoteGattServiceAndroid* service, diff --git a/chromium/device/bluetooth/bluetooth_remote_gatt_characteristic_mac.h b/chromium/device/bluetooth/bluetooth_remote_gatt_characteristic_mac.h index 34e4a46769b..71510e2bddc 100644 --- a/chromium/device/bluetooth/bluetooth_remote_gatt_characteristic_mac.h +++ b/chromium/device/bluetooth/bluetooth_remote_gatt_characteristic_mac.h @@ -44,9 +44,13 @@ class DEVICE_BLUETOOTH_EXPORT BluetoothRemoteGattCharacteristicMac void ReadRemoteCharacteristic(ValueCallback callback, ErrorCallback error_callback) override; void WriteRemoteCharacteristic(const std::vector<uint8_t>& value, + WriteType write_type, base::OnceClosure callback, ErrorCallback error_callback) override; - bool WriteWithoutResponse(base::span<const uint8_t> value) override; + void DeprecatedWriteRemoteCharacteristic( + const std::vector<uint8_t>& value, + base::OnceClosure callback, + ErrorCallback error_callback) override; protected: void SubscribeToNotifications(BluetoothRemoteGattDescriptor* ccc_descriptor, @@ -82,8 +86,6 @@ class DEVICE_BLUETOOTH_EXPORT BluetoothRemoteGattCharacteristicMac bool IsReadable() const; // Returns true if the characteristic is writable. bool IsWritable() const; - // Returns true if the characteristic is writable without response. - bool IsWritableWithoutResponse() const; // Returns true if the characteristic supports notifications or indications. bool SupportsNotificationsOrIndications() const; // Returns the write type (with or without responses). diff --git a/chromium/device/bluetooth/bluetooth_remote_gatt_characteristic_mac.mm b/chromium/device/bluetooth/bluetooth_remote_gatt_characteristic_mac.mm index 65020670281..ec869f70c2f 100644 --- a/chromium/device/bluetooth/bluetooth_remote_gatt_characteristic_mac.mm +++ b/chromium/device/bluetooth/bluetooth_remote_gatt_characteristic_mac.mm @@ -5,6 +5,7 @@ #include "device/bluetooth/bluetooth_remote_gatt_characteristic_mac.h" #include "base/bind.h" +#include "base/logging.h" #include "base/memory/ptr_util.h" #include "base/strings/sys_string_conversions.h" #include "base/threading/thread_task_runner_handle.h" @@ -154,6 +155,46 @@ void BluetoothRemoteGattCharacteristicMac::ReadRemoteCharacteristic( void BluetoothRemoteGattCharacteristicMac::WriteRemoteCharacteristic( const std::vector<uint8_t>& value, + WriteType write_type, + base::OnceClosure callback, + ErrorCallback error_callback) { + if (HasPendingRead() || HasPendingWrite()) { + DVLOG(1) << *this << ": Characteristic write already in progress."; + base::ThreadTaskRunnerHandle::Get()->PostTask( + FROM_HERE, + base::BindOnce(std::move(error_callback), + BluetoothRemoteGattService::GATT_ERROR_IN_PROGRESS)); + return; + } + DVLOG(1) << *this << ": Write characteristic."; + write_characteristic_value_callbacks_ = + std::make_pair(std::move(callback), std::move(error_callback)); + base::scoped_nsobject<NSData> nsdata_value( + [[NSData alloc] initWithBytes:value.data() length:value.size()]); + + CBCharacteristicWriteType cb_write_type; + switch (write_type) { + case WriteType::kWithResponse: + cb_write_type = CBCharacteristicWriteWithResponse; + break; + case WriteType::kWithoutResponse: + cb_write_type = CBCharacteristicWriteWithoutResponse; + break; + } + + [GetCBPeripheral() writeValue:nsdata_value + forCharacteristic:cb_characteristic_ + type:cb_write_type]; + if (cb_write_type == CBCharacteristicWriteWithoutResponse) { + base::ThreadTaskRunnerHandle::Get()->PostTask( + FROM_HERE, + base::BindOnce(&BluetoothRemoteGattCharacteristicMac::DidWriteValue, + weak_ptr_factory_.GetWeakPtr(), nil)); + } +} + +void BluetoothRemoteGattCharacteristicMac::DeprecatedWriteRemoteCharacteristic( + const std::vector<uint8_t>& value, base::OnceClosure callback, ErrorCallback error_callback) { if (!IsWritable()) { @@ -189,26 +230,6 @@ void BluetoothRemoteGattCharacteristicMac::WriteRemoteCharacteristic( } } -bool BluetoothRemoteGattCharacteristicMac::WriteWithoutResponse( - base::span<const uint8_t> value) { - if (!IsWritableWithoutResponse()) { - DVLOG(1) << *this << ": Characteristic not writable without response."; - return false; - } - if (HasPendingRead() || HasPendingWrite()) { - DVLOG(1) << *this << ": Characteristic write already in progress."; - return false; - } - - DVLOG(1) << *this << ": Write characteristic without response."; - base::scoped_nsobject<NSData> nsdata_value( - [[NSData alloc] initWithBytes:value.data() length:value.size()]); - [GetCBPeripheral() writeValue:nsdata_value - forCharacteristic:cb_characteristic_ - type:CBCharacteristicWriteWithoutResponse]; - return true; -} - void BluetoothRemoteGattCharacteristicMac::SubscribeToNotifications( BluetoothRemoteGattDescriptor* ccc_descriptor, base::OnceClosure callback, @@ -407,10 +428,6 @@ bool BluetoothRemoteGattCharacteristicMac::IsWritable() const { (properties & PROPERTY_WRITE_WITHOUT_RESPONSE); } -bool BluetoothRemoteGattCharacteristicMac::IsWritableWithoutResponse() const { - return (GetProperties() & PROPERTY_WRITE_WITHOUT_RESPONSE); -} - bool BluetoothRemoteGattCharacteristicMac::SupportsNotificationsOrIndications() const { BluetoothGattCharacteristic::Properties properties = GetProperties(); diff --git a/chromium/device/bluetooth/bluetooth_remote_gatt_characteristic_unittest.cc b/chromium/device/bluetooth/bluetooth_remote_gatt_characteristic_unittest.cc index 3834b62cdd4..4581effa62f 100644 --- a/chromium/device/bluetooth/bluetooth_remote_gatt_characteristic_unittest.cc +++ b/chromium/device/bluetooth/bluetooth_remote_gatt_characteristic_unittest.cc @@ -8,6 +8,7 @@ #include <utility> #include "base/bind.h" +#include "base/logging.h" #include "base/run_loop.h" #include "base/stl_util.h" #include "base/test/bind_test_util.h" @@ -34,6 +35,7 @@ using testing::_; using testing::Invoke; +using WriteType = device::BluetoothRemoteGattCharacteristic::WriteType; namespace device { @@ -151,7 +153,7 @@ class BluetoothRemoteGattCharacteristicTest : // these two cases, this small utility function is added. bool IsClassicWin() { #if defined(OS_WIN) - return !GetParam(); + return !UsesNewBleImplementation(); #else return false; #endif @@ -419,7 +421,50 @@ TEST_F(BluetoothRemoteGattCharacteristicTest, BluetoothRemoteGattCharacteristic::PROPERTY_WRITE)); std::vector<uint8_t> empty_vector; + base::RunLoop loop; characteristic1_->WriteRemoteCharacteristic( + empty_vector, WriteType::kWithResponse, base::BindLambdaForTesting([&] { + EXPECT_EQ(1, gatt_write_characteristic_attempts_); + EXPECT_EQ(empty_vector, last_write_value_); + loop.Quit(); + }), + base::BindLambdaForTesting( + [&](BluetoothRemoteGattService::GattErrorCode error_code) { + ADD_FAILURE() << "unexpected error: " << error_code; + loop.Quit(); + })); + SimulateGattCharacteristicWrite(characteristic1_); + loop.Run(); + + // Duplicate write reported from OS shouldn't cause a problem: + SimulateGattCharacteristicWrite(characteristic1_); + base::RunLoop().RunUntilIdle(); +} + +#if defined(OS_ANDROID) || defined(OS_MACOSX) +#define MAYBE_DeprecatedWriteRemoteCharacteristic_Empty \ + DeprecatedWriteRemoteCharacteristic_Empty +#else +#define MAYBE_DeprecatedWriteRemoteCharacteristic_Empty \ + DISABLED_DeprecatedWriteRemoteCharacteristic_Empty +#endif +// Tests DeprecatedWriteRemoteCharacteristic with empty value buffer. +#if defined(OS_WIN) +TEST_P(BluetoothRemoteGattCharacteristicTestWinrt, + DeprecatedWriteRemoteCharacteristic_Empty) { +#else +TEST_F(BluetoothRemoteGattCharacteristicTest, + MAYBE_DeprecatedWriteRemoteCharacteristic_Empty) { +#endif + if (!PlatformSupportsLowEnergy()) { + LOG(WARNING) << "Low Energy Bluetooth unavailable, skipping unit test."; + return; + } + ASSERT_NO_FATAL_FAILURE(FakeCharacteristicBoilerplate( + BluetoothRemoteGattCharacteristic::PROPERTY_WRITE)); + + std::vector<uint8_t> empty_vector; + characteristic1_->DeprecatedWriteRemoteCharacteristic( empty_vector, GetCallback(Call::EXPECTED), GetGattErrorCallback(Call::NOT_EXPECTED)); SimulateGattCharacteristicWrite(characteristic1_); @@ -496,8 +541,60 @@ TEST_F(BluetoothRemoteGattCharacteristicTest, ASSERT_NO_FATAL_FAILURE(FakeCharacteristicBoilerplate( BluetoothRemoteGattCharacteristic::PROPERTY_WRITE)); - bool write_error_callback_called = false; + base::RunLoop loop; characteristic1_->WriteRemoteCharacteristic( + {} /* value */, WriteType::kWithResponse, base::BindLambdaForTesting([&] { + ADD_FAILURE() << "unexpected success"; + loop.Quit(); + }), + base::BindLambdaForTesting( + [&](BluetoothRemoteGattService::GattErrorCode error_code) { + EXPECT_EQ(BluetoothRemoteGattService::GATT_ERROR_FAILED, + error_code); + // Retrying Write should fail: + characteristic1_->WriteRemoteCharacteristic( + {} /* value */, WriteType::kWithResponse, + base::BindLambdaForTesting([&] { + ADD_FAILURE() << "unexpected success"; + loop.Quit(); + }), + base::BindLambdaForTesting( + [&](BluetoothRemoteGattService::GattErrorCode error_code) { + EXPECT_EQ( + BluetoothRemoteGattService::GATT_ERROR_IN_PROGRESS, + error_code); + loop.Quit(); + })); + })); + + DeleteDevice(device_); // TODO(576906) delete only the characteristic. + loop.Run(); +} + +#if defined(OS_ANDROID) || defined(OS_MACOSX) +#define MAYBE_Retry_DeprecatedWriteRemoteCharacteristic_DuringDestruction_Fails \ + Retry_DeprecatedWriteRemoteCharacteristic_DuringDestruction_Fails +#else +#define MAYBE_Retry_DeprecatedWriteRemoteCharacteristic_DuringDestruction_Fails \ + DISABLED_Retry_DeprecatedWriteRemoteCharacteristic_DuringDestruction_Fails +#endif +#if defined(OS_WIN) +TEST_P(BluetoothRemoteGattCharacteristicTestWinrt, + Retry_DeprecatedWriteRemoteCharacteristic_DuringDestruction_Fails) { +#else +TEST_F( + BluetoothRemoteGattCharacteristicTest, + MAYBE_Retry_DeprecatedWriteRemoteCharacteristic_DuringDestruction_Fails) { +#endif + if (!PlatformSupportsLowEnergy()) { + LOG(WARNING) << "Low Energy Bluetooth unavailable, skipping unit test."; + return; + } + ASSERT_NO_FATAL_FAILURE(FakeCharacteristicBoilerplate( + BluetoothRemoteGattCharacteristic::PROPERTY_WRITE)); + + bool write_error_callback_called = false; + characteristic1_->DeprecatedWriteRemoteCharacteristic( {} /* value */, GetCallback(Call::NOT_EXPECTED), base::BindLambdaForTesting( [&](BluetoothRemoteGattService::GattErrorCode error_code) { @@ -505,7 +602,7 @@ TEST_F(BluetoothRemoteGattCharacteristicTest, error_code); write_error_callback_called = true; // Retrying Write should fail: - characteristic1_->WriteRemoteCharacteristic( + characteristic1_->DeprecatedWriteRemoteCharacteristic( {} /* value */, GetCallback(Call::NOT_EXPECTED), GetGattErrorCallback(Call::EXPECTED)); })); @@ -617,8 +714,8 @@ TEST_F(BluetoothRemoteGattCharacteristicTest, DISABLED_WriteRemoteCharacteristic_AfterDeleted #endif // Tests WriteRemoteCharacteristic completing after Chrome objects are deleted. -// macOS: Not applicable: This can never happen if CBPeripheral delegate is set -// to nil. +// macOS: Not applicable: This can never happen if CBPeripheral +// delegate is set to nil. // WinRT: Not applicable: Pending callbacks won't fire once the underlying // object is destroyed. #if defined(OS_WIN) @@ -636,7 +733,54 @@ TEST_F(BluetoothRemoteGattCharacteristicTest, BluetoothRemoteGattCharacteristic::PROPERTY_WRITE)); std::vector<uint8_t> empty_vector; + base::RunLoop loop; characteristic1_->WriteRemoteCharacteristic( + empty_vector, WriteType::kWithResponse, base::BindLambdaForTesting([&] { + ADD_FAILURE() << "unexpected success"; + loop.Quit(); + }), + base::BindLambdaForTesting( + [&](BluetoothGattService::GattErrorCode error_code) { + EXPECT_EQ(BluetoothGattService::GATT_ERROR_FAILED, error_code); + loop.Quit(); + })); + + RememberCharacteristicForSubsequentAction(characteristic1_); + DeleteDevice(device_); // TODO(576906) delete only the characteristic. + + SimulateGattCharacteristicWrite(/* use remembered characteristic */ nullptr); + loop.Run(); +} + +#if defined(OS_ANDROID) +#define MAYBE_DeprecatedWriteRemoteCharacteristic_AfterDeleted \ + DeprecatedWriteRemoteCharacteristic_AfterDeleted +#else +#define MAYBE_DeprecatedWriteRemoteCharacteristic_AfterDeleted \ + DISABLED_DeprecatedWriteRemoteCharacteristic_AfterDeleted +#endif +// Tests DeprecatedWriteRemoteCharacteristic completing after Chrome objects are +// deleted. +// macOS: Not applicable: This can never happen if CBPeripheral +// delegate is set to nil. +// WinRT: Not applicable: Pending callbacks won't fire once the underlying +// object is destroyed. +#if defined(OS_WIN) +TEST_P(BluetoothRemoteGattCharacteristicTestWin32Only, + DeprecatedWriteRemoteCharacteristic_AfterDeleted) { +#else +TEST_F(BluetoothRemoteGattCharacteristicTest, + MAYBE_DeprecatedWriteRemoteCharacteristic_AfterDeleted) { +#endif + if (!PlatformSupportsLowEnergy()) { + LOG(WARNING) << "Low Energy Bluetooth unavailable, skipping unit test."; + return; + } + ASSERT_NO_FATAL_FAILURE(FakeCharacteristicBoilerplate( + BluetoothRemoteGattCharacteristic::PROPERTY_WRITE)); + + std::vector<uint8_t> empty_vector; + characteristic1_->DeprecatedWriteRemoteCharacteristic( empty_vector, GetCallback(Call::NOT_EXPECTED), GetGattErrorCallback(Call::EXPECTED)); @@ -671,8 +815,65 @@ TEST_F(BluetoothRemoteGattCharacteristicTest, ASSERT_NO_FATAL_FAILURE(FakeCharacteristicBoilerplate( BluetoothRemoteGattCharacteristic::PROPERTY_WRITE)); + base::RunLoop loop; std::vector<uint8_t> empty_vector; characteristic1_->WriteRemoteCharacteristic( + empty_vector, WriteType::kWithResponse, base::BindLambdaForTesting([&] { + ADD_FAILURE() << "unexpected success"; + loop.Quit(); + }), + base::BindLambdaForTesting( + [&](BluetoothRemoteGattService::GattErrorCode error_code) { + EXPECT_EQ(BluetoothRemoteGattService::GATT_ERROR_FAILED, + error_code); + loop.Quit(); + })); + +// Set up for receiving a write response after disconnection. +// On macOS and WinRT no events arrive after disconnection so there is no point +// in building the infrastructure to test this behavior. FYI +// the code CHECKs that responses arrive only when the device is connected. +#if defined(OS_ANDROID) + RememberCharacteristicForSubsequentAction(characteristic1_); +#endif // defined(OS_ANDROID) + + ASSERT_EQ(1u, adapter_->GetDevices().size()); + SimulateDeviceBreaksConnection(adapter_->GetDevices()[0]); + loop.Run(); + +// Dispatch write response after disconnection. See above explanation for why +// we don't do this in macOS and WinRT. +#if defined(OS_ANDROID) + SimulateGattCharacteristicWrite(/* use remembered characteristic */ nullptr); + base::RunLoop().RunUntilIdle(); +#endif // defined(OS_ANDROID) +} + +// TODO(crbug.com/663131): Enable test on windows when disconnection is +// implemented. +#if defined(OS_ANDROID) || defined(OS_MACOSX) +#define MAYBE_DeprecatedWriteRemoteCharacteristic_Disconnected \ + DeprecatedWriteRemoteCharacteristic_Disconnected +#else +#define MAYBE_DeprecatedWriteRemoteCharacteristic_Disconnected \ + DISABLED_DeprecatedWriteRemoteCharacteristic_Disconnected +#endif +#if defined(OS_WIN) +TEST_P(BluetoothRemoteGattCharacteristicTestWinrtOnly, + DeprecatedWriteRemoteCharacteristic_Disconnected) { +#else +TEST_F(BluetoothRemoteGattCharacteristicTest, + MAYBE_DeprecatedWriteRemoteCharacteristic_Disconnected) { +#endif + if (!PlatformSupportsLowEnergy()) { + LOG(WARNING) << "Low Energy Bluetooth unavailable, skipping unit test."; + return; + } + ASSERT_NO_FATAL_FAILURE(FakeCharacteristicBoilerplate( + BluetoothRemoteGattCharacteristic::PROPERTY_WRITE)); + + std::vector<uint8_t> empty_vector; + characteristic1_->DeprecatedWriteRemoteCharacteristic( empty_vector, GetCallback(Call::NOT_EXPECTED), GetGattErrorCallback(Call::EXPECTED)); @@ -780,8 +981,8 @@ TEST_F(BluetoothRemoteGattCharacteristicTest, base::RunLoop().RunUntilIdle(); EXPECT_EQ(0, observer.gatt_characteristic_value_changed_count()); -// TODO(https://crbug.com/699694): Remove this #if once the bug on Windows is -// fixed. + // TODO(https://crbug.com/699694): Remove this #if once the bug on Windows is + // fixed. if (IsClassicWin()) { EXPECT_FALSE(observer.last_gatt_characteristic_id().empty()); EXPECT_TRUE(observer.last_gatt_characteristic_uuid().IsValid()); @@ -812,9 +1013,57 @@ TEST_F(BluetoothRemoteGattCharacteristicTest, MAYBE_WriteRemoteCharacteristic) { TestBluetoothAdapterObserver observer(adapter_); + base::RunLoop loop; uint8_t values[] = {0, 1, 2, 3, 4, 0xf, 0xf0, 0xff}; std::vector<uint8_t> test_vector(values, values + base::size(values)); characteristic1_->WriteRemoteCharacteristic( + test_vector, WriteType::kWithResponse, base::BindLambdaForTesting([&] { + EXPECT_EQ(1, gatt_write_characteristic_attempts_); + + // TODO(crbug.com/653291): remove this if once the bug on windows is + // fixed. + if (!IsClassicWin()) + EXPECT_EQ(0, observer.gatt_characteristic_value_changed_count()); + EXPECT_EQ(test_vector, last_write_value_); + loop.Quit(); + }), + base::BindLambdaForTesting( + [&](BluetoothGattService::GattErrorCode error_code) { + ADD_FAILURE() << "unexpected error: " << error_code; + loop.Quit(); + })); + + SimulateGattCharacteristicWrite(characteristic1_); + loop.Run(); +} + +#if defined(OS_ANDROID) || defined(OS_MACOSX) +#define MAYBE_DeprecatedWriteRemoteCharacteristic \ + DeprecatedWriteRemoteCharacteristic +#else +#define MAYBE_DeprecatedWriteRemoteCharacteristic \ + DISABLED_DeprecatedWriteRemoteCharacteristic +#endif +// Tests DeprecatedWriteRemoteCharacteristic with non-empty value buffer. +#if defined(OS_WIN) +TEST_P(BluetoothRemoteGattCharacteristicTestWinrt, + DeprecatedWriteRemoteCharacteristic) { +#else +TEST_F(BluetoothRemoteGattCharacteristicTest, + MAYBE_DeprecatedWriteRemoteCharacteristic) { +#endif + if (!PlatformSupportsLowEnergy()) { + LOG(WARNING) << "Low Energy Bluetooth unavailable, skipping unit test."; + return; + } + ASSERT_NO_FATAL_FAILURE(FakeCharacteristicBoilerplate( + BluetoothRemoteGattCharacteristic::PROPERTY_WRITE)); + + TestBluetoothAdapterObserver observer(adapter_); + + uint8_t values[] = {0, 1, 2, 3, 4, 0xf, 0xf0, 0xff}; + std::vector<uint8_t> test_vector(values, values + base::size(values)); + characteristic1_->DeprecatedWriteRemoteCharacteristic( test_vector, GetCallback(Call::EXPECTED), GetGattErrorCallback(Call::NOT_EXPECTED)); @@ -899,9 +1148,69 @@ TEST_F(BluetoothRemoteGattCharacteristicTest, ASSERT_NO_FATAL_FAILURE(FakeCharacteristicBoilerplate( BluetoothRemoteGattCharacteristic::PROPERTY_WRITE)); + base::RunLoop loop1; uint8_t values[] = {0, 1, 2, 3, 4, 0xf, 0xf0, 0xff}; std::vector<uint8_t> test_vector(values, values + base::size(values)); characteristic1_->WriteRemoteCharacteristic( + test_vector, WriteType::kWithResponse, base::BindLambdaForTesting([&] { + EXPECT_EQ(1, gatt_write_characteristic_attempts_); + EXPECT_EQ(test_vector, last_write_value_); + loop1.Quit(); + }), + base::BindLambdaForTesting( + [&](BluetoothGattService::GattErrorCode error_code) { + ADD_FAILURE() << "unexpected error" << error_code; + loop1.Quit(); + })); + + SimulateGattCharacteristicWrite(characteristic1_); + loop1.Run(); + + // Write again, with different value: + ResetEventCounts(); + base::RunLoop loop2; + std::vector<uint8_t> empty_vector; + characteristic1_->WriteRemoteCharacteristic( + empty_vector, WriteType::kWithResponse, base::BindLambdaForTesting([&] { + EXPECT_EQ(1, gatt_write_characteristic_attempts_); + EXPECT_EQ(empty_vector, last_write_value_); + loop2.Quit(); + }), + base::BindLambdaForTesting( + [&](BluetoothGattService::GattErrorCode error_code) { + ADD_FAILURE() << "unexpected error" << error_code; + loop2.Quit(); + })); + + SimulateGattCharacteristicWrite(characteristic1_); + loop2.Run(); +} + +#if defined(OS_ANDROID) || defined(OS_MACOSX) +#define MAYBE_DeprecatedWriteRemoteCharacteristic_Twice \ + DeprecatedWriteRemoteCharacteristic_Twice +#else +#define MAYBE_DeprecatedWriteRemoteCharacteristic_Twice \ + DISABLED_DeprecatedWriteRemoteCharacteristic_Twice +#endif +// Tests DeprecatedWriteRemoteCharacteristic multiple times. +#if defined(OS_WIN) +TEST_P(BluetoothRemoteGattCharacteristicTestWinrt, + DeprecatedWriteRemoteCharacteristic_Twice) { +#else +TEST_F(BluetoothRemoteGattCharacteristicTest, + MAYBE_DeprecatedWriteRemoteCharacteristic_Twice) { +#endif + if (!PlatformSupportsLowEnergy()) { + LOG(WARNING) << "Low Energy Bluetooth unavailable, skipping unit test."; + return; + } + ASSERT_NO_FATAL_FAILURE(FakeCharacteristicBoilerplate( + BluetoothRemoteGattCharacteristic::PROPERTY_WRITE)); + + uint8_t values[] = {0, 1, 2, 3, 4, 0xf, 0xf0, 0xff}; + std::vector<uint8_t> test_vector(values, values + base::size(values)); + characteristic1_->DeprecatedWriteRemoteCharacteristic( test_vector, GetCallback(Call::EXPECTED), GetGattErrorCallback(Call::NOT_EXPECTED)); @@ -915,7 +1224,7 @@ TEST_F(BluetoothRemoteGattCharacteristicTest, // Write again, with different value: ResetEventCounts(); std::vector<uint8_t> empty_vector; - characteristic1_->WriteRemoteCharacteristic( + characteristic1_->DeprecatedWriteRemoteCharacteristic( empty_vector, GetCallback(Call::EXPECTED), GetGattErrorCallback(Call::NOT_EXPECTED)); @@ -999,9 +1308,76 @@ TEST_F(BluetoothRemoteGattCharacteristicTest, ASSERT_NO_FATAL_FAILURE(FakeCharacteristicBoilerplate( BluetoothRemoteGattCharacteristic::PROPERTY_WRITE)); + base::RunLoop loop1; std::vector<uint8_t> test_vector1; test_vector1.push_back(111); characteristic1_->WriteRemoteCharacteristic( + test_vector1, WriteType::kWithResponse, base::BindLambdaForTesting([&] { + if (IsClassicWin()) { + EXPECT_EQ(test_vector1, last_write_value_); + } + loop1.Quit(); + }), + base::BindLambdaForTesting( + [&](BluetoothGattService::GattErrorCode error_code) { + ADD_FAILURE() << "unexpected error" << error_code; + loop1.Quit(); + })); + if (!IsClassicWin()) { + EXPECT_EQ(test_vector1, last_write_value_); + } + + base::RunLoop loop2; + std::vector<uint8_t> test_vector2; + test_vector2.push_back(222); + characteristic2_->WriteRemoteCharacteristic( + test_vector2, WriteType::kWithResponse, base::BindLambdaForTesting([&] { + if (IsClassicWin()) { + EXPECT_EQ(test_vector2, last_write_value_); + } + loop2.Quit(); + }), + base::BindLambdaForTesting( + [&](BluetoothGattService::GattErrorCode error_code) { + ADD_FAILURE() << "unexpected error" << error_code; + loop2.Quit(); + })); + if (!IsClassicWin()) { + EXPECT_EQ(test_vector2, last_write_value_); + } + + SimulateGattCharacteristicWrite(characteristic1_); + loop1.Run(); + + SimulateGattCharacteristicWrite(characteristic2_); + loop2.Run(); +} + +#if defined(OS_ANDROID) || defined(OS_MACOSX) +#define MAYBE_DeprecatedWriteRemoteCharacteristic_MultipleCharacteristics \ + DeprecatedWriteRemoteCharacteristic_MultipleCharacteristics +#else +#define MAYBE_DeprecatedWriteRemoteCharacteristic_MultipleCharacteristics \ + DISABLED_DeprecatedWriteRemoteCharacteristic_MultipleCharacteristics +#endif +// Tests DeprecatedWriteRemoteCharacteristic on two characteristics. +#if defined(OS_WIN) +TEST_P(BluetoothRemoteGattCharacteristicTestWinrt, + DeprecatedWriteRemoteCharacteristic_MultipleCharacteristics) { +#else +TEST_F(BluetoothRemoteGattCharacteristicTest, + MAYBE_DeprecatedWriteRemoteCharacteristic_MultipleCharacteristics) { +#endif + if (!PlatformSupportsLowEnergy()) { + LOG(WARNING) << "Low Energy Bluetooth unavailable, skipping unit test."; + return; + } + ASSERT_NO_FATAL_FAILURE(FakeCharacteristicBoilerplate( + BluetoothRemoteGattCharacteristic::PROPERTY_WRITE)); + + std::vector<uint8_t> test_vector1; + test_vector1.push_back(111); + characteristic1_->DeprecatedWriteRemoteCharacteristic( test_vector1, GetCallback(Call::EXPECTED), GetGattErrorCallback(Call::NOT_EXPECTED)); if (!IsClassicWin()) @@ -1009,7 +1385,7 @@ TEST_F(BluetoothRemoteGattCharacteristicTest, std::vector<uint8_t> test_vector2; test_vector2.push_back(222); - characteristic2_->WriteRemoteCharacteristic( + characteristic2_->DeprecatedWriteRemoteCharacteristic( test_vector2, GetCallback(Call::EXPECTED), GetGattErrorCallback(Call::NOT_EXPECTED)); if (!IsClassicWin()) @@ -1110,10 +1486,67 @@ TEST_F(BluetoothRemoteGattCharacteristicTest, ASSERT_NO_FATAL_FAILURE(FakeCharacteristicBoilerplate( BluetoothRemoteGattCharacteristic::PROPERTY_WRITE)); + base::RunLoop loop; std::vector<uint8_t> test_vector_1 = {0, 1, 2, 3, 4}; std::vector<uint8_t> test_vector_2 = {0xf, 0xf0, 0xff}; characteristic1_->WriteRemoteCharacteristic( + test_vector_1, WriteType::kWithResponse, base::BindLambdaForTesting([&] { + EXPECT_EQ(1, gatt_write_characteristic_attempts_); + EXPECT_EQ(test_vector_1, last_write_value_); + + characteristic1_->WriteRemoteCharacteristic( + test_vector_2, WriteType::kWithResponse, + base::BindLambdaForTesting([&] { + EXPECT_EQ(2, gatt_write_characteristic_attempts_); + EXPECT_EQ(test_vector_2, last_write_value_); + loop.Quit(); + }), + base::BindLambdaForTesting( + [&](BluetoothGattService::GattErrorCode error_code) { + ADD_FAILURE() << "unexpected error: " << error_code; + loop.Quit(); + })); + + SimulateGattCharacteristicWrite(characteristic1_); + }), + base::BindLambdaForTesting( + [&](BluetoothGattService::GattErrorCode error_code) { + ADD_FAILURE() << "unexpected error: " << error_code; + loop.Quit(); + })); + + SimulateGattCharacteristicWrite(characteristic1_); + loop.Run(); +} + +#if defined(OS_ANDROID) || defined(OS_MACOSX) +#define MAYBE_RemoteCharacteristic_Nested_DeprecatedWrite_DeprecatedWrite \ + RemoteCharacteristic_Nested_DeprecatedWrite_DeprecatedWrite +#else +#define MAYBE_RemoteCharacteristic_Nested_DeprecatedWrite_DeprecatedWrite \ + DISABLED_RemoteCharacteristic_Nested_DeprecatedWrite_DeprecatedWrite +#endif +// Tests a nested DeprecatedWriteRemoteCharacteristic from within another +// DeprecatedWriteRemoteCharacteristic. +#if defined(OS_WIN) +TEST_P(BluetoothRemoteGattCharacteristicTestWinrt, + RemoteCharacteristic_Nested_DeprecatedWrite_DeprecatedWrite) { +#else +TEST_F(BluetoothRemoteGattCharacteristicTest, + MAYBE_RemoteCharacteristic_Nested_DeprecatedWrite_DeprecatedWrite) { +#endif + if (!PlatformSupportsLowEnergy()) { + LOG(WARNING) << "Low Energy Bluetooth unavailable, skipping unit test."; + return; + } + ASSERT_NO_FATAL_FAILURE(FakeCharacteristicBoilerplate( + BluetoothRemoteGattCharacteristic::PROPERTY_WRITE)); + + std::vector<uint8_t> test_vector_1 = {0, 1, 2, 3, 4}; + std::vector<uint8_t> test_vector_2 = {0xf, 0xf0, 0xff}; + + characteristic1_->DeprecatedWriteRemoteCharacteristic( test_vector_1, base::BindLambdaForTesting([&] { GetCallback(Call::EXPECTED).Run(); @@ -1122,7 +1555,7 @@ TEST_F(BluetoothRemoteGattCharacteristicTest, EXPECT_EQ(0, error_callback_count_); EXPECT_EQ(test_vector_1, last_write_value_); - characteristic1_->WriteRemoteCharacteristic( + characteristic1_->DeprecatedWriteRemoteCharacteristic( test_vector_2, GetCallback(Call::EXPECTED), GetGattErrorCallback(Call::NOT_EXPECTED)); SimulateGattCharacteristicWrite(characteristic1_); @@ -1162,6 +1595,67 @@ TEST_F(BluetoothRemoteGattCharacteristicTest, BluetoothRemoteGattCharacteristic::PROPERTY_READ | BluetoothRemoteGattCharacteristic::PROPERTY_WRITE)); + base::RunLoop loop; + std::vector<uint8_t> test_vector_1 = {0, 1, 2, 3, 4}; + std::vector<uint8_t> test_vector_2 = {0xf, 0xf0, 0xff}; + + characteristic1_->ReadRemoteCharacteristic( + base::BindLambdaForTesting([&](const std::vector<uint8_t>& data) { + EXPECT_EQ(1, gatt_read_characteristic_attempts_); + EXPECT_EQ(0, gatt_write_characteristic_attempts_); + EXPECT_EQ(test_vector_1, data); + EXPECT_EQ(test_vector_1, characteristic1_->GetValue()); + + characteristic1_->WriteRemoteCharacteristic( + test_vector_2, WriteType::kWithResponse, + base::BindLambdaForTesting([&] { + EXPECT_EQ(1, gatt_read_characteristic_attempts_); + EXPECT_EQ(1, gatt_write_characteristic_attempts_); + EXPECT_EQ(test_vector_2, last_write_value_); + loop.Quit(); + }), + base::BindLambdaForTesting( + [&](BluetoothGattService::GattErrorCode error_code) { + ADD_FAILURE() << "unexpected error: " << error_code; + loop.Quit(); + })); + + SimulateGattCharacteristicWrite(characteristic1_); + }), + base::BindLambdaForTesting( + [&](BluetoothGattService::GattErrorCode error_code) { + ADD_FAILURE() << "unexpected error: " << error_code; + loop.Quit(); + })); + + SimulateGattCharacteristicRead(characteristic1_, test_vector_1); + loop.Run(); +} + +#if defined(OS_ANDROID) || defined(OS_MACOSX) +#define MAYBE_RemoteCharacteristic_Nested_Read_DeprecatedWrite \ + RemoteCharacteristic_Nested_Read_DeprecatedWrite +#else +#define MAYBE_RemoteCharacteristic_Nested_Read_DeprecatedWrite \ + DISABLED_RemoteCharacteristic_Nested_Read_DeprecatedWrite +#endif +// Tests a nested DeprecatedWriteRemoteCharacteristic from within a +// ReadRemoteCharacteristic. +#if defined(OS_WIN) +TEST_P(BluetoothRemoteGattCharacteristicTestWinrt, + RemoteCharacteristic_Nested_Read_DeprecatedWrite) { +#else +TEST_F(BluetoothRemoteGattCharacteristicTest, + MAYBE_RemoteCharacteristic_Nested_Read_DeprecatedWrite) { +#endif + if (!PlatformSupportsLowEnergy()) { + LOG(WARNING) << "Low Energy Bluetooth unavailable, skipping unit test."; + return; + } + ASSERT_NO_FATAL_FAILURE(FakeCharacteristicBoilerplate( + BluetoothRemoteGattCharacteristic::PROPERTY_READ | + BluetoothRemoteGattCharacteristic::PROPERTY_WRITE)); + std::vector<uint8_t> test_vector_1 = {0, 1, 2, 3, 4}; std::vector<uint8_t> test_vector_2 = {0xf, 0xf0, 0xff}; @@ -1176,7 +1670,7 @@ TEST_F(BluetoothRemoteGattCharacteristicTest, EXPECT_EQ(test_vector_1, last_read_value_); EXPECT_EQ(test_vector_1, characteristic1_->GetValue()); - characteristic1_->WriteRemoteCharacteristic( + characteristic1_->DeprecatedWriteRemoteCharacteristic( test_vector_2, GetCallback(Call::EXPECTED), GetGattErrorCallback(Call::NOT_EXPECTED)); SimulateGattCharacteristicWrite(characteristic1_); @@ -1216,10 +1710,69 @@ TEST_F(BluetoothRemoteGattCharacteristicTest, BluetoothRemoteGattCharacteristic::PROPERTY_READ | BluetoothRemoteGattCharacteristic::PROPERTY_WRITE)); + base::RunLoop loop; std::vector<uint8_t> test_vector_1 = {0, 1, 2, 3, 4}; std::vector<uint8_t> test_vector_2 = {0xf, 0xf0, 0xff}; characteristic1_->WriteRemoteCharacteristic( + test_vector_1, WriteType::kWithResponse, base::BindLambdaForTesting([&] { + EXPECT_EQ(0, gatt_read_characteristic_attempts_); + EXPECT_EQ(1, gatt_write_characteristic_attempts_); + EXPECT_EQ(test_vector_1, last_write_value_); + + characteristic1_->ReadRemoteCharacteristic( + base::BindLambdaForTesting([&](const std::vector<uint8_t>& data) { + EXPECT_EQ(1, gatt_read_characteristic_attempts_); + EXPECT_EQ(1, gatt_write_characteristic_attempts_); + EXPECT_EQ(test_vector_2, data); + EXPECT_EQ(test_vector_2, characteristic1_->GetValue()); + loop.Quit(); + }), + base::BindLambdaForTesting( + [&](BluetoothGattService::GattErrorCode error_code) { + ADD_FAILURE() << "unexpected error: " << error_code; + loop.Quit(); + })); + SimulateGattCharacteristicRead(characteristic1_, test_vector_2); + }), + base::BindLambdaForTesting( + [&](BluetoothGattService::GattErrorCode error_code) { + ADD_FAILURE() << "unexpected error: " << error_code; + loop.Quit(); + })); + + SimulateGattCharacteristicWrite(characteristic1_); + loop.Run(); +} + +#if defined(OS_ANDROID) || defined(OS_MACOSX) +#define MAYBE_RemoteCharacteristic_Nested_DeprecatedWrite_Read \ + RemoteCharacteristic_Nested_DeprecatedWrite_Read +#else +#define MAYBE_RemoteCharacteristic_Nested_DeprecatedWrite_Read \ + DISABLED_RemoteCharacteristic_Nested_DeprecatedWrite_Read +#endif +// Tests a nested ReadRemoteCharacteristic from within a +// DeprecatedWriteRemoteCharacteristic. +#if defined(OS_WIN) +TEST_P(BluetoothRemoteGattCharacteristicTestWinrt, + RemoteCharacteristic_Nested_DeprecatedWrite_Read) { +#else +TEST_F(BluetoothRemoteGattCharacteristicTest, + MAYBE_RemoteCharacteristic_Nested_DeprecatedWrite_Read) { +#endif + if (!PlatformSupportsLowEnergy()) { + LOG(WARNING) << "Low Energy Bluetooth unavailable, skipping unit test."; + return; + } + ASSERT_NO_FATAL_FAILURE(FakeCharacteristicBoilerplate( + BluetoothRemoteGattCharacteristic::PROPERTY_READ | + BluetoothRemoteGattCharacteristic::PROPERTY_WRITE)); + + std::vector<uint8_t> test_vector_1 = {0, 1, 2, 3, 4}; + std::vector<uint8_t> test_vector_2 = {0xf, 0xf0, 0xff}; + + characteristic1_->DeprecatedWriteRemoteCharacteristic( test_vector_1, base::BindLambdaForTesting([&] { GetCallback(Call::EXPECTED).Run(); @@ -1297,8 +1850,47 @@ TEST_F(BluetoothRemoteGattCharacteristicTest, MAYBE_WriteError) { ASSERT_NO_FATAL_FAILURE(FakeCharacteristicBoilerplate( BluetoothRemoteGattCharacteristic::PROPERTY_WRITE)); + base::RunLoop loop; std::vector<uint8_t> empty_vector; characteristic1_->WriteRemoteCharacteristic( + empty_vector, WriteType::kWithResponse, base::BindLambdaForTesting([&] { + ADD_FAILURE() << "unexpected success"; + loop.Quit(); + }), + base::BindLambdaForTesting( + [&](BluetoothGattService::GattErrorCode error_code) { + EXPECT_EQ(BluetoothRemoteGattService::GATT_ERROR_INVALID_LENGTH, + error_code); + loop.Quit(); + })); + SimulateGattCharacteristicWriteError( + characteristic1_, BluetoothRemoteGattService::GATT_ERROR_INVALID_LENGTH); + // Only the error above should be reported to the caller. + SimulateGattCharacteristicWriteError( + characteristic1_, BluetoothRemoteGattService::GATT_ERROR_FAILED); + loop.Run(); +} + +#if defined(OS_ANDROID) || defined(OS_MACOSX) +#define MAYBE_DeprecatedWriteError DeprecatedWriteError +#else +#define MAYBE_DeprecatedWriteError DISABLED_DeprecatedWriteError +#endif +// Tests DeprecatedWriteRemoteCharacteristic asynchronous error. +#if defined(OS_WIN) +TEST_P(BluetoothRemoteGattCharacteristicTestWinrt, DeprecatedWriteError) { +#else +TEST_F(BluetoothRemoteGattCharacteristicTest, MAYBE_DeprecatedWriteError) { +#endif + if (!PlatformSupportsLowEnergy()) { + LOG(WARNING) << "Low Energy Bluetooth unavailable, skipping unit test."; + return; + } + ASSERT_NO_FATAL_FAILURE(FakeCharacteristicBoilerplate( + BluetoothRemoteGattCharacteristic::PROPERTY_WRITE)); + + std::vector<uint8_t> empty_vector; + characteristic1_->DeprecatedWriteRemoteCharacteristic( empty_vector, GetCallback(Call::NOT_EXPECTED), GetGattErrorCallback(Call::EXPECTED)); SimulateGattCharacteristicWriteError( @@ -1358,8 +1950,54 @@ TEST_F(BluetoothRemoteGattCharacteristicTest, MAYBE_WriteSynchronousError) { ASSERT_NO_FATAL_FAILURE(FakeCharacteristicBoilerplate()); SimulateGattCharacteristicWriteWillFailSynchronouslyOnce(characteristic1_); + base::RunLoop loop1; std::vector<uint8_t> empty_vector; characteristic1_->WriteRemoteCharacteristic( + empty_vector, WriteType::kWithResponse, base::BindLambdaForTesting([&] { + ADD_FAILURE() << "unexpected success"; + loop1.Quit(); + }), + base::BindLambdaForTesting( + [&](BluetoothGattService::GattErrorCode error_code) { + EXPECT_EQ(BluetoothRemoteGattService::GATT_ERROR_FAILED, + error_code); + loop1.Quit(); + })); + loop1.Run(); + + // After failing once, can succeed: + ResetEventCounts(); + base::RunLoop loop2; + characteristic1_->WriteRemoteCharacteristic( + empty_vector, WriteType::kWithResponse, base::BindLambdaForTesting([&] { + SUCCEED(); + loop2.Quit(); + }), + base::BindLambdaForTesting( + [&](BluetoothGattService::GattErrorCode error_code) { + ADD_FAILURE() << "unexpected error: " << error_code; + loop2.Quit(); + })); + SimulateGattCharacteristicWrite(characteristic1_); + loop2.Run(); +} + +#if defined(OS_ANDROID) +#define MAYBE_DeprecatedWriteSynchronousError DeprecatedWriteSynchronousError +#else +#define MAYBE_DeprecatedWriteSynchronousError \ + DISABLED_DeprecatedWriteSynchronousError +#endif +// Tests DeprecatedWriteRemoteCharacteristic synchronous error. +// This test doesn't apply to macOS and WinRT since a synchronous API does not +// exist. +TEST_F(BluetoothRemoteGattCharacteristicTest, + MAYBE_DeprecatedWriteSynchronousError) { + ASSERT_NO_FATAL_FAILURE(FakeCharacteristicBoilerplate()); + + SimulateGattCharacteristicWriteWillFailSynchronouslyOnce(characteristic1_); + std::vector<uint8_t> empty_vector; + characteristic1_->DeprecatedWriteRemoteCharacteristic( empty_vector, GetCallback(Call::NOT_EXPECTED), GetGattErrorCallback(Call::EXPECTED)); EXPECT_EQ(0, gatt_write_characteristic_attempts_); @@ -1371,7 +2009,7 @@ TEST_F(BluetoothRemoteGattCharacteristicTest, MAYBE_WriteSynchronousError) { // After failing once, can succeed: ResetEventCounts(); - characteristic1_->WriteRemoteCharacteristic( + characteristic1_->DeprecatedWriteRemoteCharacteristic( empty_vector, GetCallback(Call::EXPECTED), GetGattErrorCallback(Call::NOT_EXPECTED)); EXPECT_EQ(1, gatt_write_characteristic_attempts_); @@ -1433,7 +2071,8 @@ TEST_F(BluetoothRemoteGattCharacteristicTest, #define MAYBE_WriteRemoteCharacteristic_WritePending \ DISABLED_WriteRemoteCharacteristic_WritePending #endif -// Tests WriteRemoteCharacteristic error with a pending write operation. +// Tests WriteRemoteCharacteristic error with a pending write +// operation. #if defined(OS_WIN) TEST_P(BluetoothRemoteGattCharacteristicTestWinrt, WriteRemoteCharacteristic_WritePending) { @@ -1448,11 +2087,67 @@ TEST_F(BluetoothRemoteGattCharacteristicTest, ASSERT_NO_FATAL_FAILURE(FakeCharacteristicBoilerplate( BluetoothRemoteGattCharacteristic::PROPERTY_WRITE)); + base::RunLoop loop1; std::vector<uint8_t> empty_vector; characteristic1_->WriteRemoteCharacteristic( + empty_vector, WriteType::kWithResponse, base::BindLambdaForTesting([&] { + SUCCEED(); + loop1.Quit(); + }), + base::BindLambdaForTesting( + [&](BluetoothGattService::GattErrorCode error_code) { + ADD_FAILURE() << "unexpected error: " << error_code; + loop1.Quit(); + })); + base::RunLoop loop2; + characteristic1_->WriteRemoteCharacteristic( + empty_vector, WriteType::kWithResponse, base::BindLambdaForTesting([&] { + ADD_FAILURE() << "unexpected success"; + loop2.Quit(); + }), + base::BindLambdaForTesting( + [&](BluetoothGattService::GattErrorCode error_code) { + EXPECT_EQ(BluetoothRemoteGattService::GATT_ERROR_IN_PROGRESS, + error_code); + loop2.Quit(); + })); + + loop2.Run(); + + // Initial write should still succeed: + ResetEventCounts(); + SimulateGattCharacteristicWrite(characteristic1_); + loop1.Run(); +} + +#if defined(OS_ANDROID) || defined(OS_MACOSX) +#define MAYBE_DeprecatedWriteRemoteCharacteristic_WritePending \ + DeprecatedWriteRemoteCharacteristic_WritePending +#else +#define MAYBE_DeprecatedWriteRemoteCharacteristic_WritePending \ + DISABLED_DeprecatedWriteRemoteCharacteristic_WritePending +#endif +// Tests DeprecatedWriteRemoteCharacteristic error with a pending write +// operation. +#if defined(OS_WIN) +TEST_P(BluetoothRemoteGattCharacteristicTestWinrt, + DeprecatedWriteRemoteCharacteristic_WritePending) { +#else +TEST_F(BluetoothRemoteGattCharacteristicTest, + MAYBE_DeprecatedWriteRemoteCharacteristic_WritePending) { +#endif + if (!PlatformSupportsLowEnergy()) { + LOG(WARNING) << "Low Energy Bluetooth unavailable, skipping unit test."; + return; + } + ASSERT_NO_FATAL_FAILURE(FakeCharacteristicBoilerplate( + BluetoothRemoteGattCharacteristic::PROPERTY_WRITE)); + + std::vector<uint8_t> empty_vector; + characteristic1_->DeprecatedWriteRemoteCharacteristic( empty_vector, GetCallback(Call::EXPECTED), GetGattErrorCallback(Call::NOT_EXPECTED)); - characteristic1_->WriteRemoteCharacteristic( + characteristic1_->DeprecatedWriteRemoteCharacteristic( empty_vector, GetCallback(Call::NOT_EXPECTED), GetGattErrorCallback(Call::EXPECTED)); @@ -1494,8 +2189,64 @@ TEST_F(BluetoothRemoteGattCharacteristicTest, BluetoothRemoteGattCharacteristic::PROPERTY_READ | BluetoothRemoteGattCharacteristic::PROPERTY_WRITE)); + base::RunLoop loop1; + base::RunLoop loop2; std::vector<uint8_t> empty_vector; characteristic1_->WriteRemoteCharacteristic( + empty_vector, WriteType::kWithResponse, base::BindLambdaForTesting([&] { + SUCCEED(); + loop1.Quit(); + }), + base::BindLambdaForTesting( + [&](BluetoothGattService::GattErrorCode error_code) { + ADD_FAILURE() << "unexpected error: " << error_code; + loop1.Quit(); + })); + characteristic1_->ReadRemoteCharacteristic( + base::BindLambdaForTesting([&](const std::vector<uint8_t>& data) { + ADD_FAILURE() << "unexpected success"; + loop2.Quit(); + }), + base::BindLambdaForTesting( + [&](BluetoothGattService::GattErrorCode error_code) { + EXPECT_EQ(BluetoothRemoteGattService::GATT_ERROR_IN_PROGRESS, + error_code); + loop2.Quit(); + })); + + loop2.Run(); + + // Initial write should still succeed: + ResetEventCounts(); + SimulateGattCharacteristicWrite(characteristic1_); + loop1.Run(); +} + +#if defined(OS_ANDROID) || defined(OS_MACOSX) +#define MAYBE_ReadRemoteCharacteristic_DeprecatedWritePending \ + ReadRemoteCharacteristic_DeprecatedWritePending +#else +#define MAYBE_ReadRemoteCharacteristic_DeprecatedWritePending \ + DISABLED_ReadRemoteCharacteristic_DeprecatedWritePending +#endif +// Tests ReadRemoteCharacteristic error with a pending write operation. +#if defined(OS_WIN) +TEST_P(BluetoothRemoteGattCharacteristicTestWinrt, + ReadRemoteCharacteristic_DeprecatedWritePending) { +#else +TEST_F(BluetoothRemoteGattCharacteristicTest, + MAYBE_ReadRemoteCharacteristic_DeprecatedWritePending) { +#endif + if (!PlatformSupportsLowEnergy()) { + LOG(WARNING) << "Low Energy Bluetooth unavailable, skipping unit test."; + return; + } + ASSERT_NO_FATAL_FAILURE(FakeCharacteristicBoilerplate( + BluetoothRemoteGattCharacteristic::PROPERTY_READ | + BluetoothRemoteGattCharacteristic::PROPERTY_WRITE)); + + std::vector<uint8_t> empty_vector; + characteristic1_->DeprecatedWriteRemoteCharacteristic( empty_vector, GetCallback(Call::EXPECTED), GetGattErrorCallback(Call::NOT_EXPECTED)); characteristic1_->ReadRemoteCharacteristic( @@ -1540,11 +2291,67 @@ TEST_F(BluetoothRemoteGattCharacteristicTest, BluetoothRemoteGattCharacteristic::PROPERTY_READ | BluetoothRemoteGattCharacteristic::PROPERTY_WRITE)); + base::RunLoop loop1; + base::RunLoop loop2; + std::vector<uint8_t> empty_vector; + characteristic1_->ReadRemoteCharacteristic( + base::BindLambdaForTesting([&](const std::vector<uint8_t>& data) { + SUCCEED(); + loop1.Quit(); + }), + base::BindLambdaForTesting( + [&](BluetoothGattService::GattErrorCode error_code) { + ADD_FAILURE() << "unexpected error: " << error_code; + loop1.Quit(); + })); + characteristic1_->WriteRemoteCharacteristic( + empty_vector, WriteType::kWithResponse, base::BindLambdaForTesting([&] { + ADD_FAILURE() << "unexpected success"; + loop2.Quit(); + }), + base::BindLambdaForTesting( + [&](BluetoothGattService::GattErrorCode error_code) { + EXPECT_EQ(BluetoothRemoteGattService::GATT_ERROR_IN_PROGRESS, + error_code); + loop2.Quit(); + })); + loop2.Run(); + + // Initial read should still succeed: + ResetEventCounts(); + SimulateGattCharacteristicRead(characteristic1_, empty_vector); + loop1.Run(); +} + +#if defined(OS_ANDROID) || defined(OS_MACOSX) +#define MAYBE_DeprecatedWriteRemoteCharacteristic_ReadPending \ + DeprecatedWriteRemoteCharacteristic_ReadPending +#else +#define MAYBE_DeprecatedWriteRemoteCharacteristic_ReadPending \ + DISABLED_DeprecatedWriteRemoteCharacteristic_ReadPending +#endif +// Tests DeprecatedWriteRemoteCharacteristic error with a pending Read +// operation. +#if defined(OS_WIN) +TEST_P(BluetoothRemoteGattCharacteristicTestWinrt, + DeprecatedWriteRemoteCharacteristic_ReadPending) { +#else +TEST_F(BluetoothRemoteGattCharacteristicTest, + MAYBE_DeprecatedWriteRemoteCharacteristic_ReadPending) { +#endif + if (!PlatformSupportsLowEnergy()) { + LOG(WARNING) << "Low Energy Bluetooth unavailable, skipping unit test."; + return; + } + ASSERT_NO_FATAL_FAILURE(FakeCharacteristicBoilerplate( + BluetoothRemoteGattCharacteristic::PROPERTY_READ | + BluetoothRemoteGattCharacteristic::PROPERTY_WRITE)); + std::vector<uint8_t> empty_vector; characteristic1_->ReadRemoteCharacteristic( GetReadValueCallback(Call::EXPECTED), GetGattErrorCallback(Call::NOT_EXPECTED)); - characteristic1_->WriteRemoteCharacteristic( + characteristic1_->DeprecatedWriteRemoteCharacteristic( empty_vector, GetCallback(Call::NOT_EXPECTED), GetGattErrorCallback(Call::EXPECTED)); base::RunLoop().RunUntilIdle(); @@ -1656,8 +2463,60 @@ TEST_F(BluetoothRemoteGattCharacteristicTest, TestBluetoothAdapterObserver observer(adapter_); + base::RunLoop loop; std::vector<uint8_t> write_value = {111}; characteristic1_->WriteRemoteCharacteristic( + write_value, WriteType::kWithResponse, base::BindLambdaForTesting([&] { + EXPECT_EQ(write_value, last_write_value_); + loop.Quit(); + }), + base::BindLambdaForTesting( + [&](BluetoothGattService::GattErrorCode error_code) { + ADD_FAILURE() << "unexpected error: " << error_code; + loop.Quit(); + })); + + std::vector<uint8_t> notification_value = {222}; + SimulateGattCharacteristicChanged(characteristic1_, notification_value); + base::RunLoop().RunUntilIdle(); + + EXPECT_EQ(notification_value, characteristic1_->GetValue()); + EXPECT_EQ(1, observer.gatt_characteristic_value_changed_count()); + + observer.Reset(); + SimulateGattCharacteristicWrite(characteristic1_); + loop.Run(); +} + +#if defined(OS_ANDROID) || defined(OS_MACOSX) +#define MAYBE_Notification_During_DeprecatedWriteRemoteCharacteristic \ + Notification_During_DeprecatedWriteRemoteCharacteristic +#else +#define MAYBE_Notification_During_DeprecatedWriteRemoteCharacteristic \ + DISABLED_Notification_During_DeprecatedWriteRemoteCharacteristic +#endif +// Tests that a notification arriving during a pending write doesn't +// cause a crash. +#if defined(OS_WIN) +TEST_P(BluetoothRemoteGattCharacteristicTestWinrt, + Notification_During_DeprecatedWriteRemoteCharacteristic) { +#else +TEST_F(BluetoothRemoteGattCharacteristicTest, + MAYBE_Notification_During_DeprecatedWriteRemoteCharacteristic) { +#endif + if (!PlatformSupportsLowEnergy()) { + LOG(WARNING) << "Low Energy Bluetooth unavailable, skipping unit test."; + return; + } + ASSERT_NO_FATAL_FAILURE(StartNotifyBoilerplate( + BluetoothRemoteGattCharacteristic::PROPERTY_NOTIFY | + BluetoothRemoteGattCharacteristic::PROPERTY_WRITE, + NotifyValueState::NOTIFY)); + + TestBluetoothAdapterObserver observer(adapter_); + + std::vector<uint8_t> write_value = {111}; + characteristic1_->DeprecatedWriteRemoteCharacteristic( write_value, GetCallback(Call::EXPECTED), GetGattErrorCallback(Call::NOT_EXPECTED)); @@ -3344,9 +4203,47 @@ TEST_F(BluetoothRemoteGattCharacteristicTest, MAYBE_WriteDuringDisconnect) { ASSERT_NO_FATAL_FAILURE(FakeCharacteristicBoilerplate( BluetoothRemoteGattCharacteristic::PROPERTY_WRITE)); + base::RunLoop loop; SimulateGattDisconnection(device_); - // Do not yet call RunUntilIdle() to process the disconnect task. + // Do not yet call loop.Run() to process the disconnect task. characteristic1_->WriteRemoteCharacteristic( + std::vector<uint8_t>(), WriteType::kWithResponse, + base::BindLambdaForTesting([&] { + ADD_FAILURE() << "unexpected success"; + loop.Quit(); + }), + base::BindLambdaForTesting( + [&](BluetoothGattService::GattErrorCode error_code) { + EXPECT_EQ(BluetoothRemoteGattService::GATT_ERROR_FAILED, + error_code); + loop.Quit(); + })); + + loop.Run(); +} + +#if defined(OS_ANDROID) +#define MAYBE_DeprecatedWriteDuringDisconnect DeprecatedWriteDuringDisconnect +#else +#define MAYBE_DeprecatedWriteDuringDisconnect \ + DISABLED_DeprecatedWriteDuringDisconnect +#endif +// Tests that write requests after a device disconnects but before the +// disconnect task runs result in an error. +// macOS: Does not apply. All events arrive on the UI Thread. +// TODO(crbug.com/694102): Enable this test on Windows. +TEST_F(BluetoothRemoteGattCharacteristicTest, + MAYBE_DeprecatedWriteDuringDisconnect) { + if (!PlatformSupportsLowEnergy()) { + LOG(WARNING) << "Low Energy Bluetooth unavailable, skipping unit test."; + return; + } + ASSERT_NO_FATAL_FAILURE(FakeCharacteristicBoilerplate( + BluetoothRemoteGattCharacteristic::PROPERTY_WRITE)); + + SimulateGattDisconnection(device_); + // Do not yet call RunUntilIdle() to process the disconnect task. + characteristic1_->DeprecatedWriteRemoteCharacteristic( std::vector<uint8_t>(), GetCallback(Call::NOT_EXPECTED), GetGattErrorCallback(Call::EXPECTED)); @@ -3382,7 +4279,52 @@ TEST_F( ASSERT_NO_FATAL_FAILURE(FakeCharacteristicBoilerplate( BluetoothRemoteGattCharacteristic::PROPERTY_WRITE_WITHOUT_RESPONSE)); + base::RunLoop loop; characteristic1_->WriteRemoteCharacteristic( + std::vector<uint8_t>(), WriteType::kWithoutResponse, + base::BindLambdaForTesting([&] { + ADD_FAILURE() << "unexpected success"; + loop.Quit(); + }), + base::BindLambdaForTesting( + [&](BluetoothGattService::GattErrorCode error_code) { + EXPECT_EQ(BluetoothRemoteGattService::GATT_ERROR_FAILED, + error_code); + loop.Quit(); + })); + SimulateDeviceBreaksConnection(adapter_->GetDevices()[0]); + + loop.Run(); +} + +#if defined(OS_MACOSX) +#define MAYBE_WriteWithoutResponseOnlyCharacteristic_DeprecatedWriteRemoteCharacteristicDuringDisconnect \ + WriteWithoutResponseOnlyCharacteristic_DeprecatedWriteRemoteCharacteristicDuringDisconnect +#else +#define MAYBE_WriteWithoutResponseOnlyCharacteristic_DeprecatedWriteRemoteCharacteristicDuringDisconnect \ + DISABLED_WriteWithoutResponseOnlyCharacteristic_DeprecatedWriteRemoteCharacteristicDuringDisconnect +#endif +// Tests that writing without response during a disconnect results in an error. +// Only applies to macOS and WinRT whose events arrive all on the UI thread. See +// other *DuringDisconnect tests for Android and Windows whose events arrive on +// a different thread. +#if defined(OS_WIN) +TEST_P( + BluetoothRemoteGattCharacteristicTestWinrtOnly, + WriteWithoutResponseOnlyCharacteristic_DeprecatedWriteRemoteCharacteristicDuringDisconnect) { +#else +TEST_F( + BluetoothRemoteGattCharacteristicTest, + MAYBE_WriteWithoutResponseOnlyCharacteristic_DeprecatedWriteRemoteCharacteristicDuringDisconnect) { +#endif + if (!PlatformSupportsLowEnergy()) { + LOG(WARNING) << "Low Energy Bluetooth unavailable, skipping unit test."; + return; + } + ASSERT_NO_FATAL_FAILURE(FakeCharacteristicBoilerplate( + BluetoothRemoteGattCharacteristic::PROPERTY_WRITE_WITHOUT_RESPONSE)); + + characteristic1_->DeprecatedWriteRemoteCharacteristic( std::vector<uint8_t>(), GetCallback(Call::NOT_EXPECTED), GetGattErrorCallback(Call::EXPECTED)); SimulateDeviceBreaksConnection(adapter_->GetDevices()[0]); @@ -3418,6 +4360,49 @@ TEST_F( base::RunLoop loop; characteristic1_->WriteRemoteCharacteristic( + std::vector<uint8_t>(), WriteType::kWithoutResponse, + base::BindLambdaForTesting([&] { + ADD_FAILURE() << "unexpected success"; + loop.Quit(); + }), + base::BindLambdaForTesting( + [&](BluetoothGattService::GattErrorCode error_code) { + EXPECT_EQ(BluetoothRemoteGattService::GATT_ERROR_FAILED, + error_code); + gatt_connections_[0]->Disconnect(); + loop.Quit(); + })); + SimulateDeviceBreaksConnection(adapter_->GetDevices()[0]); + loop.Run(); +} + +// Tests that closing the GATT connection when a characteristic value write +// fails due to a disconnect is safe. +#if defined(OS_ANDROID) || defined(OS_MACOSX) +#define MAYBE_DeprecatedWriteWithoutResponseOnlyCharacteristic_CloseConnectionDuringDisconnect \ + DeprecatedWriteWithoutResponseOnlyCharacteristic_CloseConnectionDuringDisconnect +#else +#define MAYBE_DeprecatedWriteWithoutResponseOnlyCharacteristic_CloseConnectionDuringDisconnect \ + DISABLED_DeprecatedWriteWithoutResponseOnlyCharacteristic_CloseConnectionDuringDisconnect +#endif +#if defined(OS_WIN) +TEST_P( + BluetoothRemoteGattCharacteristicTestWinrtOnly, + DeprecatedWriteWithoutResponseOnlyCharacteristic_CloseConnectionDuringDisconnect) { +#else +TEST_F( + BluetoothRemoteGattCharacteristicTest, + MAYBE_DeprecatedWriteWithoutResponseOnlyCharacteristic_CloseConnectionDuringDisconnect) { +#endif + if (!PlatformSupportsLowEnergy()) { + LOG(WARNING) << "Low Energy Bluetooth unavailable, skipping unit test."; + return; + } + ASSERT_NO_FATAL_FAILURE(FakeCharacteristicBoilerplate( + BluetoothRemoteGattCharacteristic::PROPERTY_WRITE_WITHOUT_RESPONSE)); + + base::RunLoop loop; + characteristic1_->DeprecatedWriteRemoteCharacteristic( std::vector<uint8_t>(), GetCallback(Call::NOT_EXPECTED), base::BindLambdaForTesting( [&](BluetoothGattService::GattErrorCode error_code) { @@ -3451,33 +4436,40 @@ TEST_F( ASSERT_NO_FATAL_FAILURE(FakeCharacteristicBoilerplate( BluetoothRemoteGattCharacteristic::PROPERTY_WRITE_WITHOUT_RESPONSE)); + base::RunLoop loop; characteristic1_->WriteRemoteCharacteristic( - std::vector<uint8_t>(), GetCallback(Call::NOT_EXPECTED), - GetGattErrorCallback(Call::EXPECTED)); + std::vector<uint8_t>(), WriteType::kWithoutResponse, + base::BindLambdaForTesting([&] { + ADD_FAILURE() << "unexpected success"; + loop.Quit(); + }), + base::BindLambdaForTesting( + [&](BluetoothGattService::GattErrorCode error_code) { + EXPECT_EQ(BluetoothRemoteGattService::GATT_ERROR_FAILED, + error_code); + loop.Quit(); + })); gatt_connections_[0]->Disconnect(); - base::RunLoop().RunUntilIdle(); - - EXPECT_EQ(BluetoothRemoteGattService::GATT_ERROR_FAILED, - last_gatt_error_code_); + loop.Run(); SimulateGattDisconnection(device_); base::RunLoop().RunUntilIdle(); } #if defined(OS_MACOSX) -#define MAYBE_WriteWithoutResponseOnlyCharacteristic_DisconnectCalledBeforeWriteRemoteCharacteristic \ - WriteWithoutResponseOnlyCharacteristic_DisconnectCalledBeforeWriteRemoteCharacteristic +#define MAYBE_DeprecatedWriteWithoutResponseOnlyCharacteristic_DisconnectCalledDuringWriteRemoteCharacteristic \ + DeprecatedWriteWithoutResponseOnlyCharacteristic_DisconnectCalledDuringWriteRemoteCharacteristic #else -#define MAYBE_WriteWithoutResponseOnlyCharacteristic_DisconnectCalledBeforeWriteRemoteCharacteristic \ - DISABLED_WriteWithoutResponseOnlyCharacteristic_DisconnectCalledBeforeWriteRemoteCharacteristic +#define MAYBE_DeprecatedWriteWithoutResponseOnlyCharacteristic_DisconnectCalledDuringWriteRemoteCharacteristic \ + DISABLED_DeprecatedWriteWithoutResponseOnlyCharacteristic_DisconnectCalledDuringWriteRemoteCharacteristic #endif -// Tests that disconnecting right before a write without response results in an +// Tests that disconnecting right after a write without response results in an // error. // TODO(crbug.com/726534): Enable on other platforms depending on the resolution // of crbug.com/726534. TEST_F( BluetoothRemoteGattCharacteristicTest, - MAYBE_WriteWithoutResponseOnlyCharacteristic_DisconnectCalledBeforeWriteRemoteCharacteristic) { + MAYBE_DeprecatedWriteWithoutResponseOnlyCharacteristic_DisconnectCalledDuringWriteRemoteCharacteristic) { if (!PlatformSupportsLowEnergy()) { LOG(WARNING) << "Low Energy Bluetooth unavailable, skipping unit test."; return; @@ -3485,10 +4477,10 @@ TEST_F( ASSERT_NO_FATAL_FAILURE(FakeCharacteristicBoilerplate( BluetoothRemoteGattCharacteristic::PROPERTY_WRITE_WITHOUT_RESPONSE)); - gatt_connections_[0]->Disconnect(); - characteristic1_->WriteRemoteCharacteristic( + characteristic1_->DeprecatedWriteRemoteCharacteristic( std::vector<uint8_t>(), GetCallback(Call::NOT_EXPECTED), GetGattErrorCallback(Call::EXPECTED)); + gatt_connections_[0]->Disconnect(); base::RunLoop().RunUntilIdle(); EXPECT_EQ(BluetoothRemoteGattService::GATT_ERROR_FAILED, @@ -3499,145 +4491,78 @@ TEST_F( } #if defined(OS_MACOSX) -#define MAYBE_WriteWithoutResponse_PropertyNotPresent \ - WriteWithoutResponse_PropertyNotPresent -#else -#define MAYBE_WriteWithoutResponse_PropertyNotPresent \ - DISABLED_WriteWithoutResponse_PropertyNotPresent -#endif -// Tests that WriteWithoutResponse fails when a characteristic does not have the -// required property. -// TODO(https://crbug.com/831524): Enable for other platforms once supported. -#if defined(OS_WIN) -TEST_P(BluetoothRemoteGattCharacteristicTestWinrtOnly, - WriteWithoutResponse_PropertyNotPresent) { -#else -TEST_F(BluetoothRemoteGattCharacteristicTest, - MAYBE_WriteWithoutResponse_PropertyNotPresent) { -#endif - if (!PlatformSupportsLowEnergy()) { - LOG(WARNING) << "Low Energy Bluetooth unavailable, skipping unit test."; - return; - } - ASSERT_NO_FATAL_FAILURE(FakeCharacteristicBoilerplate( - BluetoothRemoteGattCharacteristic::PROPERTY_WRITE)); - - std::vector<uint8_t> test_vector = {0, 1, 2, 3, 4, 0xf, 0xf0, 0xff}; - EXPECT_FALSE(characteristic1_->WriteWithoutResponse(test_vector)); -} - -#if defined(OS_MACOSX) -#define MAYBE_WriteWithoutResponse_PendingWrite \ - WriteWithoutResponse_PendingWrite -#else -#define MAYBE_WriteWithoutResponse_PendingWrite \ - DISABLED_WriteWithoutResponse_PendingWrite -#endif -// Tests that WriteWithoutResponse fails when a characteristic already has a -// pending write. -// TODO(https://crbug.com/831524): Enable for other platforms once supported. -#if defined(OS_WIN) -TEST_P(BluetoothRemoteGattCharacteristicTestWinrtOnly, - WriteWithoutResponse_PendingWrite) { +#define MAYBE_WriteWithoutResponseOnlyCharacteristic_DisconnectCalledBeforeWriteRemoteCharacteristic \ + WriteWithoutResponseOnlyCharacteristic_DisconnectCalledBeforeWriteRemoteCharacteristic #else -TEST_F(BluetoothRemoteGattCharacteristicTest, - MAYBE_WriteWithoutResponse_PendingWrite) { +#define MAYBE_WriteWithoutResponseOnlyCharacteristic_DisconnectCalledBeforeWriteRemoteCharacteristic \ + DISABLED_WriteWithoutResponseOnlyCharacteristic_DisconnectCalledBeforeWriteRemoteCharacteristic #endif +// Tests that disconnecting right before a write without response results in an +// error. +// TODO(crbug.com/726534): Enable on other platforms depending on the resolution +// of crbug.com/726534. +TEST_F( + BluetoothRemoteGattCharacteristicTest, + MAYBE_WriteWithoutResponseOnlyCharacteristic_DisconnectCalledBeforeWriteRemoteCharacteristic) { if (!PlatformSupportsLowEnergy()) { LOG(WARNING) << "Low Energy Bluetooth unavailable, skipping unit test."; return; } ASSERT_NO_FATAL_FAILURE(FakeCharacteristicBoilerplate( - BluetoothRemoteGattCharacteristic::PROPERTY_WRITE | BluetoothRemoteGattCharacteristic::PROPERTY_WRITE_WITHOUT_RESPONSE)); - std::vector<uint8_t> test_vector = {0, 1, 2, 3, 4, 0xf, 0xf0, 0xff}; + base::RunLoop loop; + gatt_connections_[0]->Disconnect(); characteristic1_->WriteRemoteCharacteristic( - test_vector, GetCallback(Call::EXPECTED), - GetGattErrorCallback(Call::NOT_EXPECTED)); - - // Explicitly make sure that the callback has not been invoked yet. Since - // WriteRemoteCharacteristic is still pending, this results in an error for - // WriteWithoutResponse. - EXPECT_EQ(0, callback_count_); - EXPECT_FALSE(characteristic1_->WriteWithoutResponse(test_vector)); + std::vector<uint8_t>(), WriteType::kWithoutResponse, + base::BindLambdaForTesting([&] { + ADD_FAILURE() << "unexpected success"; + loop.Quit(); + }), + base::BindLambdaForTesting( + [&](BluetoothGattService::GattErrorCode error_code) { + EXPECT_EQ(BluetoothRemoteGattService::GATT_ERROR_FAILED, + error_code); + loop.Quit(); + })); + loop.Run(); - // Test that the failed WriteWithoutReponse request does not interfere with - // the pending WriteRemoteCharacteristic request. - SimulateGattCharacteristicWrite(characteristic1_); + SimulateGattDisconnection(device_); base::RunLoop().RunUntilIdle(); - EXPECT_EQ(1, callback_count_); - EXPECT_EQ(test_vector, last_write_value_); } #if defined(OS_MACOSX) -#define MAYBE_WriteWithoutResponse_PendingRead WriteWithoutResponse_PendingRead +#define MAYBE_DeprecatedWriteWithoutResponseOnlyCharacteristic_DisconnectCalledBeforeWriteRemoteCharacteristic \ + DeprecatedWriteWithoutResponseOnlyCharacteristic_DisconnectCalledBeforeWriteRemoteCharacteristic #else -#define MAYBE_WriteWithoutResponse_PendingRead \ - DISABLED_WriteWithoutResponse_PendingRead -#endif -// Tests that WriteWithoutResponse fails when a characteristic already has a -// pending read. -// TODO(https://crbug.com/831524): Enable for other platforms once supported. -#if defined(OS_WIN) -TEST_P(BluetoothRemoteGattCharacteristicTestWinrtOnly, - WriteWithoutResponse_PendingRead) { -#else -TEST_F(BluetoothRemoteGattCharacteristicTest, - MAYBE_WriteWithoutResponse_PendingRead) { +#define MAYBE_DeprecatedWriteWithoutResponseOnlyCharacteristic_DisconnectCalledBeforeWriteRemoteCharacteristic \ + DISABLED_DeprecatedWriteWithoutResponseOnlyCharacteristic_DisconnectCalledBeforeWriteRemoteCharacteristic #endif +// Tests that disconnecting right before a write without response results in an +// error. +// TODO(crbug.com/726534): Enable on other platforms depending on the resolution +// of crbug.com/726534. +TEST_F( + BluetoothRemoteGattCharacteristicTest, + MAYBE_DeprecatedWriteWithoutResponseOnlyCharacteristic_DisconnectCalledBeforeWriteRemoteCharacteristic) { if (!PlatformSupportsLowEnergy()) { LOG(WARNING) << "Low Energy Bluetooth unavailable, skipping unit test."; return; } ASSERT_NO_FATAL_FAILURE(FakeCharacteristicBoilerplate( - BluetoothRemoteGattCharacteristic::PROPERTY_READ | BluetoothRemoteGattCharacteristic::PROPERTY_WRITE_WITHOUT_RESPONSE)); - characteristic1_->ReadRemoteCharacteristic( - GetReadValueCallback(Call::EXPECTED), - GetGattErrorCallback(Call::NOT_EXPECTED)); - - // Explicitly make sure that the callback has not been invoked yet. Since - // ReadRemoteCharacteristic is still pending, this results in an error for - // WriteWithoutResponse. - EXPECT_EQ(0, callback_count_); - std::vector<uint8_t> test_vector = {0, 1, 2, 3, 4, 0xf, 0xf0, 0xff}; - EXPECT_FALSE(characteristic1_->WriteWithoutResponse(test_vector)); - - // Test that the failed WriteWithoutReponse request does not interfere with - // the pending ReadRemoteCharacteristic request. - SimulateGattCharacteristicRead(characteristic1_, test_vector); + gatt_connections_[0]->Disconnect(); + characteristic1_->DeprecatedWriteRemoteCharacteristic( + std::vector<uint8_t>(), GetCallback(Call::NOT_EXPECTED), + GetGattErrorCallback(Call::EXPECTED)); base::RunLoop().RunUntilIdle(); - EXPECT_EQ(1, callback_count_); - EXPECT_EQ(test_vector, last_read_value_); -} -#if defined(OS_MACOSX) -#define MAYBE_WriteWithoutResponse_Success WriteWithoutResponse_Success -#else -#define MAYBE_WriteWithoutResponse_Success DISABLED_WriteWithoutResponse_Success -#endif -// Tests that WriteWithoutResponse indicates success if the proper conditions -// are met. -// TODO(https://crbug.com/831524): Enable for other platforms once supported. -#if defined(OS_WIN) -TEST_P(BluetoothRemoteGattCharacteristicTestWinrtOnly, - WriteWithoutResponse_Success) { -#else -TEST_F(BluetoothRemoteGattCharacteristicTest, - MAYBE_WriteWithoutResponse_Success) { -#endif - if (!PlatformSupportsLowEnergy()) { - LOG(WARNING) << "Low Energy Bluetooth unavailable, skipping unit test."; - return; - } - ASSERT_NO_FATAL_FAILURE(FakeCharacteristicBoilerplate( - BluetoothRemoteGattCharacteristic::PROPERTY_WRITE_WITHOUT_RESPONSE)); + EXPECT_EQ(BluetoothRemoteGattService::GATT_ERROR_FAILED, + last_gatt_error_code_); - std::vector<uint8_t> test_vector = {1, 2, 3, 4}; - EXPECT_TRUE(characteristic1_->WriteWithoutResponse(test_vector)); - EXPECT_EQ(test_vector, last_write_value_); + SimulateGattDisconnection(device_); + base::RunLoop().RunUntilIdle(); } #if defined(OS_ANDROID) @@ -3843,20 +4768,19 @@ TEST_F(BluetoothRemoteGattCharacteristicTest, ExtraDidDiscoverDescriptorsCall) { #endif // defined(OS_MACOSX) #if defined(OS_WIN) -INSTANTIATE_TEST_SUITE_P( - All, - BluetoothRemoteGattCharacteristicTestWinrt, - ::testing::Bool()); +INSTANTIATE_TEST_SUITE_P(All, + BluetoothRemoteGattCharacteristicTestWinrt, + ::testing::ValuesIn(kBluetoothTestWinrtParamAll)); INSTANTIATE_TEST_SUITE_P( All, BluetoothRemoteGattCharacteristicTestWin32Only, - ::testing::Values(false)); + ::testing::ValuesIn(kBluetoothTestWinrtParamWin32Only)); INSTANTIATE_TEST_SUITE_P( All, BluetoothRemoteGattCharacteristicTestWinrtOnly, - ::testing::Values(true)); + ::testing::ValuesIn(kBluetoothTestWinrtParamWinrtOnly)); #endif // defined(OS_WIN) } // namespace device diff --git a/chromium/device/bluetooth/bluetooth_remote_gatt_characteristic_win.cc b/chromium/device/bluetooth/bluetooth_remote_gatt_characteristic_win.cc index dfe278ab735..54d4effdcdd 100644 --- a/chromium/device/bluetooth/bluetooth_remote_gatt_characteristic_win.cc +++ b/chromium/device/bluetooth/bluetooth_remote_gatt_characteristic_win.cc @@ -159,6 +159,40 @@ void BluetoothRemoteGattCharacteristicWin::ReadRemoteCharacteristic( void BluetoothRemoteGattCharacteristicWin::WriteRemoteCharacteristic( const std::vector<uint8_t>& value, + WriteType write_type, + base::OnceClosure callback, + ErrorCallback error_callback) { + DCHECK(ui_task_runner_->RunsTasksInCurrentSequence()); + + if (characteristic_value_read_or_write_in_progress_) { + std::move(error_callback) + .Run(BluetoothRemoteGattService::GATT_ERROR_IN_PROGRESS); + return; + } + + ULONG flags; + switch (write_type) { + case WriteType::kWithResponse: + flags = BLUETOOTH_GATT_FLAG_NONE; + break; + case WriteType::kWithoutResponse: + flags = BLUETOOTH_GATT_FLAG_WRITE_WITHOUT_RESPONSE; + break; + } + + characteristic_value_read_or_write_in_progress_ = true; + write_characteristic_value_callbacks_ = + std::make_pair(std::move(callback), std::move(error_callback)); + task_manager_->PostWriteGattCharacteristicValue( + parent_service_->GetServicePath(), characteristic_info_.get(), value, + flags, + base::Bind(&BluetoothRemoteGattCharacteristicWin:: + OnWriteRemoteCharacteristicValueCallback, + weak_ptr_factory_.GetWeakPtr())); +} + +void BluetoothRemoteGattCharacteristicWin::DeprecatedWriteRemoteCharacteristic( + const std::vector<uint8_t>& value, base::OnceClosure callback, ErrorCallback error_callback) { DCHECK(ui_task_runner_->RunsTasksInCurrentSequence()); @@ -176,11 +210,17 @@ void BluetoothRemoteGattCharacteristicWin::WriteRemoteCharacteristic( return; } + ULONG flags = BLUETOOTH_GATT_FLAG_NONE; + if (!characteristic_info_->IsWritable) { + flags |= BLUETOOTH_GATT_FLAG_WRITE_WITHOUT_RESPONSE; + } + characteristic_value_read_or_write_in_progress_ = true; write_characteristic_value_callbacks_ = std::make_pair(std::move(callback), std::move(error_callback)); task_manager_->PostWriteGattCharacteristicValue( parent_service_->GetServicePath(), characteristic_info_.get(), value, + flags, base::Bind(&BluetoothRemoteGattCharacteristicWin:: OnWriteRemoteCharacteristicValueCallback, weak_ptr_factory_.GetWeakPtr())); diff --git a/chromium/device/bluetooth/bluetooth_remote_gatt_characteristic_win.h b/chromium/device/bluetooth/bluetooth_remote_gatt_characteristic_win.h index 56a3212b8b0..50fcaac8f3d 100644 --- a/chromium/device/bluetooth/bluetooth_remote_gatt_characteristic_win.h +++ b/chromium/device/bluetooth/bluetooth_remote_gatt_characteristic_win.h @@ -45,8 +45,13 @@ class DEVICE_BLUETOOTH_EXPORT BluetoothRemoteGattCharacteristicWin void ReadRemoteCharacteristic(ValueCallback callback, ErrorCallback error_callback) override; void WriteRemoteCharacteristic(const std::vector<uint8_t>& value, + WriteType write_type, base::OnceClosure callback, ErrorCallback error_callback) override; + void DeprecatedWriteRemoteCharacteristic( + const std::vector<uint8_t>& value, + base::OnceClosure callback, + ErrorCallback error_callback) override; // Update included descriptors. void Update(); diff --git a/chromium/device/bluetooth/bluetooth_remote_gatt_characteristic_winrt.cc b/chromium/device/bluetooth/bluetooth_remote_gatt_characteristic_winrt.cc index 8e340c5dbad..2e5a0a979e4 100644 --- a/chromium/device/bluetooth/bluetooth_remote_gatt_characteristic_winrt.cc +++ b/chromium/device/bluetooth/bluetooth_remote_gatt_characteristic_winrt.cc @@ -46,6 +46,8 @@ using ABI::Windows::Devices::Bluetooth::GenericAttributeProfile:: GattCommunicationStatus_Success; using ABI::Windows::Devices::Bluetooth::GenericAttributeProfile::GattReadResult; using ABI::Windows::Devices::Bluetooth::GenericAttributeProfile:: + GattWriteOption; +using ABI::Windows::Devices::Bluetooth::GenericAttributeProfile:: GattWriteOption_WriteWithoutResponse; using ABI::Windows::Devices::Bluetooth::GenericAttributeProfile:: GattWriteOption_WriteWithResponse; @@ -203,17 +205,9 @@ void BluetoothRemoteGattCharacteristicWinrt::ReadRemoteCharacteristic( void BluetoothRemoteGattCharacteristicWinrt::WriteRemoteCharacteristic( const std::vector<uint8_t>& value, + WriteType write_type, base::OnceClosure callback, ErrorCallback error_callback) { - if (!(GetProperties() & PROPERTY_WRITE) && - !(GetProperties() & PROPERTY_WRITE_WITHOUT_RESPONSE)) { - base::ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, - base::BindOnce(std::move(error_callback), - BluetoothRemoteGattService::GATT_ERROR_NOT_PERMITTED)); - return; - } - if (pending_read_callbacks_ || pending_write_callbacks_) { base::ThreadTaskRunnerHandle::Get()->PostTask( FROM_HERE, @@ -246,13 +240,19 @@ void BluetoothRemoteGattCharacteristicWinrt::WriteRemoteCharacteristic( return; } + GattWriteOption write_option; + switch (write_type) { + case WriteType::kWithResponse: + write_option = GattWriteOption_WriteWithResponse; + break; + case WriteType::kWithoutResponse: + write_option = GattWriteOption_WriteWithoutResponse; + break; + } + ComPtr<IAsyncOperation<GattWriteResult*>> write_value_op; hr = characteristic_3->WriteValueWithResultAndOptionAsync( - buffer.Get(), - (GetProperties() & PROPERTY_WRITE) ? GattWriteOption_WriteWithResponse - : GattWriteOption_WriteWithoutResponse, - - &write_value_op); + buffer.Get(), write_option, &write_value_op); if (FAILED(hr)) { BLUETOOTH_LOG(DEBUG) << "GattCharacteristic::WriteValueWithResultAndOptionAsync failed: " @@ -284,6 +284,27 @@ void BluetoothRemoteGattCharacteristicWinrt::WriteRemoteCharacteristic( std::move(callback), std::move(error_callback)); } +void BluetoothRemoteGattCharacteristicWinrt:: + DeprecatedWriteRemoteCharacteristic(const std::vector<uint8_t>& value, + base::OnceClosure callback, + ErrorCallback error_callback) { + if (!(GetProperties() & PROPERTY_WRITE) && + !(GetProperties() & PROPERTY_WRITE_WITHOUT_RESPONSE)) { + base::ThreadTaskRunnerHandle::Get()->PostTask( + FROM_HERE, + base::BindOnce(std::move(error_callback), + BluetoothRemoteGattService::GATT_ERROR_NOT_PERMITTED)); + return; + } + + WriteType write_type = (GetProperties() & PROPERTY_WRITE) + ? WriteType::kWithResponse + : WriteType::kWithoutResponse; + + WriteRemoteCharacteristic(value, write_type, std::move(callback), + std::move(error_callback)); +} + void BluetoothRemoteGattCharacteristicWinrt::UpdateDescriptors( BluetoothGattDiscovererWinrt* gatt_discoverer) { const auto* gatt_descriptors = @@ -311,56 +332,6 @@ void BluetoothRemoteGattCharacteristicWinrt::UpdateDescriptors( std::swap(descriptors, descriptors_); } -bool BluetoothRemoteGattCharacteristicWinrt::WriteWithoutResponse( - base::span<const uint8_t> value) { - if (!(GetProperties() & PROPERTY_WRITE_WITHOUT_RESPONSE)) - return false; - - if (pending_read_callbacks_ || pending_write_callbacks_) - return false; - - ComPtr<IGattCharacteristic3> characteristic_3; - HRESULT hr = characteristic_.As(&characteristic_3); - if (FAILED(hr)) { - BLUETOOTH_LOG(DEBUG) << "As IGattCharacteristic3 failed: " - << logging::SystemErrorCodeToString(hr); - return false; - } - - ComPtr<IBuffer> buffer; - hr = base::win::CreateIBufferFromData(value.data(), value.size(), &buffer); - if (FAILED(hr)) { - BLUETOOTH_LOG(DEBUG) << "base::win::CreateIBufferFromData failed: " - << logging::SystemErrorCodeToString(hr); - return false; - } - - ComPtr<IAsyncOperation<GattWriteResult*>> write_value_op; - // Note: As we are ignoring the result WriteValueWithOptionAsync() would work - // as well, but re-using WriteValueWithResultAndOptionAsync() does simplify - // the testing code and there is no difference in production. - hr = characteristic_3->WriteValueWithResultAndOptionAsync( - buffer.Get(), GattWriteOption_WriteWithoutResponse, &write_value_op); - if (FAILED(hr)) { - BLUETOOTH_LOG(DEBUG) - << "GattCharacteristic::WriteValueWithResultAndOptionAsync failed: " - << logging::SystemErrorCodeToString(hr); - return false; - } - - // While we are ignoring the response, we still post the async_op in order to - // extend its lifetime until the operation has completed. - hr = - base::win::PostAsyncResults(std::move(write_value_op), base::DoNothing()); - if (FAILED(hr)) { - BLUETOOTH_LOG(DEBUG) << "PostAsyncResults failed: " - << logging::SystemErrorCodeToString(hr); - return false; - } - - return true; -} - IGattCharacteristic* BluetoothRemoteGattCharacteristicWinrt::GetCharacteristicForTesting() { return characteristic_.Get(); diff --git a/chromium/device/bluetooth/bluetooth_remote_gatt_characteristic_winrt.h b/chromium/device/bluetooth/bluetooth_remote_gatt_characteristic_winrt.h index c1d7df05a32..1402fa2354c 100644 --- a/chromium/device/bluetooth/bluetooth_remote_gatt_characteristic_winrt.h +++ b/chromium/device/bluetooth/bluetooth_remote_gatt_characteristic_winrt.h @@ -48,9 +48,13 @@ class DEVICE_BLUETOOTH_EXPORT BluetoothRemoteGattCharacteristicWinrt void ReadRemoteCharacteristic(ValueCallback callback, ErrorCallback error_callback) override; void WriteRemoteCharacteristic(const std::vector<uint8_t>& value, + WriteType write_type, base::OnceClosure callback, ErrorCallback error_callback) override; - bool WriteWithoutResponse(base::span<const uint8_t> value) override; + void DeprecatedWriteRemoteCharacteristic( + const std::vector<uint8_t>& value, + base::OnceClosure callback, + ErrorCallback error_callback) override; void UpdateDescriptors(BluetoothGattDiscovererWinrt* gatt_discoverer); diff --git a/chromium/device/bluetooth/bluetooth_remote_gatt_descriptor_unittest.cc b/chromium/device/bluetooth/bluetooth_remote_gatt_descriptor_unittest.cc index b0d14a15cd3..1a410cbc377 100644 --- a/chromium/device/bluetooth/bluetooth_remote_gatt_descriptor_unittest.cc +++ b/chromium/device/bluetooth/bluetooth_remote_gatt_descriptor_unittest.cc @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "base/logging.h" #include "base/run_loop.h" #include "base/stl_util.h" #include "build/build_config.h" @@ -999,7 +1000,7 @@ TEST_F(BluetoothRemoteGattDescriptorTest, ReadRemoteDescriptor_NSNumber) { INSTANTIATE_TEST_SUITE_P( All, BluetoothRemoteGattDescriptorTestWinrtOnly, - ::testing::Values(true)); + ::testing::ValuesIn(kBluetoothTestWinrtParamWinrtOnly)); #endif // defined(OS_WIN) } // namespace device diff --git a/chromium/device/bluetooth/bluetooth_remote_gatt_service_unittest.cc b/chromium/device/bluetooth/bluetooth_remote_gatt_service_unittest.cc index 70221d3bc1e..5ba4392be5e 100644 --- a/chromium/device/bluetooth/bluetooth_remote_gatt_service_unittest.cc +++ b/chromium/device/bluetooth/bluetooth_remote_gatt_service_unittest.cc @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "base/logging.h" #include "base/run_loop.h" #include "build/build_config.h" #include "device/bluetooth/bluetooth_gatt_service.h" @@ -415,7 +416,7 @@ TEST_F(BluetoothRemoteGattServiceTest, MAYBE_SimulateGattServiceRemove) { SimulateGattServiceRemoved(device->GetGattService(removed_service)); base::RunLoop().RunUntilIdle(); #if defined(OS_WIN) - if (!GetParam()) { + if (!UsesNewBleImplementation()) { // The GattServicesRemoved event is not implemented for WinRT. EXPECT_EQ(1, observer.gatt_service_removed_count()); } @@ -597,10 +598,9 @@ TEST_F(BluetoothRemoteGattServiceTest, ExtraDidDiscoverCharacteristicsCall) { #endif // defined(OS_MACOSX) #if defined(OS_WIN) -INSTANTIATE_TEST_SUITE_P( - All, - BluetoothRemoteGattServiceTestWinrt, - ::testing::Bool()); +INSTANTIATE_TEST_SUITE_P(All, + BluetoothRemoteGattServiceTestWinrt, + ::testing::ValuesIn(kBluetoothTestWinrtParamAll)); #endif // defined(OS_WIN) } // namespace device diff --git a/chromium/device/bluetooth/bluetooth_remote_gatt_service_winrt.h b/chromium/device/bluetooth/bluetooth_remote_gatt_service_winrt.h index e8c990dc7c2..75852935344 100644 --- a/chromium/device/bluetooth/bluetooth_remote_gatt_service_winrt.h +++ b/chromium/device/bluetooth/bluetooth_remote_gatt_service_winrt.h @@ -14,6 +14,7 @@ #include <string> #include <vector> +#include "base/logging.h" #include "base/macros.h" #include "device/bluetooth/bluetooth_export.h" #include "device/bluetooth/bluetooth_remote_gatt_characteristic_winrt.h" diff --git a/chromium/device/bluetooth/bluetooth_task_manager_win.cc b/chromium/device/bluetooth/bluetooth_task_manager_win.cc index 4f1883f4edc..55a425be257 100644 --- a/chromium/device/bluetooth/bluetooth_task_manager_win.cc +++ b/chromium/device/bluetooth/bluetooth_task_manager_win.cc @@ -12,6 +12,7 @@ #include <utility> #include "base/bind.h" +#include "base/logging.h" #include "base/memory/ptr_util.h" #include "base/memory/ref_counted.h" #include "base/no_destructor.h" @@ -20,6 +21,7 @@ #include "base/strings/sys_string_conversions.h" #include "base/task/post_task.h" #include "base/task/thread_pool.h" +#include "base/threading/scoped_thread_priority.h" #include "device/bluetooth/bluetooth_classic_win.h" #include "device/bluetooth/bluetooth_device.h" #include "device/bluetooth/bluetooth_init_win.h" @@ -644,6 +646,10 @@ int BluetoothTaskManagerWin::DiscoverClassicDeviceServicesWorker( const GUID& protocol_uuid, bool search_cached_services_only, std::vector<std::unique_ptr<ServiceRecordState>>* service_record_states) { + // Mitigate the issues caused by loading DLLs on a background thread + // (http://crbug/973868). + SCOPED_MAY_LOAD_LIBRARY_AT_BACKGROUND_PRIORITY(); + // Bluetooth and WSAQUERYSET for Service Inquiry. See http://goo.gl/2v9pyt. WSAQUERYSET sdp_query; ZeroMemory(&sdp_query, sizeof(sdp_query)); @@ -869,6 +875,7 @@ void BluetoothTaskManagerWin::WriteGattCharacteristicValue( base::FilePath service_path, BTH_LE_GATT_CHARACTERISTIC characteristic, std::vector<uint8_t> new_value, + ULONG flags, const HResultCallback& callback) { ULONG length = (ULONG)(sizeof(ULONG) + new_value.size()); std::vector<UCHAR> data(length); @@ -880,7 +887,7 @@ void BluetoothTaskManagerWin::WriteGattCharacteristicValue( HRESULT hr = le_wrapper_->WriteCharacteristicValue( service_path, (PBTH_LE_GATT_CHARACTERISTIC)(&characteristic), - win_new_value); + win_new_value, flags); ui_task_runner_->PostTask(FROM_HERE, base::BindOnce(callback, hr)); } @@ -987,12 +994,14 @@ void BluetoothTaskManagerWin::PostWriteGattCharacteristicValue( const base::FilePath& service_path, const PBTH_LE_GATT_CHARACTERISTIC characteristic, const std::vector<uint8_t>& new_value, + ULONG flags, const HResultCallback& callback) { DCHECK(ui_task_runner_->RunsTasksInCurrentSequence()); bluetooth_task_runner_->PostTask( FROM_HERE, base::BindOnce(&BluetoothTaskManagerWin::WriteGattCharacteristicValue, - this, service_path, *characteristic, new_value, callback)); + this, service_path, *characteristic, new_value, flags, + callback)); } void BluetoothTaskManagerWin::PostRegisterGattCharacteristicValueChangedEvent( diff --git a/chromium/device/bluetooth/bluetooth_task_manager_win.h b/chromium/device/bluetooth/bluetooth_task_manager_win.h index de693e2ede5..bd7181e7977 100644 --- a/chromium/device/bluetooth/bluetooth_task_manager_win.h +++ b/chromium/device/bluetooth/bluetooth_task_manager_win.h @@ -186,6 +186,7 @@ class DEVICE_BLUETOOTH_EXPORT BluetoothTaskManagerWin const base::FilePath& service_path, const PBTH_LE_GATT_CHARACTERISTIC characteristic, const std::vector<uint8_t>& new_value, + ULONG flags, const HResultCallback& callback); // Post a task to register to receive value changed notifications from @@ -319,6 +320,7 @@ class DEVICE_BLUETOOTH_EXPORT BluetoothTaskManagerWin void WriteGattCharacteristicValue(base::FilePath service_path, BTH_LE_GATT_CHARACTERISTIC characteristic, std::vector<uint8_t> new_value, + ULONG flags, const HResultCallback& callback); void RegisterGattCharacteristicValueChangedEvent( base::FilePath service_path, diff --git a/chromium/device/bluetooth/bluez/bluetooth_adapter_bluez.cc b/chromium/device/bluetooth/bluez/bluetooth_adapter_bluez.cc index 6e6928e0ca2..bbea7dffa02 100644 --- a/chromium/device/bluetooth/bluez/bluetooth_adapter_bluez.cc +++ b/chromium/device/bluetooth/bluez/bluetooth_adapter_bluez.cc @@ -1523,6 +1523,8 @@ void BluetoothAdapterBlueZ::UpdateFilter( void BluetoothAdapterBlueZ::StartScanWithFilter( std::unique_ptr<device::BluetoothDiscoveryFilter> discovery_filter, DiscoverySessionResultCallback callback) { + DCHECK(discovery_filter.get()); + if (!IsPresent()) { std::move(callback).Run( true, UMABluetoothDiscoverySessionOutcome::ADAPTER_NOT_PRESENT); @@ -1532,39 +1534,16 @@ void BluetoothAdapterBlueZ::StartScanWithFilter( BLUETOOTH_LOG(EVENT) << __func__; auto copyable_callback = base::AdaptCallbackForRepeating(std::move(callback)); - - if (discovery_filter && !discovery_filter->IsDefault()) { - std::unique_ptr<BluetoothDiscoveryFilter> df( - new BluetoothDiscoveryFilter(device::BLUETOOTH_TRANSPORT_DUAL)); - df->CopyFrom(*discovery_filter); - SetDiscoveryFilter( - std::move(df), - base::BindRepeating( - &BluetoothAdapterBlueZ::OnPreSetDiscoveryFilter, - weak_ptr_factory_.GetWeakPtr(), - base::BindRepeating(copyable_callback, /*is_error=*/false, - UMABluetoothDiscoverySessionOutcome::SUCCESS), - base::BindRepeating(copyable_callback, true)), - base::BindOnce( - &BluetoothAdapterBlueZ::OnPreSetDiscoveryFilterError, - weak_ptr_factory_.GetWeakPtr(), - base::BindRepeating(copyable_callback, /*is_error=*/false, - UMABluetoothDiscoverySessionOutcome::SUCCESS), - base::BindOnce(copyable_callback, true))); - return; - } - - // This is the first request to start device discovery. - bluez::BluezDBusManager::Get()->GetBluetoothAdapterClient()->StartDiscovery( - object_path_, - base::BindOnce( - &BluetoothAdapterBlueZ::OnStartDiscovery, + SetDiscoveryFilter( + std::move(discovery_filter), + base::BindRepeating( + &BluetoothAdapterBlueZ::OnPreSetDiscoveryFilter, weak_ptr_factory_.GetWeakPtr(), base::BindRepeating(copyable_callback, /*is_error=*/false, UMABluetoothDiscoverySessionOutcome::SUCCESS), base::BindRepeating(copyable_callback, true)), base::BindOnce( - &BluetoothAdapterBlueZ::OnStartDiscoveryError, + &BluetoothAdapterBlueZ::OnPreSetDiscoveryFilterError, weak_ptr_factory_.GetWeakPtr(), base::BindRepeating(copyable_callback, /*is_error=*/false, UMABluetoothDiscoverySessionOutcome::SUCCESS), @@ -1607,6 +1586,8 @@ void BluetoothAdapterBlueZ::SetDiscoveryFilter( std::unique_ptr<BluetoothDiscoveryFilter> discovery_filter, const base::Closure& callback, DiscoverySessionErrorCallback error_callback) { + DCHECK(discovery_filter.get()); + if (!IsPresent()) { std::move(error_callback) .Run(UMABluetoothDiscoverySessionOutcome::ADAPTER_REMOVED); @@ -1614,36 +1595,32 @@ void BluetoothAdapterBlueZ::SetDiscoveryFilter( } bluez::BluetoothAdapterClient::DiscoveryFilter dbus_discovery_filter; + uint16_t pathloss; + int16_t rssi; + uint8_t transport; + std::set<device::BluetoothUUID> uuids; + + if (discovery_filter->GetPathloss(&pathloss)) + dbus_discovery_filter.pathloss = std::make_unique<uint16_t>(pathloss); + + if (discovery_filter->GetRSSI(&rssi)) + dbus_discovery_filter.rssi = std::make_unique<int16_t>(rssi); + + transport = discovery_filter->GetTransport(); + if (transport == device::BLUETOOTH_TRANSPORT_LE) { + dbus_discovery_filter.transport = std::make_unique<std::string>("le"); + } else if (transport == device::BLUETOOTH_TRANSPORT_CLASSIC) { + dbus_discovery_filter.transport = std::make_unique<std::string>("bredr"); + } else if (transport == device::BLUETOOTH_TRANSPORT_DUAL) { + dbus_discovery_filter.transport = std::make_unique<std::string>("auto"); + } - if (discovery_filter.get() && !discovery_filter->IsDefault()) { - uint16_t pathloss; - int16_t rssi; - uint8_t transport; - std::set<device::BluetoothUUID> uuids; - - if (discovery_filter->GetPathloss(&pathloss)) - dbus_discovery_filter.pathloss.reset(new uint16_t(pathloss)); - - if (discovery_filter->GetRSSI(&rssi)) - dbus_discovery_filter.rssi.reset(new int16_t(rssi)); - - transport = discovery_filter->GetTransport(); - if (transport == device::BLUETOOTH_TRANSPORT_LE) { - dbus_discovery_filter.transport.reset(new std::string("le")); - } else if (transport == device::BLUETOOTH_TRANSPORT_CLASSIC) { - dbus_discovery_filter.transport.reset(new std::string("bredr")); - } else if (transport == device::BLUETOOTH_TRANSPORT_DUAL) { - dbus_discovery_filter.transport.reset(new std::string("auto")); - } - - discovery_filter->GetUUIDs(uuids); - if (uuids.size()) { - dbus_discovery_filter.uuids = std::unique_ptr<std::vector<std::string>>( - new std::vector<std::string>); + discovery_filter->GetUUIDs(uuids); + if (uuids.size()) { + dbus_discovery_filter.uuids = std::make_unique<std::vector<std::string>>(); - for (const auto& it : uuids) - dbus_discovery_filter.uuids.get()->push_back(it.value()); - } + for (const auto& it : uuids) + dbus_discovery_filter.uuids.get()->push_back(it.value()); } auto copyable_error_callback = diff --git a/chromium/device/bluetooth/bluez/bluetooth_device_bluez.cc b/chromium/device/bluetooth/bluez/bluetooth_device_bluez.cc index fadcb54401f..2d060a3424d 100644 --- a/chromium/device/bluetooth/bluez/bluetooth_device_bluez.cc +++ b/chromium/device/bluetooth/bluez/bluetooth_device_bluez.cc @@ -853,11 +853,13 @@ void BluetoothDeviceBlueZ::UpdateGattServices( // Add all previously unknown GATT services associated with the device. GattServiceAdded(service_path); - // If the service does not belong in this device, there is nothing left to - // do. + // |service_paths| includes all services for all devices, not just this + // device. GetGattService() will return nullptr for services belonging + // to other devices, so we skip those and keep looking for services that + // belong to this device. BluetoothRemoteGattService* service = GetGattService(service_path.value()); if (service == nullptr) { - return; + continue; } // Notify of GATT discovery complete if we haven't before. diff --git a/chromium/device/bluetooth/bluez/bluetooth_gatt_bluez_unittest.cc b/chromium/device/bluetooth/bluez/bluetooth_gatt_bluez_unittest.cc index 1f81414ef63..b59f4ace1d4 100644 --- a/chromium/device/bluetooth/bluez/bluetooth_gatt_bluez_unittest.cc +++ b/chromium/device/bluetooth/bluez/bluetooth_gatt_bluez_unittest.cc @@ -50,6 +50,7 @@ using device::BluetoothUUID; using device::TestBluetoothAdapterObserver; using UUIDSet = device::BluetoothDevice::UUIDSet; +using WriteType = device::BluetoothRemoteGattCharacteristic::WriteType; typedef std::unordered_map<device::BluetoothDevice*, device::BluetoothDevice::UUIDSet> @@ -96,7 +97,7 @@ void AddDeviceFilterWithUUID(BluetoothDiscoveryFilter* filter, class BluetoothGattBlueZTest : public testing::Test { public: BluetoothGattBlueZTest() - : fake_bluetooth_gatt_service_client_(NULL), + : fake_bluetooth_gatt_service_client_(nullptr), success_callback_count_(0), error_callback_count_(0) {} @@ -1027,7 +1028,7 @@ TEST_F(BluetoothGattBlueZTest, GattCharacteristicValue) { characteristic->GetIdentifier()); EXPECT_EQ(kHeartRateMeasurementUUID, characteristic->GetUUID()); characteristic->WriteRemoteCharacteristic( - write_value, + write_value, WriteType::kWithResponse, base::BindOnce(&BluetoothGattBlueZTest::SuccessCallback, base::Unretained(this)), base::BindOnce(&BluetoothGattBlueZTest::ServiceErrorCallback, @@ -1050,7 +1051,7 @@ TEST_F(BluetoothGattBlueZTest, GattCharacteristicValue) { characteristic->GetIdentifier()); EXPECT_EQ(kBodySensorLocationUUID, characteristic->GetUUID()); characteristic->WriteRemoteCharacteristic( - write_value, + write_value, WriteType::kWithResponse, base::BindOnce(&BluetoothGattBlueZTest::SuccessCallback, base::Unretained(this)), base::BindOnce(&BluetoothGattBlueZTest::ServiceErrorCallback, @@ -1077,7 +1078,7 @@ TEST_F(BluetoothGattBlueZTest, GattCharacteristicValue) { characteristic->GetIdentifier()); EXPECT_EQ(kHeartRateControlPointUUID, characteristic->GetUUID()); characteristic->WriteRemoteCharacteristic( - write_value, + write_value, WriteType::kWithResponse, base::BindOnce(&BluetoothGattBlueZTest::SuccessCallback, base::Unretained(this)), base::BindOnce(&BluetoothGattBlueZTest::ServiceErrorCallback, @@ -1095,7 +1096,7 @@ TEST_F(BluetoothGattBlueZTest, GattCharacteristicValue) { invalid_write_length.push_back(0x01); invalid_write_length.push_back(0x00); characteristic->WriteRemoteCharacteristic( - invalid_write_length, + invalid_write_length, WriteType::kWithResponse, base::BindOnce(&BluetoothGattBlueZTest::SuccessCallback, base::Unretained(this)), base::BindOnce(&BluetoothGattBlueZTest::ServiceErrorCallback, @@ -1109,6 +1110,227 @@ TEST_F(BluetoothGattBlueZTest, GattCharacteristicValue) { std::vector<uint8_t> invalid_write_value; invalid_write_value.push_back(0x02); characteristic->WriteRemoteCharacteristic( + invalid_write_value, WriteType::kWithResponse, + base::BindOnce(&BluetoothGattBlueZTest::SuccessCallback, + base::Unretained(this)), + base::BindOnce(&BluetoothGattBlueZTest::ServiceErrorCallback, + base::Unretained(this))); + EXPECT_EQ(1, success_callback_count_); + EXPECT_EQ(4, error_callback_count_); + EXPECT_EQ(BluetoothRemoteGattService::GATT_ERROR_FAILED, last_service_error_); + EXPECT_EQ(0, observer.gatt_characteristic_value_changed_count()); + + // Issue a read request. + characteristic = service->GetCharacteristic( + fake_bluetooth_gatt_characteristic_client_->GetBodySensorLocationPath() + .value()); + ASSERT_TRUE(characteristic); + EXPECT_EQ( + fake_bluetooth_gatt_characteristic_client_->GetBodySensorLocationPath() + .value(), + characteristic->GetIdentifier()); + EXPECT_EQ(kBodySensorLocationUUID, characteristic->GetUUID()); + characteristic->ReadRemoteCharacteristic( + base::BindOnce(&BluetoothGattBlueZTest::ValueCallback, + base::Unretained(this)), + base::BindOnce(&BluetoothGattBlueZTest::ServiceErrorCallback, + base::Unretained(this))); + EXPECT_EQ(2, success_callback_count_); + EXPECT_EQ(4, error_callback_count_); + EXPECT_EQ(0, observer.gatt_characteristic_value_changed_count()); + EXPECT_TRUE(ValuesEqual(characteristic->GetValue(), last_read_value_)); + + // Test long-running actions. + fake_bluetooth_gatt_characteristic_client_->SetExtraProcessing(1); + characteristic = service->GetCharacteristic( + fake_bluetooth_gatt_characteristic_client_->GetBodySensorLocationPath() + .value()); + ASSERT_TRUE(characteristic); + EXPECT_EQ( + fake_bluetooth_gatt_characteristic_client_->GetBodySensorLocationPath() + .value(), + characteristic->GetIdentifier()); + EXPECT_EQ(kBodySensorLocationUUID, characteristic->GetUUID()); + characteristic->ReadRemoteCharacteristic( + base::BindOnce(&BluetoothGattBlueZTest::ValueCallback, + base::Unretained(this)), + base::BindOnce(&BluetoothGattBlueZTest::ServiceErrorCallback, + base::Unretained(this))); + + // Callback counts shouldn't change, this one will be delayed until after + // tne next one. + EXPECT_EQ(2, success_callback_count_); + EXPECT_EQ(4, error_callback_count_); + EXPECT_EQ(0, observer.gatt_characteristic_value_changed_count()); + + // Next read should error because IN_PROGRESS + characteristic->ReadRemoteCharacteristic( + base::BindOnce(&BluetoothGattBlueZTest::ValueCallback, + base::Unretained(this)), + base::BindOnce(&BluetoothGattBlueZTest::ServiceErrorCallback, + base::Unretained(this))); + EXPECT_EQ(5, error_callback_count_); + EXPECT_EQ(BluetoothRemoteGattService::GATT_ERROR_IN_PROGRESS, + last_service_error_); + + // But previous call finished. + EXPECT_EQ(3, success_callback_count_); + EXPECT_EQ(0, observer.gatt_characteristic_value_changed_count()); + EXPECT_TRUE(ValuesEqual(characteristic->GetValue(), last_read_value_)); + fake_bluetooth_gatt_characteristic_client_->SetExtraProcessing(0); + + // Test unauthorized actions. + fake_bluetooth_gatt_characteristic_client_->SetAuthorized(false); + characteristic->ReadRemoteCharacteristic( + base::BindOnce(&BluetoothGattBlueZTest::ValueCallback, + base::Unretained(this)), + base::BindOnce(&BluetoothGattBlueZTest::ServiceErrorCallback, + base::Unretained(this))); + EXPECT_EQ(3, success_callback_count_); + EXPECT_EQ(6, error_callback_count_); + EXPECT_EQ(BluetoothRemoteGattService::GATT_ERROR_NOT_AUTHORIZED, + last_service_error_); + EXPECT_EQ(0, observer.gatt_characteristic_value_changed_count()); + fake_bluetooth_gatt_characteristic_client_->SetAuthorized(true); + + // Test unauthenticated / needs login. + fake_bluetooth_gatt_characteristic_client_->SetAuthenticated(false); + characteristic->ReadRemoteCharacteristic( + base::BindOnce(&BluetoothGattBlueZTest::ValueCallback, + base::Unretained(this)), + base::BindOnce(&BluetoothGattBlueZTest::ServiceErrorCallback, + base::Unretained(this))); + EXPECT_EQ(3, success_callback_count_); + EXPECT_EQ(7, error_callback_count_); + EXPECT_EQ(BluetoothRemoteGattService::GATT_ERROR_NOT_PAIRED, + last_service_error_); + EXPECT_EQ(0, observer.gatt_characteristic_value_changed_count()); + fake_bluetooth_gatt_characteristic_client_->SetAuthenticated(true); +} + +TEST_F(BluetoothGattBlueZTest, DeprecatedGattCharacteristicValue) { + fake_bluetooth_device_client_->CreateDevice( + dbus::ObjectPath(bluez::FakeBluetoothAdapterClient::kAdapterPath), + dbus::ObjectPath(bluez::FakeBluetoothDeviceClient::kLowEnergyPath)); + BluetoothDevice* device = + adapter_->GetDevice(bluez::FakeBluetoothDeviceClient::kLowEnergyAddress); + ASSERT_TRUE(device); + + TestBluetoothAdapterObserver observer(adapter_); + + // Expose the fake Heart Rate service. This will asynchronously expose + // characteristics. + fake_bluetooth_gatt_service_client_->ExposeHeartRateService( + dbus::ObjectPath(bluez::FakeBluetoothDeviceClient::kLowEnergyPath)); + ASSERT_EQ(1, observer.gatt_service_added_count()); + + BluetoothRemoteGattService* service = + device->GetGattService(observer.last_gatt_service_id()); + + EXPECT_EQ(0, observer.gatt_characteristic_value_changed_count()); + + // Run the message loop so that the characteristics appear. + base::RunLoop().Run(); + + // Issue write request to non-writable characteristics. + observer.Reset(); + + std::vector<uint8_t> write_value; + write_value.push_back(0x01); + BluetoothRemoteGattCharacteristic* characteristic = + service->GetCharacteristic(fake_bluetooth_gatt_characteristic_client_ + ->GetHeartRateMeasurementPath() + .value()); + ASSERT_TRUE(characteristic); + EXPECT_FALSE(characteristic->IsNotifying()); + EXPECT_EQ( + fake_bluetooth_gatt_characteristic_client_->GetHeartRateMeasurementPath() + .value(), + characteristic->GetIdentifier()); + EXPECT_EQ(kHeartRateMeasurementUUID, characteristic->GetUUID()); + characteristic->DeprecatedWriteRemoteCharacteristic( + write_value, + base::BindOnce(&BluetoothGattBlueZTest::SuccessCallback, + base::Unretained(this)), + base::BindOnce(&BluetoothGattBlueZTest::ServiceErrorCallback, + base::Unretained(this))); + EXPECT_TRUE(observer.last_gatt_characteristic_id().empty()); + EXPECT_FALSE(observer.last_gatt_characteristic_uuid().IsValid()); + EXPECT_EQ(0, success_callback_count_); + EXPECT_EQ(1, error_callback_count_); + EXPECT_EQ(BluetoothRemoteGattService::GATT_ERROR_NOT_SUPPORTED, + last_service_error_); + EXPECT_EQ(0, observer.gatt_characteristic_value_changed_count()); + + characteristic = service->GetCharacteristic( + fake_bluetooth_gatt_characteristic_client_->GetBodySensorLocationPath() + .value()); + ASSERT_TRUE(characteristic); + EXPECT_EQ( + fake_bluetooth_gatt_characteristic_client_->GetBodySensorLocationPath() + .value(), + characteristic->GetIdentifier()); + EXPECT_EQ(kBodySensorLocationUUID, characteristic->GetUUID()); + characteristic->DeprecatedWriteRemoteCharacteristic( + write_value, + base::BindOnce(&BluetoothGattBlueZTest::SuccessCallback, + base::Unretained(this)), + base::BindOnce(&BluetoothGattBlueZTest::ServiceErrorCallback, + base::Unretained(this))); + EXPECT_TRUE(observer.last_gatt_characteristic_id().empty()); + EXPECT_FALSE(observer.last_gatt_characteristic_uuid().IsValid()); + EXPECT_EQ(0, success_callback_count_); + EXPECT_EQ(2, error_callback_count_); + EXPECT_EQ(BluetoothRemoteGattService::GATT_ERROR_NOT_PERMITTED, + last_service_error_); + EXPECT_EQ(0, observer.gatt_characteristic_value_changed_count()); + + // Issue write request to writable characteristic. The "Body Sensor Location" + // characteristic does not send notifications and WriteValue does not result + // in a CharacteristicValueChanged event, thus no such event should be + // received. + characteristic = service->GetCharacteristic( + fake_bluetooth_gatt_characteristic_client_->GetHeartRateControlPointPath() + .value()); + ASSERT_TRUE(characteristic); + EXPECT_EQ( + fake_bluetooth_gatt_characteristic_client_->GetHeartRateControlPointPath() + .value(), + characteristic->GetIdentifier()); + EXPECT_EQ(kHeartRateControlPointUUID, characteristic->GetUUID()); + characteristic->DeprecatedWriteRemoteCharacteristic( + write_value, + base::BindOnce(&BluetoothGattBlueZTest::SuccessCallback, + base::Unretained(this)), + base::BindOnce(&BluetoothGattBlueZTest::ServiceErrorCallback, + base::Unretained(this))); + EXPECT_TRUE(observer.last_gatt_characteristic_id().empty()); + EXPECT_FALSE(observer.last_gatt_characteristic_uuid().IsValid()); + EXPECT_EQ(1, success_callback_count_); + EXPECT_EQ(2, error_callback_count_); + EXPECT_EQ(0, observer.gatt_characteristic_value_changed_count()); + + // Issue some invalid write requests to the characteristic. + // The value should still not change. + + std::vector<uint8_t> invalid_write_length; + invalid_write_length.push_back(0x01); + invalid_write_length.push_back(0x00); + characteristic->DeprecatedWriteRemoteCharacteristic( + invalid_write_length, + base::BindOnce(&BluetoothGattBlueZTest::SuccessCallback, + base::Unretained(this)), + base::BindOnce(&BluetoothGattBlueZTest::ServiceErrorCallback, + base::Unretained(this))); + EXPECT_EQ(1, success_callback_count_); + EXPECT_EQ(3, error_callback_count_); + EXPECT_EQ(BluetoothRemoteGattService::GATT_ERROR_INVALID_LENGTH, + last_service_error_); + EXPECT_EQ(0, observer.gatt_characteristic_value_changed_count()); + + std::vector<uint8_t> invalid_write_value; + invalid_write_value.push_back(0x02); + characteristic->DeprecatedWriteRemoteCharacteristic( invalid_write_value, base::BindOnce(&BluetoothGattBlueZTest::SuccessCallback, base::Unretained(this)), @@ -1288,12 +1510,63 @@ TEST_F(BluetoothGattBlueZTest, GattCharacteristicValue_Nested_Write_Write) { std::vector<uint8_t> write_value = {0x01}; characteristic->WriteRemoteCharacteristic( - write_value, base::BindLambdaForTesting([&] { + write_value, WriteType::kWithResponse, base::BindLambdaForTesting([&] { SuccessCallback(); EXPECT_EQ(1, success_callback_count_); EXPECT_EQ(0, error_callback_count_); characteristic->WriteRemoteCharacteristic( + write_value, WriteType::kWithResponse, + base::BindOnce(&BluetoothGattBlueZTest::SuccessCallback, + base::Unretained(this)), + base::BindOnce(&BluetoothGattBlueZTest::ServiceErrorCallback, + base::Unretained(this))); + }), + base::BindOnce(&BluetoothGattBlueZTest::ServiceErrorCallback, + base::Unretained(this))); + EXPECT_EQ(2, success_callback_count_); + EXPECT_EQ(0, error_callback_count_); +} + +// Test a write request issued from the success callback of another write +// request. +TEST_F(BluetoothGattBlueZTest, + GattCharacteristicValue_Nested_DeprecatedWrite_DeprecatedWrite) { + fake_bluetooth_device_client_->CreateDevice( + dbus::ObjectPath(bluez::FakeBluetoothAdapterClient::kAdapterPath), + dbus::ObjectPath(bluez::FakeBluetoothDeviceClient::kLowEnergyPath)); + BluetoothDevice* device = + adapter_->GetDevice(bluez::FakeBluetoothDeviceClient::kLowEnergyAddress); + ASSERT_TRUE(device); + + TestBluetoothAdapterObserver observer(adapter_); + + // Expose the fake Heart Rate service. This will asynchronously expose + // characteristics. + fake_bluetooth_gatt_service_client_->ExposeHeartRateService( + dbus::ObjectPath(bluez::FakeBluetoothDeviceClient::kLowEnergyPath)); + ASSERT_EQ(1, observer.gatt_service_added_count()); + + BluetoothRemoteGattService* service = + device->GetGattService(observer.last_gatt_service_id()); + + // Run the message loop so that the characteristics appear. + base::RunLoop().Run(); + + // Obtain writable Heart Rate Control Point characteristic. + BluetoothRemoteGattCharacteristic* characteristic = + service->GetCharacteristic(fake_bluetooth_gatt_characteristic_client_ + ->GetHeartRateControlPointPath() + .value()); + + std::vector<uint8_t> write_value = {0x01}; + characteristic->DeprecatedWriteRemoteCharacteristic( + write_value, base::BindLambdaForTesting([&] { + SuccessCallback(); + EXPECT_EQ(1, success_callback_count_); + EXPECT_EQ(0, error_callback_count_); + + characteristic->DeprecatedWriteRemoteCharacteristic( write_value, base::BindOnce(&BluetoothGattBlueZTest::SuccessCallback, base::Unretained(this)), @@ -1349,6 +1622,62 @@ TEST_F(BluetoothGattBlueZTest, GattCharacteristicValue_Nested_Read_Write) { .value()); characteristic->WriteRemoteCharacteristic( + std::vector<uint8_t>({0x01}), WriteType::kWithResponse, + base::BindOnce(&BluetoothGattBlueZTest::SuccessCallback, + base::Unretained(this)), + base::BindOnce(&BluetoothGattBlueZTest::ServiceErrorCallback, + base::Unretained(this))); + }), + base::BindOnce(&BluetoothGattBlueZTest::ServiceErrorCallback, + base::Unretained(this))); + EXPECT_EQ(2, success_callback_count_); + EXPECT_EQ(0, error_callback_count_); +} + +// Test a write request issued from the success callback of a read request. +TEST_F(BluetoothGattBlueZTest, + GattCharacteristicValue_Nested_Read_DeprecatedWrite) { + fake_bluetooth_device_client_->CreateDevice( + dbus::ObjectPath(bluez::FakeBluetoothAdapterClient::kAdapterPath), + dbus::ObjectPath(bluez::FakeBluetoothDeviceClient::kLowEnergyPath)); + BluetoothDevice* device = + adapter_->GetDevice(bluez::FakeBluetoothDeviceClient::kLowEnergyAddress); + ASSERT_TRUE(device); + + TestBluetoothAdapterObserver observer(adapter_); + + // Expose the fake Heart Rate service. This will asynchronously expose + // characteristics. + fake_bluetooth_gatt_service_client_->ExposeHeartRateService( + dbus::ObjectPath(bluez::FakeBluetoothDeviceClient::kLowEnergyPath)); + ASSERT_EQ(1, observer.gatt_service_added_count()); + + BluetoothRemoteGattService* service = + device->GetGattService(observer.last_gatt_service_id()); + + // Run the message loop so that the characteristics appear. + base::RunLoop().Run(); + + // Obtain readable Body Sensor Location characteristic. + BluetoothRemoteGattCharacteristic* characteristic = + service->GetCharacteristic(fake_bluetooth_gatt_characteristic_client_ + ->GetBodySensorLocationPath() + .value()); + + characteristic->ReadRemoteCharacteristic( + base::BindLambdaForTesting([&](const std::vector<uint8_t>& data) { + ValueCallback(data); + EXPECT_EQ(1, success_callback_count_); + EXPECT_EQ(0, error_callback_count_); + EXPECT_EQ(characteristic->GetValue(), last_read_value_); + + // Obtain writable Heart Rate Control Point characteristic. + characteristic = service->GetCharacteristic( + fake_bluetooth_gatt_characteristic_client_ + ->GetHeartRateControlPointPath() + .value()); + + characteristic->DeprecatedWriteRemoteCharacteristic( std::vector<uint8_t>({0x01}), base::BindOnce(&BluetoothGattBlueZTest::SuccessCallback, base::Unretained(this)), @@ -1391,6 +1720,62 @@ TEST_F(BluetoothGattBlueZTest, GattCharacteristicValue_Nested_Write_Read) { .value()); characteristic->WriteRemoteCharacteristic( + std::vector<uint8_t>({0x01}), WriteType::kWithResponse, + base::BindLambdaForTesting([&] { + SuccessCallback(); + EXPECT_EQ(1, success_callback_count_); + EXPECT_EQ(0, error_callback_count_); + + // Obtain readable Body Sensor Location characteristic. + characteristic = service->GetCharacteristic( + fake_bluetooth_gatt_characteristic_client_ + ->GetBodySensorLocationPath() + .value()); + + characteristic->ReadRemoteCharacteristic( + base::BindOnce(&BluetoothGattBlueZTest::ValueCallback, + base::Unretained(this)), + base::BindOnce(&BluetoothGattBlueZTest::ServiceErrorCallback, + base::Unretained(this))); + }), + base::BindOnce(&BluetoothGattBlueZTest::ServiceErrorCallback, + base::Unretained(this))); + EXPECT_EQ(2, success_callback_count_); + EXPECT_EQ(0, error_callback_count_); + EXPECT_EQ(characteristic->GetValue(), last_read_value_); +} + +// Test a read request issued from the success callback of a write request. +TEST_F(BluetoothGattBlueZTest, + GattCharacteristicValue_Nested_DeprecatedWrite_Read) { + fake_bluetooth_device_client_->CreateDevice( + dbus::ObjectPath(bluez::FakeBluetoothAdapterClient::kAdapterPath), + dbus::ObjectPath(bluez::FakeBluetoothDeviceClient::kLowEnergyPath)); + BluetoothDevice* device = + adapter_->GetDevice(bluez::FakeBluetoothDeviceClient::kLowEnergyAddress); + ASSERT_TRUE(device); + + TestBluetoothAdapterObserver observer(adapter_); + + // Expose the fake Heart Rate service. This will asynchronously expose + // characteristics. + fake_bluetooth_gatt_service_client_->ExposeHeartRateService( + dbus::ObjectPath(bluez::FakeBluetoothDeviceClient::kLowEnergyPath)); + ASSERT_EQ(1, observer.gatt_service_added_count()); + + BluetoothRemoteGattService* service = + device->GetGattService(observer.last_gatt_service_id()); + + // Run the message loop so that the characteristics appear. + base::RunLoop().Run(); + + // Obtain writable Heart Rate Control Point characteristic. + BluetoothRemoteGattCharacteristic* characteristic = + service->GetCharacteristic(fake_bluetooth_gatt_characteristic_client_ + ->GetHeartRateControlPointPath() + .value()); + + characteristic->DeprecatedWriteRemoteCharacteristic( std::vector<uint8_t>({0x01}), base::BindLambdaForTesting([&] { SuccessCallback(); EXPECT_EQ(1, success_callback_count_); @@ -2018,4 +2403,50 @@ TEST_F(BluetoothGattBlueZTest, NotificationType) { } #endif +TEST_F(BluetoothGattBlueZTest, MultipleDevices) { + fake_bluetooth_device_client_->CreateDevice( + dbus::ObjectPath(bluez::FakeBluetoothAdapterClient::kAdapterPath), + dbus::ObjectPath(bluez::FakeBluetoothDeviceClient::kLowEnergyPath)); + bluez::FakeBluetoothDeviceClient::Properties* properties1 = + fake_bluetooth_device_client_->GetProperties( + dbus::ObjectPath(bluez::FakeBluetoothDeviceClient::kLowEnergyPath)); + properties1->services_resolved.ReplaceValue(false); + + fake_bluetooth_gatt_service_client_->ExposeHeartRateService( + dbus::ObjectPath(bluez::FakeBluetoothDeviceClient::kLowEnergyPath)); + while (!fake_bluetooth_gatt_characteristic_client_->IsHeartRateVisible()) + base::RunLoop().RunUntilIdle(); + ASSERT_TRUE(fake_bluetooth_gatt_service_client_->IsHeartRateVisible()); + ASSERT_TRUE(fake_bluetooth_gatt_characteristic_client_->IsHeartRateVisible()); + + fake_bluetooth_device_client_->CreateDevice( + dbus::ObjectPath(bluez::FakeBluetoothAdapterClient::kAdapterPath), + dbus::ObjectPath(bluez::FakeBluetoothDeviceClient::kDualPath)); + bluez::FakeBluetoothDeviceClient::Properties* properties2 = + fake_bluetooth_device_client_->GetProperties( + dbus::ObjectPath(bluez::FakeBluetoothDeviceClient::kDualPath)); + properties2->services_resolved.ReplaceValue(false); + + fake_bluetooth_gatt_service_client_->ExposeBatteryService( + dbus::ObjectPath(bluez::FakeBluetoothDeviceClient::kDualPath)); + ASSERT_TRUE(fake_bluetooth_gatt_service_client_->IsBatteryServiceVisible()); + + BluetoothDeviceBlueZ* device1 = static_cast<BluetoothDeviceBlueZ*>( + adapter_->GetDevice(bluez::FakeBluetoothDeviceClient::kLowEnergyAddress)); + ASSERT_TRUE(device1); + BluetoothDeviceBlueZ* device2 = static_cast<BluetoothDeviceBlueZ*>( + adapter_->GetDevice(bluez::FakeBluetoothDeviceClient::kDualAddress)); + ASSERT_TRUE(device2); + + TestBluetoothAdapterObserver observer(adapter_); + + EXPECT_EQ(0, observer.gatt_discovery_complete_count()); + + properties1->services_resolved.ReplaceValue(true); + properties2->services_resolved.ReplaceValue(true); + + // Since BlueZ iterates all services for all devices for each device, this + // can catch errors like https://crbug.com/1087648 + EXPECT_EQ(2, observer.gatt_discovery_complete_count()); +} } // namespace bluez diff --git a/chromium/device/bluetooth/bluez/bluetooth_pairing_bluez.cc b/chromium/device/bluetooth/bluez/bluetooth_pairing_bluez.cc index b6e96297052..e0bb2b6ae37 100644 --- a/chromium/device/bluetooth/bluez/bluetooth_pairing_bluez.cc +++ b/chromium/device/bluetooth/bluez/bluetooth_pairing_bluez.cc @@ -67,7 +67,7 @@ BluetoothPairingBlueZ::~BluetoothPairingBlueZ() { .Run(bluez::BluetoothAgentServiceProvider::Delegate::CANCELLED); } - pairing_delegate_ = NULL; + pairing_delegate_ = nullptr; } void BluetoothPairingBlueZ::RequestPinCode( diff --git a/chromium/device/bluetooth/bluez/bluetooth_remote_gatt_characteristic_bluez.cc b/chromium/device/bluetooth/bluez/bluetooth_remote_gatt_characteristic_bluez.cc index 18f508f36fb..d68db58794f 100644 --- a/chromium/device/bluetooth/bluez/bluetooth_remote_gatt_characteristic_bluez.cc +++ b/chromium/device/bluetooth/bluez/bluetooth_remote_gatt_characteristic_bluez.cc @@ -24,6 +24,7 @@ #include "device/bluetooth/bluez/bluetooth_remote_gatt_service_bluez.h" #include "device/bluetooth/dbus/bluetooth_gatt_characteristic_client.h" #include "device/bluetooth/dbus/bluez_dbus_manager.h" +#include "third_party/cros_system_api/dbus/bluetooth/dbus-constants.h" #include "third_party/cros_system_api/dbus/service_constants.h" namespace bluez { @@ -173,16 +174,46 @@ void BluetoothRemoteGattCharacteristicBlueZ::ReadRemoteCharacteristic( void BluetoothRemoteGattCharacteristicBlueZ::WriteRemoteCharacteristic( const std::vector<uint8_t>& value, + WriteType write_type, base::OnceClosure callback, ErrorCallback error_callback) { DVLOG(1) << "Sending GATT characteristic write request to characteristic: " << GetIdentifier() << ", UUID: " << GetUUID().canonical_value() + << ", with value: " << value << ", with response: " + << ((write_type == WriteType::kWithoutResponse) ? "no" : "yes") + << "."; + + const char* type_option; + switch (write_type) { + case WriteType::kWithResponse: + type_option = bluetooth_gatt_characteristic::kTypeRequest; + break; + case WriteType::kWithoutResponse: + type_option = bluetooth_gatt_characteristic::kTypeCommand; + break; + } + + bluez::BluezDBusManager::Get() + ->GetBluetoothGattCharacteristicClient() + ->WriteValue( + object_path(), value, type_option, std::move(callback), + base::BindOnce(&BluetoothRemoteGattCharacteristicBlueZ::OnWriteError, + weak_ptr_factory_.GetWeakPtr(), + std::move(error_callback))); +} + +void BluetoothRemoteGattCharacteristicBlueZ:: + DeprecatedWriteRemoteCharacteristic(const std::vector<uint8_t>& value, + base::OnceClosure callback, + ErrorCallback error_callback) { + DVLOG(1) << "Sending GATT characteristic write request to characteristic: " + << GetIdentifier() << ", UUID: " << GetUUID().canonical_value() << ", with value: " << value << "."; bluez::BluezDBusManager::Get() ->GetBluetoothGattCharacteristicClient() ->WriteValue( - object_path(), value, std::move(callback), + object_path(), value, "", std::move(callback), base::BindOnce(&BluetoothRemoteGattCharacteristicBlueZ::OnWriteError, weak_ptr_factory_.GetWeakPtr(), std::move(error_callback))); diff --git a/chromium/device/bluetooth/bluez/bluetooth_remote_gatt_characteristic_bluez.h b/chromium/device/bluetooth/bluez/bluetooth_remote_gatt_characteristic_bluez.h index f435e4ddbd4..164aa707956 100644 --- a/chromium/device/bluetooth/bluez/bluetooth_remote_gatt_characteristic_bluez.h +++ b/chromium/device/bluetooth/bluez/bluetooth_remote_gatt_characteristic_bluez.h @@ -57,8 +57,13 @@ class BluetoothRemoteGattCharacteristicBlueZ void ReadRemoteCharacteristic(ValueCallback callback, ErrorCallback error_callback) override; void WriteRemoteCharacteristic(const std::vector<uint8_t>& value, + WriteType write_type, base::OnceClosure callback, ErrorCallback error_callback) override; + void DeprecatedWriteRemoteCharacteristic( + const std::vector<uint8_t>& value, + base::OnceClosure callback, + ErrorCallback error_callback) override; #if defined(OS_CHROMEOS) void PrepareWriteRemoteCharacteristic(const std::vector<uint8_t>& value, base::OnceClosure callback, diff --git a/chromium/device/bluetooth/cast/bluetooth_adapter_cast.cc b/chromium/device/bluetooth/cast/bluetooth_adapter_cast.cc index 1eee419655c..5113465e533 100644 --- a/chromium/device/bluetooth/cast/bluetooth_adapter_cast.cc +++ b/chromium/device/bluetooth/cast/bluetooth_adapter_cast.cc @@ -9,6 +9,7 @@ #include "base/bind.h" #include "base/callback_helpers.h" #include "base/location.h" +#include "base/logging.h" #include "base/no_destructor.h" #include "base/task/post_task.h" #include "base/threading/sequenced_task_runner_handle.h" diff --git a/chromium/device/bluetooth/cast/bluetooth_device_cast.cc b/chromium/device/bluetooth/cast/bluetooth_device_cast.cc index 4ec0b249e26..17da5222f60 100644 --- a/chromium/device/bluetooth/cast/bluetooth_device_cast.cc +++ b/chromium/device/bluetooth/cast/bluetooth_device_cast.cc @@ -10,6 +10,7 @@ #include <utility> #include "base/bind.h" +#include "base/logging.h" #include "base/strings/stringprintf.h" #include "chromecast/device/bluetooth/bluetooth_util.h" #include "chromecast/device/bluetooth/le/remote_characteristic.h" diff --git a/chromium/device/bluetooth/cast/bluetooth_remote_gatt_characteristic_cast.cc b/chromium/device/bluetooth/cast/bluetooth_remote_gatt_characteristic_cast.cc index 83cdc280981..e52f00359e6 100644 --- a/chromium/device/bluetooth/cast/bluetooth_remote_gatt_characteristic_cast.cc +++ b/chromium/device/bluetooth/cast/bluetooth_remote_gatt_characteristic_cast.cc @@ -10,10 +10,12 @@ #include "base/callback.h" #include "base/callback_forward.h" #include "base/containers/queue.h" +#include "base/logging.h" #include "base/macros.h" #include "base/memory/weak_ptr.h" #include "chromecast/device/bluetooth/le/remote_characteristic.h" #include "chromecast/device/bluetooth/le/remote_descriptor.h" +#include "chromecast/public/bluetooth/gatt.h" #include "device/bluetooth/cast/bluetooth_remote_gatt_descriptor_cast.h" #include "device/bluetooth/cast/bluetooth_remote_gatt_service_cast.h" #include "device/bluetooth/cast/bluetooth_utils.h" @@ -143,6 +145,32 @@ void BluetoothRemoteGattCharacteristicCast::ReadRemoteCharacteristic( void BluetoothRemoteGattCharacteristicCast::WriteRemoteCharacteristic( const std::vector<uint8_t>& value, + WriteType write_type, + base::OnceClosure callback, + ErrorCallback error_callback) { + using ChromecastWriteType = chromecast::bluetooth_v2_shlib::Gatt::WriteType; + + ChromecastWriteType chromecast_write_type; + switch (write_type) { + case WriteType::kWithResponse: + chromecast_write_type = ChromecastWriteType::WRITE_TYPE_DEFAULT; + break; + case WriteType::kWithoutResponse: + chromecast_write_type = ChromecastWriteType::WRITE_TYPE_NO_RESPONSE; + break; + } + + remote_characteristic_->WriteAuth( + chromecast::bluetooth_v2_shlib::Gatt::Client::AUTH_REQ_NONE, + chromecast_write_type, value, + base::BindOnce( + &BluetoothRemoteGattCharacteristicCast::OnWriteRemoteCharacteristic, + weak_factory_.GetWeakPtr(), value, std::move(callback), + std::move(error_callback))); +} + +void BluetoothRemoteGattCharacteristicCast::DeprecatedWriteRemoteCharacteristic( + const std::vector<uint8_t>& value, base::OnceClosure callback, ErrorCallback error_callback) { remote_characteristic_->Write( diff --git a/chromium/device/bluetooth/cast/bluetooth_remote_gatt_characteristic_cast.h b/chromium/device/bluetooth/cast/bluetooth_remote_gatt_characteristic_cast.h index f42c545fece..af4dd712c5f 100644 --- a/chromium/device/bluetooth/cast/bluetooth_remote_gatt_characteristic_cast.h +++ b/chromium/device/bluetooth/cast/bluetooth_remote_gatt_characteristic_cast.h @@ -48,8 +48,13 @@ class BluetoothRemoteGattCharacteristicCast void ReadRemoteCharacteristic(ValueCallback callback, ErrorCallback error_callback) override; void WriteRemoteCharacteristic(const std::vector<uint8_t>& value, + WriteType write_type, base::OnceClosure callback, ErrorCallback error_callback) override; + void DeprecatedWriteRemoteCharacteristic( + const std::vector<uint8_t>& value, + base::OnceClosure callback, + ErrorCallback error_callback) override; // Called by BluetoothAdapterCast to set the value when a new notification // comes in. diff --git a/chromium/device/bluetooth/dbus/bluetooth_gatt_application_service_provider.cc b/chromium/device/bluetooth/dbus/bluetooth_gatt_application_service_provider.cc index 6ccfcc27914..611e810ffb6 100644 --- a/chromium/device/bluetooth/dbus/bluetooth_gatt_application_service_provider.cc +++ b/chromium/device/bluetooth/dbus/bluetooth_gatt_application_service_provider.cc @@ -7,6 +7,7 @@ #include <string> #include <utility> +#include "base/logging.h" #include "base/memory/ptr_util.h" #include "device/bluetooth/bluetooth_gatt_characteristic.h" #include "device/bluetooth/bluez/bluetooth_gatt_service_bluez.h" diff --git a/chromium/device/bluetooth/dbus/bluetooth_gatt_characteristic_client.cc b/chromium/device/bluetooth/dbus/bluetooth_gatt_characteristic_client.cc index ec4a928cdb2..4ae1703db72 100644 --- a/chromium/device/bluetooth/dbus/bluetooth_gatt_characteristic_client.cc +++ b/chromium/device/bluetooth/dbus/bluetooth_gatt_characteristic_client.cc @@ -7,6 +7,7 @@ #include <stddef.h> #include "base/bind.h" +#include "base/logging.h" #include "base/macros.h" #include "base/memory/weak_ptr.h" #include "base/observer_list.h" @@ -14,6 +15,7 @@ #include "dbus/bus.h" #include "dbus/object_manager.h" #include "dbus/values_util.h" +#include "third_party/cros_system_api/dbus/bluetooth/dbus-constants.h" #include "third_party/cros_system_api/dbus/service_constants.h" namespace bluez { @@ -113,6 +115,7 @@ class BluetoothGattCharacteristicClientImpl // BluetoothGattCharacteristicClient override. void WriteValue(const dbus::ObjectPath& object_path, const std::vector<uint8_t>& value, + base::StringPiece type_option, base::OnceClosure callback, ErrorCallback error_callback) override { dbus::ObjectProxy* object_proxy = @@ -128,8 +131,14 @@ class BluetoothGattCharacteristicClientImpl dbus::MessageWriter writer(&method_call); writer.AppendArrayOfBytes(value.data(), value.size()); - // Append empty option dict + // Append option dict base::DictionaryValue dict; + if (!type_option.empty()) { + // NB: the "type" option was added in BlueZ 5.51. Older versions of BlueZ + // will ignore this option. + dict.SetStringKey(bluetooth_gatt_characteristic::kOptionType, + type_option); + } dbus::AppendValueData(&writer, dict); object_proxy->CallMethodWithErrorCallback( diff --git a/chromium/device/bluetooth/dbus/bluetooth_gatt_characteristic_client.h b/chromium/device/bluetooth/dbus/bluetooth_gatt_characteristic_client.h index b76a8317d39..93b4cc76c15 100644 --- a/chromium/device/bluetooth/dbus/bluetooth_gatt_characteristic_client.h +++ b/chromium/device/bluetooth/dbus/bluetooth_gatt_characteristic_client.h @@ -105,10 +105,12 @@ class DEVICE_BLUETOOTH_EXPORT BluetoothGattCharacteristicClient ErrorCallback error_callback) = 0; // Issues a request to write the value of GATT characteristic with object path - // |object_path| with value |value|. Invokes |callback| on success and - // |error_callback| on failure. + // |object_path| with value |value| and |type_option|. |type_option| is + // bluetooth_gatt_characteristic::kTypeRequest or kTypeCommand, or "" to omit + // the option. Invokes |callback| on success and |error_callback| on failure. virtual void WriteValue(const dbus::ObjectPath& object_path, const std::vector<uint8_t>& value, + base::StringPiece type_option, base::OnceClosure callback, ErrorCallback error_callback) = 0; diff --git a/chromium/device/bluetooth/dbus/bluetooth_gatt_descriptor_client.cc b/chromium/device/bluetooth/dbus/bluetooth_gatt_descriptor_client.cc index ff3f0d53765..c2fbd87c6fd 100644 --- a/chromium/device/bluetooth/dbus/bluetooth_gatt_descriptor_client.cc +++ b/chromium/device/bluetooth/dbus/bluetooth_gatt_descriptor_client.cc @@ -7,6 +7,7 @@ #include <stddef.h> #include "base/bind.h" +#include "base/logging.h" #include "base/macros.h" #include "base/memory/weak_ptr.h" #include "base/observer_list.h" diff --git a/chromium/device/bluetooth/dbus/bluetooth_gatt_service_client.cc b/chromium/device/bluetooth/dbus/bluetooth_gatt_service_client.cc index 014f26f6ceb..2ea601b5c78 100644 --- a/chromium/device/bluetooth/dbus/bluetooth_gatt_service_client.cc +++ b/chromium/device/bluetooth/dbus/bluetooth_gatt_service_client.cc @@ -5,6 +5,7 @@ #include "device/bluetooth/dbus/bluetooth_gatt_service_client.h" #include "base/bind.h" +#include "base/logging.h" #include "base/macros.h" #include "base/memory/weak_ptr.h" #include "base/observer_list.h" diff --git a/chromium/device/bluetooth/dbus/bluez_dbus_manager.cc b/chromium/device/bluetooth/dbus/bluez_dbus_manager.cc index 9edc0a39a1a..bd1df9bfe7b 100644 --- a/chromium/device/bluetooth/dbus/bluez_dbus_manager.cc +++ b/chromium/device/bluetooth/dbus/bluez_dbus_manager.cc @@ -10,6 +10,7 @@ #include "base/bind.h" #include "base/command_line.h" #include "base/feature_list.h" +#include "base/logging.h" #include "base/memory/ptr_util.h" #include "base/system/sys_info.h" #include "base/threading/thread.h" diff --git a/chromium/device/bluetooth/dbus/bluez_dbus_thread_manager.cc b/chromium/device/bluetooth/dbus/bluez_dbus_thread_manager.cc index 31793710e2b..8b606656703 100644 --- a/chromium/device/bluetooth/dbus/bluez_dbus_thread_manager.cc +++ b/chromium/device/bluetooth/dbus/bluez_dbus_thread_manager.cc @@ -4,6 +4,7 @@ #include "device/bluetooth/dbus/bluez_dbus_thread_manager.h" +#include "base/logging.h" #include "base/message_loop/message_pump_type.h" #include "base/threading/thread.h" #include "dbus/bus.h" diff --git a/chromium/device/bluetooth/dbus/fake_bluetooth_agent_manager_client.cc b/chromium/device/bluetooth/dbus/fake_bluetooth_agent_manager_client.cc index 4885352ee59..48107e1091d 100644 --- a/chromium/device/bluetooth/dbus/fake_bluetooth_agent_manager_client.cc +++ b/chromium/device/bluetooth/dbus/fake_bluetooth_agent_manager_client.cc @@ -11,7 +11,7 @@ namespace bluez { FakeBluetoothAgentManagerClient::FakeBluetoothAgentManagerClient() - : service_provider_(NULL) {} + : service_provider_(nullptr) {} FakeBluetoothAgentManagerClient::~FakeBluetoothAgentManagerClient() = default; @@ -81,7 +81,7 @@ void FakeBluetoothAgentManagerClient::RegisterAgentServiceProvider( void FakeBluetoothAgentManagerClient::UnregisterAgentServiceProvider( FakeBluetoothAgentServiceProvider* service_provider) { if (service_provider_ == service_provider) - service_provider_ = NULL; + service_provider_ = nullptr; } FakeBluetoothAgentServiceProvider* diff --git a/chromium/device/bluetooth/dbus/fake_bluetooth_agent_service_provider.cc b/chromium/device/bluetooth/dbus/fake_bluetooth_agent_service_provider.cc index 2266c059d4f..edfe29d3b31 100644 --- a/chromium/device/bluetooth/dbus/fake_bluetooth_agent_service_provider.cc +++ b/chromium/device/bluetooth/dbus/fake_bluetooth_agent_service_provider.cc @@ -4,6 +4,7 @@ #include "device/bluetooth/dbus/fake_bluetooth_agent_service_provider.h" +#include "base/logging.h" #include "device/bluetooth/dbus/bluez_dbus_manager.h" #include "device/bluetooth/dbus/fake_bluetooth_agent_manager_client.h" diff --git a/chromium/device/bluetooth/dbus/fake_bluetooth_device_client.cc b/chromium/device/bluetooth/dbus/fake_bluetooth_device_client.cc index 3f137c01978..23c5fe33b0b 100644 --- a/chromium/device/bluetooth/dbus/fake_bluetooth_device_client.cc +++ b/chromium/device/bluetooth/dbus/fake_bluetooth_device_client.cc @@ -650,6 +650,7 @@ void FakeBluetoothDeviceClient::ExecuteWrite( bluez::BluezDBusManager::Get() ->GetBluetoothGattCharacteristicClient() ->WriteValue(prepare_write_request.first, prepare_write_request.second, + bluetooth_gatt_characteristic::kTypeRequest, base::DoNothing(), base::DoNothing()); } prepare_write_requests_.clear(); @@ -882,248 +883,242 @@ void FakeBluetoothDeviceClient::CreateDeviceWithProperties( observer.DeviceAdded(device_path); } -std::unique_ptr<base::ListValue> -FakeBluetoothDeviceClient::GetBluetoothDevicesAsDictionaries() const { - std::unique_ptr<base::ListValue> predefined_devices(new base::ListValue); - std::unique_ptr<base::DictionaryValue> pairedDevice( - new base::DictionaryValue); - pairedDevice->SetString("path", kPairedDevicePath); - pairedDevice->SetString("address", kPairedDeviceAddress); - pairedDevice->SetString("name", kPairedDeviceName); - pairedDevice->SetString("alias", kPairedDeviceName); - pairedDevice->SetString("pairingMethod", ""); - pairedDevice->SetString("pairingAuthToken", ""); - pairedDevice->SetString("pairingAction", ""); - pairedDevice->SetInteger("classValue", kPairedDeviceClass); - pairedDevice->SetBoolean("discoverable", true); - pairedDevice->SetBoolean("isTrusted", true); - pairedDevice->SetBoolean("paired", true); - pairedDevice->SetBoolean("incoming", false); - predefined_devices->Append(std::move(pairedDevice)); - - std::unique_ptr<base::DictionaryValue> legacyDevice( - new base::DictionaryValue); - legacyDevice->SetString("path", kLegacyAutopairPath); - legacyDevice->SetString("address", kLegacyAutopairAddress); - legacyDevice->SetString("name", kLegacyAutopairName); - legacyDevice->SetString("alias", kLegacyAutopairName); - legacyDevice->SetString("pairingMethod", ""); - legacyDevice->SetString("pairingAuthToken", ""); - legacyDevice->SetString("pairingAction", ""); - legacyDevice->SetInteger("classValue", kLegacyAutopairClass); - legacyDevice->SetBoolean("isTrusted", true); - legacyDevice->SetBoolean("discoverable", false); - legacyDevice->SetBoolean("paired", false); - legacyDevice->SetBoolean("incoming", false); - predefined_devices->Append(std::move(legacyDevice)); - - std::unique_ptr<base::DictionaryValue> pin(new base::DictionaryValue); - pin->SetString("path", kDisplayPinCodePath); - pin->SetString("address", kDisplayPinCodeAddress); - pin->SetString("name", kDisplayPinCodeName); - pin->SetString("alias", kDisplayPinCodeName); - pin->SetString("pairingMethod", kPairingMethodPinCode); - pin->SetString("pairingAuthToken", kTestPinCode); - pin->SetString("pairingAction", kPairingActionDisplay); - pin->SetInteger("classValue", kDisplayPinCodeClass); - pin->SetBoolean("isTrusted", false); - pin->SetBoolean("discoverable", false); - pin->SetBoolean("paired", false); - pin->SetBoolean("incoming", false); - predefined_devices->Append(std::move(pin)); - - std::unique_ptr<base::DictionaryValue> vanishing(new base::DictionaryValue); - vanishing->SetString("path", kVanishingDevicePath); - vanishing->SetString("address", kVanishingDeviceAddress); - vanishing->SetString("name", kVanishingDeviceName); - vanishing->SetString("alias", kVanishingDeviceName); - vanishing->SetString("pairingMethod", ""); - vanishing->SetString("pairingAuthToken", ""); - vanishing->SetString("pairingAction", ""); - vanishing->SetInteger("classValue", kVanishingDeviceClass); - vanishing->SetBoolean("isTrusted", false); - vanishing->SetBoolean("discoverable", false); - vanishing->SetBoolean("paired", false); - vanishing->SetBoolean("incoming", false); - predefined_devices->Append(std::move(vanishing)); - - std::unique_ptr<base::DictionaryValue> connect_unpairable( - new base::DictionaryValue); - connect_unpairable->SetString("path", kConnectUnpairablePath); - connect_unpairable->SetString("address", kConnectUnpairableAddress); - connect_unpairable->SetString("name", kConnectUnpairableName); - connect_unpairable->SetString("pairingMethod", ""); - connect_unpairable->SetString("pairingAuthToken", ""); - connect_unpairable->SetString("pairingAction", ""); - connect_unpairable->SetString("alias", kConnectUnpairableName); - connect_unpairable->SetInteger("classValue", kConnectUnpairableClass); - connect_unpairable->SetBoolean("isTrusted", false); - connect_unpairable->SetBoolean("discoverable", false); - connect_unpairable->SetBoolean("paired", false); - connect_unpairable->SetBoolean("incoming", false); - predefined_devices->Append(std::move(connect_unpairable)); - - std::unique_ptr<base::DictionaryValue> passkey(new base::DictionaryValue); - passkey->SetString("path", kDisplayPasskeyPath); - passkey->SetString("address", kDisplayPasskeyAddress); - passkey->SetString("name", kDisplayPasskeyName); - passkey->SetString("alias", kDisplayPasskeyName); - passkey->SetString("pairingMethod", kPairingMethodPassKey); - passkey->SetInteger("pairingAuthToken", kTestPassKey); - passkey->SetString("pairingAction", kPairingActionDisplay); - passkey->SetInteger("classValue", kDisplayPasskeyClass); - passkey->SetBoolean("isTrusted", false); - passkey->SetBoolean("discoverable", false); - passkey->SetBoolean("paired", false); - passkey->SetBoolean("incoming", false); - predefined_devices->Append(std::move(passkey)); - - std::unique_ptr<base::DictionaryValue> request_pin(new base::DictionaryValue); - request_pin->SetString("path", kRequestPinCodePath); - request_pin->SetString("address", kRequestPinCodeAddress); - request_pin->SetString("name", kRequestPinCodeName); - request_pin->SetString("alias", kRequestPinCodeName); - request_pin->SetString("pairingMethod", ""); - request_pin->SetString("pairingAuthToken", ""); - request_pin->SetString("pairingAction", kPairingActionRequest); - request_pin->SetInteger("classValue", kRequestPinCodeClass); - request_pin->SetBoolean("isTrusted", false); - request_pin->SetBoolean("discoverable", false); - request_pin->SetBoolean("paired", false); - request_pin->SetBoolean("incoming", false); - predefined_devices->Append(std::move(request_pin)); - - std::unique_ptr<base::DictionaryValue> confirm(new base::DictionaryValue); - confirm->SetString("path", kConfirmPasskeyPath); - confirm->SetString("address", kConfirmPasskeyAddress); - confirm->SetString("name", kConfirmPasskeyName); - confirm->SetString("alias", kConfirmPasskeyName); - confirm->SetString("pairingMethod", ""); - confirm->SetInteger("pairingAuthToken", kTestPassKey); - confirm->SetString("pairingAction", kPairingActionConfirmation); - confirm->SetInteger("classValue", kConfirmPasskeyClass); - confirm->SetBoolean("isTrusted", false); - confirm->SetBoolean("discoverable", false); - confirm->SetBoolean("paired", false); - confirm->SetBoolean("incoming", false); - predefined_devices->Append(std::move(confirm)); - - std::unique_ptr<base::DictionaryValue> request_passkey( - new base::DictionaryValue); - request_passkey->SetString("path", kRequestPasskeyPath); - request_passkey->SetString("address", kRequestPasskeyAddress); - request_passkey->SetString("name", kRequestPasskeyName); - request_passkey->SetString("alias", kRequestPasskeyName); - request_passkey->SetString("pairingMethod", kPairingMethodPassKey); - request_passkey->SetString("pairingAction", kPairingActionRequest); - request_passkey->SetInteger("pairingAuthToken", kTestPassKey); - request_passkey->SetInteger("classValue", kRequestPasskeyClass); - request_passkey->SetBoolean("isTrusted", false); - request_passkey->SetBoolean("discoverable", false); - request_passkey->SetBoolean("paired", false); - request_passkey->SetBoolean("incoming", false); - predefined_devices->Append(std::move(request_passkey)); - - std::unique_ptr<base::DictionaryValue> unconnectable( - new base::DictionaryValue); - unconnectable->SetString("path", kUnconnectableDevicePath); - unconnectable->SetString("address", kUnconnectableDeviceAddress); - unconnectable->SetString("name", kUnconnectableDeviceName); - unconnectable->SetString("alias", kUnconnectableDeviceName); - unconnectable->SetString("pairingMethod", ""); - unconnectable->SetString("pairingAuthToken", ""); - unconnectable->SetString("pairingAction", ""); - unconnectable->SetInteger("classValue", kUnconnectableDeviceClass); - unconnectable->SetBoolean("isTrusted", true); - unconnectable->SetBoolean("discoverable", false); - unconnectable->SetBoolean("paired", false); - unconnectable->SetBoolean("incoming", false); - predefined_devices->Append(std::move(unconnectable)); - - std::unique_ptr<base::DictionaryValue> unpairable(new base::DictionaryValue); - unpairable->SetString("path", kUnpairableDevicePath); - unpairable->SetString("address", kUnpairableDeviceAddress); - unpairable->SetString("name", kUnpairableDeviceName); - unpairable->SetString("alias", kUnpairableDeviceName); - unpairable->SetString("pairingMethod", ""); - unpairable->SetString("pairingAuthToken", ""); - unpairable->SetString("pairingAction", kPairingActionFail); - unpairable->SetInteger("classValue", kUnpairableDeviceClass); - unpairable->SetBoolean("isTrusted", false); - unpairable->SetBoolean("discoverable", false); - unpairable->SetBoolean("paired", false); - unpairable->SetBoolean("incoming", false); - predefined_devices->Append(std::move(unpairable)); - - std::unique_ptr<base::DictionaryValue> just_works(new base::DictionaryValue); - just_works->SetString("path", kJustWorksPath); - just_works->SetString("address", kJustWorksAddress); - just_works->SetString("name", kJustWorksName); - just_works->SetString("alias", kJustWorksName); - just_works->SetString("pairingMethod", ""); - just_works->SetString("pairingAuthToken", ""); - just_works->SetString("pairingAction", ""); - just_works->SetInteger("classValue", kJustWorksClass); - just_works->SetBoolean("isTrusted", false); - just_works->SetBoolean("discoverable", false); - just_works->SetBoolean("paired", false); - just_works->SetBoolean("incoming", false); - predefined_devices->Append(std::move(just_works)); - - std::unique_ptr<base::DictionaryValue> low_energy(new base::DictionaryValue); - low_energy->SetString("path", kLowEnergyPath); - low_energy->SetString("address", kLowEnergyAddress); - low_energy->SetString("name", kLowEnergyName); - low_energy->SetString("alias", kLowEnergyName); - low_energy->SetString("pairingMethod", ""); - low_energy->SetString("pairingAuthToken", ""); - low_energy->SetString("pairingAction", ""); - low_energy->SetInteger("classValue", kLowEnergyClass); - low_energy->SetBoolean("isTrusted", false); - low_energy->SetBoolean("discoverable", false); - low_energy->SetBoolean("paireed", false); - low_energy->SetBoolean("incoming", false); - predefined_devices->Append(std::move(low_energy)); - - std::unique_ptr<base::DictionaryValue> paired_unconnectable( - new base::DictionaryValue); - paired_unconnectable->SetString("path", kPairedUnconnectableDevicePath); - paired_unconnectable->SetString("address", kPairedUnconnectableDeviceAddress); - paired_unconnectable->SetString("name", kPairedUnconnectableDeviceName); - paired_unconnectable->SetString("pairingMethod", ""); - paired_unconnectable->SetString("pairingAuthToken", ""); - paired_unconnectable->SetString("pairingAction", ""); - paired_unconnectable->SetString("alias", kPairedUnconnectableDeviceName); - paired_unconnectable->SetInteger("classValue", - kPairedUnconnectableDeviceClass); - paired_unconnectable->SetBoolean("isTrusted", false); - paired_unconnectable->SetBoolean("discoverable", true); - paired_unconnectable->SetBoolean("paired", true); - paired_unconnectable->SetBoolean("incoming", false); - predefined_devices->Append(std::move(paired_unconnectable)); - - std::unique_ptr<base::DictionaryValue> connected_trusted_not_paired( - new base::DictionaryValue); - connected_trusted_not_paired->SetString("path", - kConnectedTrustedNotPairedDevicePath); - connected_trusted_not_paired->SetString( +base::Value FakeBluetoothDeviceClient::GetBluetoothDevicesAsDictionaries() + const { + base::Value::ListStorage predefined_devices; + + base::Value paired_device(base::Value::Type::DICTIONARY); + paired_device.SetStringKey("path", kPairedDevicePath); + paired_device.SetStringKey("address", kPairedDeviceAddress); + paired_device.SetStringKey("name", kPairedDeviceName); + paired_device.SetStringKey("alias", kPairedDeviceName); + paired_device.SetStringKey("pairingMethod", ""); + paired_device.SetStringKey("pairingAuthToken", ""); + paired_device.SetStringKey("pairingAction", ""); + paired_device.SetIntKey("classValue", kPairedDeviceClass); + paired_device.SetBoolKey("discoverable", true); + paired_device.SetBoolKey("isTrusted", true); + paired_device.SetBoolKey("paired", true); + paired_device.SetBoolKey("incoming", false); + predefined_devices.push_back(std::move(paired_device)); + + base::Value legacy_device(base::Value::Type::DICTIONARY); + legacy_device.SetStringKey("path", kLegacyAutopairPath); + legacy_device.SetStringKey("address", kLegacyAutopairAddress); + legacy_device.SetStringKey("name", kLegacyAutopairName); + legacy_device.SetStringKey("alias", kLegacyAutopairName); + legacy_device.SetStringKey("pairingMethod", ""); + legacy_device.SetStringKey("pairingAuthToken", ""); + legacy_device.SetStringKey("pairingAction", ""); + legacy_device.SetIntKey("classValue", kLegacyAutopairClass); + legacy_device.SetBoolKey("isTrusted", true); + legacy_device.SetBoolKey("discoverable", false); + legacy_device.SetBoolKey("paired", false); + legacy_device.SetBoolKey("incoming", false); + predefined_devices.push_back(std::move(legacy_device)); + + base::Value pin(base::Value::Type::DICTIONARY); + pin.SetStringKey("path", kDisplayPinCodePath); + pin.SetStringKey("address", kDisplayPinCodeAddress); + pin.SetStringKey("name", kDisplayPinCodeName); + pin.SetStringKey("alias", kDisplayPinCodeName); + pin.SetStringKey("pairingMethod", kPairingMethodPinCode); + pin.SetStringKey("pairingAuthToken", kTestPinCode); + pin.SetStringKey("pairingAction", kPairingActionDisplay); + pin.SetIntKey("classValue", kDisplayPinCodeClass); + pin.SetBoolKey("isTrusted", false); + pin.SetBoolKey("discoverable", false); + pin.SetBoolKey("paired", false); + pin.SetBoolKey("incoming", false); + predefined_devices.push_back(std::move(pin)); + + base::Value vanishing(base::Value::Type::DICTIONARY); + vanishing.SetStringKey("path", kVanishingDevicePath); + vanishing.SetStringKey("address", kVanishingDeviceAddress); + vanishing.SetStringKey("name", kVanishingDeviceName); + vanishing.SetStringKey("alias", kVanishingDeviceName); + vanishing.SetStringKey("pairingMethod", ""); + vanishing.SetStringKey("pairingAuthToken", ""); + vanishing.SetStringKey("pairingAction", ""); + vanishing.SetIntKey("classValue", kVanishingDeviceClass); + vanishing.SetBoolKey("isTrusted", false); + vanishing.SetBoolKey("discoverable", false); + vanishing.SetBoolKey("paired", false); + vanishing.SetBoolKey("incoming", false); + predefined_devices.push_back(std::move(vanishing)); + + base::Value connect_unpairable(base::Value::Type::DICTIONARY); + connect_unpairable.SetStringKey("path", kConnectUnpairablePath); + connect_unpairable.SetStringKey("address", kConnectUnpairableAddress); + connect_unpairable.SetStringKey("name", kConnectUnpairableName); + connect_unpairable.SetStringKey("pairingMethod", ""); + connect_unpairable.SetStringKey("pairingAuthToken", ""); + connect_unpairable.SetStringKey("pairingAction", ""); + connect_unpairable.SetStringKey("alias", kConnectUnpairableName); + connect_unpairable.SetIntKey("classValue", kConnectUnpairableClass); + connect_unpairable.SetBoolKey("isTrusted", false); + connect_unpairable.SetBoolKey("discoverable", false); + connect_unpairable.SetBoolKey("paired", false); + connect_unpairable.SetBoolKey("incoming", false); + predefined_devices.push_back(std::move(connect_unpairable)); + + base::Value passkey(base::Value::Type::DICTIONARY); + passkey.SetStringKey("path", kDisplayPasskeyPath); + passkey.SetStringKey("address", kDisplayPasskeyAddress); + passkey.SetStringKey("name", kDisplayPasskeyName); + passkey.SetStringKey("alias", kDisplayPasskeyName); + passkey.SetStringKey("pairingMethod", kPairingMethodPassKey); + passkey.SetIntKey("pairingAuthToken", kTestPassKey); + passkey.SetStringKey("pairingAction", kPairingActionDisplay); + passkey.SetIntKey("classValue", kDisplayPasskeyClass); + passkey.SetBoolKey("isTrusted", false); + passkey.SetBoolKey("discoverable", false); + passkey.SetBoolKey("paired", false); + passkey.SetBoolKey("incoming", false); + predefined_devices.push_back(std::move(passkey)); + + base::Value request_pin(base::Value::Type::DICTIONARY); + request_pin.SetStringKey("path", kRequestPinCodePath); + request_pin.SetStringKey("address", kRequestPinCodeAddress); + request_pin.SetStringKey("name", kRequestPinCodeName); + request_pin.SetStringKey("alias", kRequestPinCodeName); + request_pin.SetStringKey("pairingMethod", ""); + request_pin.SetStringKey("pairingAuthToken", ""); + request_pin.SetStringKey("pairingAction", kPairingActionRequest); + request_pin.SetIntKey("classValue", kRequestPinCodeClass); + request_pin.SetBoolKey("isTrusted", false); + request_pin.SetBoolKey("discoverable", false); + request_pin.SetBoolKey("paired", false); + request_pin.SetBoolKey("incoming", false); + predefined_devices.push_back(std::move(request_pin)); + + base::Value confirm(base::Value::Type::DICTIONARY); + confirm.SetStringKey("path", kConfirmPasskeyPath); + confirm.SetStringKey("address", kConfirmPasskeyAddress); + confirm.SetStringKey("name", kConfirmPasskeyName); + confirm.SetStringKey("alias", kConfirmPasskeyName); + confirm.SetStringKey("pairingMethod", ""); + confirm.SetIntKey("pairingAuthToken", kTestPassKey); + confirm.SetStringKey("pairingAction", kPairingActionConfirmation); + confirm.SetIntKey("classValue", kConfirmPasskeyClass); + confirm.SetBoolKey("isTrusted", false); + confirm.SetBoolKey("discoverable", false); + confirm.SetBoolKey("paired", false); + confirm.SetBoolKey("incoming", false); + predefined_devices.push_back(std::move(confirm)); + + base::Value request_passkey(base::Value::Type::DICTIONARY); + request_passkey.SetStringKey("path", kRequestPasskeyPath); + request_passkey.SetStringKey("address", kRequestPasskeyAddress); + request_passkey.SetStringKey("name", kRequestPasskeyName); + request_passkey.SetStringKey("alias", kRequestPasskeyName); + request_passkey.SetStringKey("pairingMethod", kPairingMethodPassKey); + request_passkey.SetStringKey("pairingAction", kPairingActionRequest); + request_passkey.SetIntKey("pairingAuthToken", kTestPassKey); + request_passkey.SetIntKey("classValue", kRequestPasskeyClass); + request_passkey.SetBoolKey("isTrusted", false); + request_passkey.SetBoolKey("discoverable", false); + request_passkey.SetBoolKey("paired", false); + request_passkey.SetBoolKey("incoming", false); + predefined_devices.push_back(std::move(request_passkey)); + + base::Value unconnectable(base::Value::Type::DICTIONARY); + unconnectable.SetStringKey("path", kUnconnectableDevicePath); + unconnectable.SetStringKey("address", kUnconnectableDeviceAddress); + unconnectable.SetStringKey("name", kUnconnectableDeviceName); + unconnectable.SetStringKey("alias", kUnconnectableDeviceName); + unconnectable.SetStringKey("pairingMethod", ""); + unconnectable.SetStringKey("pairingAuthToken", ""); + unconnectable.SetStringKey("pairingAction", ""); + unconnectable.SetIntKey("classValue", kUnconnectableDeviceClass); + unconnectable.SetBoolKey("isTrusted", true); + unconnectable.SetBoolKey("discoverable", false); + unconnectable.SetBoolKey("paired", false); + unconnectable.SetBoolKey("incoming", false); + predefined_devices.push_back(std::move(unconnectable)); + + base::Value unpairable(base::Value::Type::DICTIONARY); + unpairable.SetStringKey("path", kUnpairableDevicePath); + unpairable.SetStringKey("address", kUnpairableDeviceAddress); + unpairable.SetStringKey("name", kUnpairableDeviceName); + unpairable.SetStringKey("alias", kUnpairableDeviceName); + unpairable.SetStringKey("pairingMethod", ""); + unpairable.SetStringKey("pairingAuthToken", ""); + unpairable.SetStringKey("pairingAction", kPairingActionFail); + unpairable.SetIntKey("classValue", kUnpairableDeviceClass); + unpairable.SetBoolKey("isTrusted", false); + unpairable.SetBoolKey("discoverable", false); + unpairable.SetBoolKey("paired", false); + unpairable.SetBoolKey("incoming", false); + predefined_devices.push_back(std::move(unpairable)); + + base::Value just_works(base::Value::Type::DICTIONARY); + just_works.SetStringKey("path", kJustWorksPath); + just_works.SetStringKey("address", kJustWorksAddress); + just_works.SetStringKey("name", kJustWorksName); + just_works.SetStringKey("alias", kJustWorksName); + just_works.SetStringKey("pairingMethod", ""); + just_works.SetStringKey("pairingAuthToken", ""); + just_works.SetStringKey("pairingAction", ""); + just_works.SetIntKey("classValue", kJustWorksClass); + just_works.SetBoolKey("isTrusted", false); + just_works.SetBoolKey("discoverable", false); + just_works.SetBoolKey("paired", false); + just_works.SetBoolKey("incoming", false); + predefined_devices.push_back(std::move(just_works)); + + base::Value low_energy(base::Value::Type::DICTIONARY); + low_energy.SetStringKey("path", kLowEnergyPath); + low_energy.SetStringKey("address", kLowEnergyAddress); + low_energy.SetStringKey("name", kLowEnergyName); + low_energy.SetStringKey("alias", kLowEnergyName); + low_energy.SetStringKey("pairingMethod", ""); + low_energy.SetStringKey("pairingAuthToken", ""); + low_energy.SetStringKey("pairingAction", ""); + low_energy.SetIntKey("classValue", kLowEnergyClass); + low_energy.SetBoolKey("isTrusted", false); + low_energy.SetBoolKey("discoverable", false); + low_energy.SetBoolKey("paireed", false); + low_energy.SetBoolKey("incoming", false); + predefined_devices.push_back(std::move(low_energy)); + + base::Value paired_unconnectable(base::Value::Type::DICTIONARY); + paired_unconnectable.SetStringKey("path", kPairedUnconnectableDevicePath); + paired_unconnectable.SetStringKey("address", + kPairedUnconnectableDeviceAddress); + paired_unconnectable.SetStringKey("name", kPairedUnconnectableDeviceName); + paired_unconnectable.SetStringKey("pairingMethod", ""); + paired_unconnectable.SetStringKey("pairingAuthToken", ""); + paired_unconnectable.SetStringKey("pairingAction", ""); + paired_unconnectable.SetStringKey("alias", kPairedUnconnectableDeviceName); + paired_unconnectable.SetIntKey("classValue", kPairedUnconnectableDeviceClass); + paired_unconnectable.SetBoolKey("isTrusted", false); + paired_unconnectable.SetBoolKey("discoverable", true); + paired_unconnectable.SetBoolKey("paired", true); + paired_unconnectable.SetBoolKey("incoming", false); + predefined_devices.push_back(std::move(paired_unconnectable)); + + base::Value connected_trusted_not_paired(base::Value::Type::DICTIONARY); + connected_trusted_not_paired.SetStringKey( + "path", kConnectedTrustedNotPairedDevicePath); + connected_trusted_not_paired.SetStringKey( "address", kConnectedTrustedNotPairedDeviceAddress); - connected_trusted_not_paired->SetString("name", - kConnectedTrustedNotPairedDeviceName); - connected_trusted_not_paired->SetString("pairingMethod", ""); - connected_trusted_not_paired->SetString("pairingAuthToken", ""); - connected_trusted_not_paired->SetString("pairingAction", ""); - connected_trusted_not_paired->SetString("alias", - kConnectedTrustedNotPairedDeviceName); - connected_trusted_not_paired->SetInteger( - "classValue", kConnectedTrustedNotPairedDeviceClass); - connected_trusted_not_paired->SetBoolean("isTrusted", true); - connected_trusted_not_paired->SetBoolean("discoverable", true); - connected_trusted_not_paired->SetBoolean("paired", false); - connected_trusted_not_paired->SetBoolean("incoming", false); - predefined_devices->Append(std::move(connected_trusted_not_paired)); - - return predefined_devices; + connected_trusted_not_paired.SetStringKey( + "name", kConnectedTrustedNotPairedDeviceName); + connected_trusted_not_paired.SetStringKey("pairingMethod", ""); + connected_trusted_not_paired.SetStringKey("pairingAuthToken", ""); + connected_trusted_not_paired.SetStringKey("pairingAction", ""); + connected_trusted_not_paired.SetStringKey( + "alias", kConnectedTrustedNotPairedDeviceName); + connected_trusted_not_paired.SetIntKey("classValue", + kConnectedTrustedNotPairedDeviceClass); + connected_trusted_not_paired.SetBoolKey("isTrusted", true); + connected_trusted_not_paired.SetBoolKey("discoverable", true); + connected_trusted_not_paired.SetBoolKey("paired", false); + connected_trusted_not_paired.SetBoolKey("incoming", false); + predefined_devices.push_back(std::move(connected_trusted_not_paired)); + + return base::Value(std::move(predefined_devices)); } void FakeBluetoothDeviceClient::RemoveDevice( diff --git a/chromium/device/bluetooth/dbus/fake_bluetooth_device_client.h b/chromium/device/bluetooth/dbus/fake_bluetooth_device_client.h index 66db5320ea0..98a9676382a 100644 --- a/chromium/device/bluetooth/dbus/fake_bluetooth_device_client.h +++ b/chromium/device/bluetooth/dbus/fake_bluetooth_device_client.h @@ -140,7 +140,7 @@ class DEVICE_BLUETOOTH_EXPORT FakeBluetoothDeviceClient // Creates and returns a list of std::unique_ptr<base::DictionaryValue> // objects, which contain all the data from the constants for devices with // predefined behavior. - std::unique_ptr<base::ListValue> GetBluetoothDevicesAsDictionaries() const; + base::Value GetBluetoothDevicesAsDictionaries() const; SimulatedPairingOptions* GetPairingOptions( const dbus::ObjectPath& object_path); diff --git a/chromium/device/bluetooth/dbus/fake_bluetooth_gatt_characteristic_client.cc b/chromium/device/bluetooth/dbus/fake_bluetooth_gatt_characteristic_client.cc index ab1c641f56b..41e00e93a88 100644 --- a/chromium/device/bluetooth/dbus/fake_bluetooth_gatt_characteristic_client.cc +++ b/chromium/device/bluetooth/dbus/fake_bluetooth_gatt_characteristic_client.cc @@ -6,6 +6,7 @@ #include "base/bind.h" #include "base/location.h" +#include "base/logging.h" #include "base/rand_util.h" #include "base/single_thread_task_runner.h" #include "base/threading/thread_task_runner_handle.h" @@ -206,6 +207,7 @@ void FakeBluetoothGattCharacteristicClient::ReadValue( void FakeBluetoothGattCharacteristicClient::WriteValue( const dbus::ObjectPath& object_path, const std::vector<uint8_t>& value, + base::StringPiece type_option, base::OnceClosure callback, ErrorCallback error_callback) { if (!authenticated_) { diff --git a/chromium/device/bluetooth/dbus/fake_bluetooth_gatt_characteristic_client.h b/chromium/device/bluetooth/dbus/fake_bluetooth_gatt_characteristic_client.h index 217636c5389..bb17ba3f958 100644 --- a/chromium/device/bluetooth/dbus/fake_bluetooth_gatt_characteristic_client.h +++ b/chromium/device/bluetooth/dbus/fake_bluetooth_gatt_characteristic_client.h @@ -57,6 +57,7 @@ class DEVICE_BLUETOOTH_EXPORT FakeBluetoothGattCharacteristicClient ErrorCallback error_callback) override; void WriteValue(const dbus::ObjectPath& object_path, const std::vector<uint8_t>& value, + base::StringPiece type_option, base::OnceClosure callback, ErrorCallback error_callback) override; void PrepareWriteValue(const dbus::ObjectPath& object_path, diff --git a/chromium/device/bluetooth/dbus/fake_bluetooth_gatt_service_client.cc b/chromium/device/bluetooth/dbus/fake_bluetooth_gatt_service_client.cc index 5441071b4bd..1dfd30aa534 100644 --- a/chromium/device/bluetooth/dbus/fake_bluetooth_gatt_service_client.cc +++ b/chromium/device/bluetooth/dbus/fake_bluetooth_gatt_service_client.cc @@ -6,6 +6,7 @@ #include "base/bind.h" #include "base/location.h" +#include "base/logging.h" #include "base/single_thread_task_runner.h" #include "base/threading/thread_task_runner_handle.h" #include "base/time/time.h" diff --git a/chromium/device/bluetooth/dbus/fake_bluetooth_le_advertisement_service_provider.cc b/chromium/device/bluetooth/dbus/fake_bluetooth_le_advertisement_service_provider.cc index 52d3239f925..a4a3ba97129 100644 --- a/chromium/device/bluetooth/dbus/fake_bluetooth_le_advertisement_service_provider.cc +++ b/chromium/device/bluetooth/dbus/fake_bluetooth_le_advertisement_service_provider.cc @@ -4,6 +4,7 @@ #include "device/bluetooth/dbus/fake_bluetooth_le_advertisement_service_provider.h" +#include "base/logging.h" #include "device/bluetooth/dbus/bluez_dbus_manager.h" #include "device/bluetooth/dbus/fake_bluetooth_le_advertising_manager_client.h" diff --git a/chromium/device/bluetooth/dbus/fake_bluetooth_media_client.cc b/chromium/device/bluetooth/dbus/fake_bluetooth_media_client.cc index 7e67ac7a86e..fd693399dd6 100644 --- a/chromium/device/bluetooth/dbus/fake_bluetooth_media_client.cc +++ b/chromium/device/bluetooth/dbus/fake_bluetooth_media_client.cc @@ -6,6 +6,7 @@ #include <string> +#include "base/logging.h" #include "base/stl_util.h" #include "device/bluetooth/dbus/bluez_dbus_manager.h" #include "device/bluetooth/dbus/fake_bluetooth_adapter_client.h" diff --git a/chromium/device/bluetooth/dbus/fake_bluetooth_media_endpoint_service_provider.cc b/chromium/device/bluetooth/dbus/fake_bluetooth_media_endpoint_service_provider.cc index faf04dc0363..4a0b7c33695 100644 --- a/chromium/device/bluetooth/dbus/fake_bluetooth_media_endpoint_service_provider.cc +++ b/chromium/device/bluetooth/dbus/fake_bluetooth_media_endpoint_service_provider.cc @@ -4,6 +4,7 @@ #include "device/bluetooth/dbus/fake_bluetooth_media_endpoint_service_provider.h" +#include "base/logging.h" #include "device/bluetooth/dbus/bluez_dbus_manager.h" #include "device/bluetooth/dbus/fake_bluetooth_media_client.h" #include "device/bluetooth/dbus/fake_bluetooth_media_transport_client.h" diff --git a/chromium/device/bluetooth/dbus/fake_bluetooth_media_endpoint_service_provider.h b/chromium/device/bluetooth/dbus/fake_bluetooth_media_endpoint_service_provider.h index f907e4da732..43b72422101 100644 --- a/chromium/device/bluetooth/dbus/fake_bluetooth_media_endpoint_service_provider.h +++ b/chromium/device/bluetooth/dbus/fake_bluetooth_media_endpoint_service_provider.h @@ -9,7 +9,6 @@ #include <vector> -#include "base/logging.h" #include "base/macros.h" #include "dbus/object_path.h" #include "device/bluetooth/bluetooth_export.h" diff --git a/chromium/device/bluetooth/dbus/fake_bluetooth_media_transport_client.cc b/chromium/device/bluetooth/dbus/fake_bluetooth_media_transport_client.cc index d7b267d8cc7..7d4c63a468e 100644 --- a/chromium/device/bluetooth/dbus/fake_bluetooth_media_transport_client.cc +++ b/chromium/device/bluetooth/dbus/fake_bluetooth_media_transport_client.cc @@ -13,6 +13,7 @@ #include "base/bind.h" #include "base/file_descriptor_posix.h" +#include "base/logging.h" #include "base/memory/ptr_util.h" #include "base/stl_util.h" #include "device/bluetooth/dbus/bluetooth_media_client.h" diff --git a/chromium/device/bluetooth/dbus/fake_bluetooth_profile_service_provider.cc b/chromium/device/bluetooth/dbus/fake_bluetooth_profile_service_provider.cc index f684ecb112a..508e833fb3e 100644 --- a/chromium/device/bluetooth/dbus/fake_bluetooth_profile_service_provider.cc +++ b/chromium/device/bluetooth/dbus/fake_bluetooth_profile_service_provider.cc @@ -7,6 +7,7 @@ #include <memory> #include <utility> +#include "base/logging.h" #include "device/bluetooth/dbus/bluez_dbus_manager.h" #include "device/bluetooth/dbus/fake_bluetooth_profile_manager_client.h" diff --git a/chromium/device/bluetooth/device.cc b/chromium/device/bluetooth/device.cc index d155f38ee65..fd3df58d5de 100644 --- a/chromium/device/bluetooth/device.cc +++ b/chromium/device/bluetooth/device.cc @@ -180,7 +180,7 @@ void Device::WriteValueForCharacteristic( } auto copyable_callback = base::AdaptCallbackForRepeating(std::move(callback)); - characteristic->WriteRemoteCharacteristic( + characteristic->DeprecatedWriteRemoteCharacteristic( value, base::BindOnce(&Device::OnWriteRemoteCharacteristic, weak_ptr_factory_.GetWeakPtr(), copyable_callback), diff --git a/chromium/device/bluetooth/public/mojom/BUILD.gn b/chromium/device/bluetooth/public/mojom/BUILD.gn index beed96c8d44..a8229236120 100644 --- a/chromium/device/bluetooth/public/mojom/BUILD.gn +++ b/chromium/device/bluetooth/public/mojom/BUILD.gn @@ -58,7 +58,10 @@ mojom("deprecated_experimental_interfaces") { # Implementation of the mojom interfaces: "//device/bluetooth:deprecated_experimental_mojo", - # Single approved client of the interfaces: + # Bluetooth internals page "//chrome/browser/ui/webui/bluetooth_internals:*", + + # Nearby Sharing feature + "//chrome/services/sharing/public/mojom:*", ] } diff --git a/chromium/device/bluetooth/public/mojom/test/fake_bluetooth.mojom b/chromium/device/bluetooth/public/mojom/test/fake_bluetooth.mojom index 710be64b77d..cd133119570 100644 --- a/chromium/device/bluetooth/public/mojom/test/fake_bluetooth.mojom +++ b/chromium/device/bluetooth/public/mojom/test/fake_bluetooth.mojom @@ -38,6 +38,14 @@ enum CentralState { POWERED_OFF, }; +// GATT characteristic write type. +enum WriteType { + kNone, + kWriteDefaultDeprecated, + kWriteWithResponse, + kWriteWithoutResponse, +}; + // Stores the external appearance description of the device. struct Appearance { bool has_value; @@ -323,7 +331,8 @@ interface FakeCentral { GetLastWrittenCharacteristicValue( string characteristic_id, string service_id, - string peripheral_address) => (bool success, array<uint8>? value); + string peripheral_address) => (bool success, array<uint8>? value, + WriteType write_type); // Sets the next read response for descriptor with |descriptor_id| in // |characteristics_id| in |service_id| and in |peripheral_address| to |code| |