From 81cb41ca2ef3aac1b90cc343c6fba50afba35763 Mon Sep 17 00:00:00 2001 From: Gordon Seto Date: Fri, 8 Apr 2022 23:41:12 +0000 Subject: [PATCH] [CrOS Bluetooth] Add automatic pairing to BluetoothHidDetectorImpl. Update BluetoothHidDetectorImpl to queue discovered devices when Bluetooth HID detection starts and attempt to pair with them consecutively. Adding BluetoothHidDetectorDelegate and notifying the delegate when the Bluetooth HID detection status changes will be added in a follow-up CL. Bug: 1299099 Test: BluetoothHidDetectorImplTest Change-Id: I0cff676e6278ab9b10a3b0376d4e79432b1ea67a Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3576779 Reviewed-by: Chad Duffin Commit-Queue: Gordon Seto Cr-Commit-Position: refs/heads/main@{#990659} --- .../hid_detection/bluetooth_hid_detector.h | 8 +- .../bluetooth_hid_detector_impl.cc | 146 ++++++++++- .../bluetooth_hid_detector_impl.h | 56 ++++- .../bluetooth_hid_detector_impl_unittest.cc | 236 +++++++++++++++++- ...discovery_session_manager_impl_unittest.cc | 4 - .../fake_device_pairing_handler.cc | 2 + .../fake_discovery_session_manager.cc | 9 +- .../fake_discovery_session_manager.h | 7 + 8 files changed, 445 insertions(+), 23 deletions(-) diff --git a/ash/components/hid_detection/bluetooth_hid_detector.h b/ash/components/hid_detection/bluetooth_hid_detector.h index 8ebd0d20e5d5ee..7a2368c1662f0e 100644 --- a/ash/components/hid_detection/bluetooth_hid_detector.h +++ b/ash/components/hid_detection/bluetooth_hid_detector.h @@ -13,9 +13,15 @@ namespace hid_detection { // currently paired with. class BluetoothHidDetector { public: + struct InputDevicesStatus { + bool pointer_is_missing; + bool keyboard_is_missing; + }; + virtual ~BluetoothHidDetector(); - virtual void StartBluetoothHidDetection() = 0; + virtual void StartBluetoothHidDetection( + InputDevicesStatus input_devices_status) = 0; virtual void StopBluetoothHidDetection() = 0; protected: diff --git a/ash/components/hid_detection/bluetooth_hid_detector_impl.cc b/ash/components/hid_detection/bluetooth_hid_detector_impl.cc index 0ed65397ca5d37..281e1d2494dedc 100644 --- a/ash/components/hid_detection/bluetooth_hid_detector_impl.cc +++ b/ash/components/hid_detection/bluetooth_hid_detector_impl.cc @@ -6,10 +6,14 @@ #include "ash/public/cpp/bluetooth_config_service.h" #include "components/device_event_log/device_event_log.h" -using chromeos::bluetooth_config::mojom::BluetoothSystemState; - namespace ash { namespace hid_detection { +namespace { +using chromeos::bluetooth_config::mojom::BluetoothDevicePropertiesPtr; +using chromeos::bluetooth_config::mojom::BluetoothSystemState; +using chromeos::bluetooth_config::mojom::DeviceType; +using chromeos::bluetooth_config::mojom::KeyEnteredHandler; +} // namespace BluetoothHidDetectorImpl::BluetoothHidDetectorImpl() = default; @@ -18,9 +22,15 @@ BluetoothHidDetectorImpl::~BluetoothHidDetectorImpl() { << "BluetoothHidDetectorImpl is destroyed."; } -void BluetoothHidDetectorImpl::StartBluetoothHidDetection() { +void BluetoothHidDetectorImpl::StartBluetoothHidDetection( + InputDevicesStatus input_devices_status) { + DCHECK(input_devices_status.pointer_is_missing || + input_devices_status.keyboard_is_missing) + << "StartBluetoothHidDetection() called when neither pointer or keyboard " + << "is missing"; DCHECK_EQ(kNotStarted, state_); HID_LOG(EVENT) << "Starting Bluetooth HID detection"; + input_devices_status_ = input_devices_status; state_ = kStarting; GetBluetoothConfigService( cros_bluetooth_config_remote_.BindNewPipeAndPassReceiver()); @@ -36,7 +46,7 @@ void BluetoothHidDetectorImpl::StopBluetoothHidDetection() { cros_bluetooth_config_remote_->SetBluetoothHidDetectionActive(false); cros_bluetooth_config_remote_.reset(); system_properties_observer_receiver_.reset(); - bluetooth_discovery_delegate_receiver_.reset(); + ResetDiscoveryState(); } void BluetoothHidDetectorImpl::OnPropertiesUpdated( @@ -80,7 +90,6 @@ void BluetoothHidDetectorImpl::OnPropertiesUpdated( HID_LOG(EVENT) << "Bluetooth adapter has stopped being enabled while " << "Bluetooth HID detection is in progress"; state_ = kStoppedExternally; - bluetooth_discovery_delegate_receiver_.reset(); } return; case kStoppedExternally: @@ -98,15 +107,132 @@ void BluetoothHidDetectorImpl::OnPropertiesUpdated( void BluetoothHidDetectorImpl::OnBluetoothDiscoveryStarted( mojo::PendingRemote handler) { - // TODO(crbug.com/1299099): Implement pairing. + HID_LOG(EVENT) << "Bluetooth discovery started."; + DCHECK(!device_pairing_handler_remote_); + device_pairing_handler_remote_.Bind(std::move(handler)); } -void BluetoothHidDetectorImpl::OnBluetoothDiscoveryStopped() {} +void BluetoothHidDetectorImpl::OnBluetoothDiscoveryStopped() { + HID_LOG(EVENT) << "Bluetooth discovery stopped."; + ResetDiscoveryState(); +} void BluetoothHidDetectorImpl::OnDiscoveredDevicesListChanged( - std::vector - discovered_devices) { - // TODO(crbug.com/1299099): Implement pairing. + std::vector discovered_devices) { + for (const auto& discovered_device : discovered_devices) { + if (!ShouldAttemptToPairWithDevice(discovered_device)) + continue; + if (queued_device_ids_.contains(discovered_device->id)) + continue; + + queued_device_ids_.insert(discovered_device->id); + queue_->emplace(discovered_device.Clone()); + HID_LOG(EVENT) << "Queuing device: " << discovered_device->id << ". [" + << queue_->size() << "] devices now in queue."; + } + ProcessQueue(); +} + +void BluetoothHidDetectorImpl::RequestPinCode(RequestPinCodeCallback callback) { + // TODO(crbug/1299099): Implement. +} + +void BluetoothHidDetectorImpl::RequestPasskey(RequestPasskeyCallback callback) { + // TODO(crbug/1299099): Implement. +} + +void BluetoothHidDetectorImpl::DisplayPinCode( + const std::string& pin_code, + mojo::PendingReceiver handler) { + // TODO(crbug/1299099): Implement. +} + +void BluetoothHidDetectorImpl::DisplayPasskey( + const std::string& passkey, + mojo::PendingReceiver handler) { + // TODO(crbug/1299099): Implement. +} + +void BluetoothHidDetectorImpl::ConfirmPasskey(const std::string& passkey, + ConfirmPasskeyCallback callback) { + // TODO(crbug/1299099): Implement. +} + +void BluetoothHidDetectorImpl::AuthorizePairing( + AuthorizePairingCallback callback) { + // TODO(crbug/1299099): Implement. +} + +bool BluetoothHidDetectorImpl::ShouldAttemptToPairWithDevice( + const BluetoothDevicePropertiesPtr& device) { + switch (device->device_type) { + case DeviceType::kMouse: + [[fallthrough]]; + case DeviceType::kTablet: + return input_devices_status_.pointer_is_missing; + case DeviceType::kKeyboard: + return input_devices_status_.keyboard_is_missing; + case DeviceType::kKeyboardMouseCombo: + return input_devices_status_.pointer_is_missing || + input_devices_status_.keyboard_is_missing; + default: + return false; + } +} + +void BluetoothHidDetectorImpl::ProcessQueue() { + if (current_pairing_device_) + return; + + if (queue_->empty()) { + HID_LOG(DEBUG) << "No devices queued"; + return; + } + + current_pairing_device_ = std::move(queue_->front()); + queue_->pop(); + HID_LOG(EVENT) << "Popped device with id: " + << current_pairing_device_.value()->id + << " from front of queue. [" << queue_->size() + << "] devices now in queue."; + + // TODO(crbug.com/1299099): Check if device type is still missing and return + // early if not. + + // TODO(crbug.com/1299099): Notify delegate of change in status. + HID_LOG(EVENT) << "Pairing with device with id: " + << current_pairing_device_.value()->id; + device_pairing_handler_remote_->PairDevice( + current_pairing_device_.value()->id, + device_pairing_delegate_receiver_.BindNewPipeAndPassRemote(), + base::BindOnce(&BluetoothHidDetectorImpl::OnPairDevice, + weak_ptr_factory_.GetWeakPtr())); +} + +void BluetoothHidDetectorImpl::OnPairDevice( + chromeos::bluetooth_config::mojom::PairingResult pairing_result) { + // TODO(crbug.com/1299099): Notify delegate of change in status. + HID_LOG(EVENT) << "Finished pairing with " + << current_pairing_device_.value()->id + << ", result: " << pairing_result << ", [" << queue_->size() + << "] devices still in queue."; + queued_device_ids_.erase(current_pairing_device_.value()->id); + current_pairing_device_.reset(); + device_pairing_delegate_receiver_.reset(); + ProcessQueue(); +} + +void BluetoothHidDetectorImpl::ResetDiscoveryState() { + // Reset Mojo-related properties. + bluetooth_discovery_delegate_receiver_.reset(); + device_pairing_handler_remote_.reset(); + device_pairing_delegate_receiver_.reset(); + + // Reset queue-related properties. + current_pairing_device_.reset(); + queue_ = std::make_unique>(); + queued_device_ids_.clear(); } } // namespace hid_detection diff --git a/ash/components/hid_detection/bluetooth_hid_detector_impl.h b/ash/components/hid_detection/bluetooth_hid_detector_impl.h index df359ddfdbcd89..50b1fd8818fe50 100644 --- a/ash/components/hid_detection/bluetooth_hid_detector_impl.h +++ b/ash/components/hid_detection/bluetooth_hid_detector_impl.h @@ -6,6 +6,9 @@ #define ASH_COMPONENTS_HID_DETECTION_BLUETOOTH_HID_DETECTOR_IMPL_H_ #include "ash/components/hid_detection/bluetooth_hid_detector.h" +#include "base/containers/flat_set.h" +#include "base/containers/queue.h" +#include "base/memory/weak_ptr.h" #include "chromeos/services/bluetooth_config/public/mojom/cros_bluetooth_config.mojom.h" #include "mojo/public/cpp/bindings/receiver.h" #include "mojo/public/cpp/bindings/remote.h" @@ -17,13 +20,15 @@ namespace hid_detection { class BluetoothHidDetectorImpl : public BluetoothHidDetector, public chromeos::bluetooth_config::mojom::SystemPropertiesObserver, - public chromeos::bluetooth_config::mojom::BluetoothDiscoveryDelegate { + public chromeos::bluetooth_config::mojom::BluetoothDiscoveryDelegate, + public chromeos::bluetooth_config::mojom::DevicePairingDelegate { public: BluetoothHidDetectorImpl(); ~BluetoothHidDetectorImpl() override; // BluetoothHidDetector: - void StartBluetoothHidDetection() override; + void StartBluetoothHidDetection( + InputDevicesStatus input_devices_status) override; void StopBluetoothHidDetection() override; private: @@ -63,6 +68,47 @@ class BluetoothHidDetectorImpl chromeos::bluetooth_config::mojom::BluetoothDevicePropertiesPtr> discovered_devices) override; + // mojom::DevicePairingDelegate: + void RequestPinCode(RequestPinCodeCallback callback) override; + void RequestPasskey(RequestPasskeyCallback callback) override; + void DisplayPinCode(const std::string& pin_code, + mojo::PendingReceiver< + chromeos::bluetooth_config::mojom::KeyEnteredHandler> + handler) override; + void DisplayPasskey(const std::string& passkey, + mojo::PendingReceiver< + chromeos::bluetooth_config::mojom::KeyEnteredHandler> + handler) override; + void ConfirmPasskey(const std::string& passkey, + ConfirmPasskeyCallback callback) override; + void AuthorizePairing(AuthorizePairingCallback callback) override; + + bool ShouldAttemptToPairWithDevice( + const chromeos::bluetooth_config::mojom::BluetoothDevicePropertiesPtr& + device); + + void ProcessQueue(); + void OnPairDevice( + chromeos::bluetooth_config::mojom::PairingResult pairing_result); + + // Resets properties related to discovery, pairing handlers and queueing. + void ResetDiscoveryState(); + + // Map that contains the ids of the devices in |queue_|. + base::flat_set queued_device_ids_; + + // The queue of devices that will be attempted to be paired with. + std::unique_ptr> + queue_ = std::make_unique>(); + + // The device currently being paired with. + absl::optional< + chromeos::bluetooth_config::mojom::BluetoothDevicePropertiesPtr> + current_pairing_device_; + + InputDevicesStatus input_devices_status_; State state_ = kNotStarted; mojo::Remote @@ -71,6 +117,12 @@ class BluetoothHidDetectorImpl system_properties_observer_receiver_{this}; mojo::Receiver bluetooth_discovery_delegate_receiver_{this}; + mojo::Remote + device_pairing_handler_remote_; + mojo::Receiver + device_pairing_delegate_receiver_{this}; + + base::WeakPtrFactory weak_ptr_factory_{this}; }; } // namespace hid_detection diff --git a/ash/components/hid_detection/bluetooth_hid_detector_impl_unittest.cc b/ash/components/hid_detection/bluetooth_hid_detector_impl_unittest.cc index f3947c85e203d3..2cd9feede93f4a 100644 --- a/ash/components/hid_detection/bluetooth_hid_detector_impl_unittest.cc +++ b/ash/components/hid_detection/bluetooth_hid_detector_impl_unittest.cc @@ -8,13 +8,18 @@ #include "chromeos/services/bluetooth_config/fake_adapter_state_controller.h" #include "chromeos/services/bluetooth_config/fake_bluetooth_power_controller.h" #include "chromeos/services/bluetooth_config/fake_device_cache.h" +#include "chromeos/services/bluetooth_config/fake_device_pairing_handler.h" +#include "chromeos/services/bluetooth_config/fake_discovered_devices_provider.h" #include "chromeos/services/bluetooth_config/fake_discovery_session_manager.h" #include "chromeos/services/bluetooth_config/public/mojom/cros_bluetooth_config.mojom.h" #include "chromeos/services/bluetooth_config/scoped_bluetooth_config_test_helper.h" #include "testing/gtest/include/gtest/gtest.h" +using chromeos::bluetooth_config::FakeDevicePairingHandler; using chromeos::bluetooth_config::mojom::BluetoothDeviceProperties; +using chromeos::bluetooth_config::mojom::BluetoothDevicePropertiesPtr; using chromeos::bluetooth_config::mojom::BluetoothSystemState; +using chromeos::bluetooth_config::mojom::DeviceType; using chromeos::bluetooth_config::mojom::PairedBluetoothDeviceProperties; using chromeos::bluetooth_config::mojom::PairedBluetoothDevicePropertiesPtr; @@ -39,8 +44,11 @@ class BluetoothHidDetectorImplTest : public testing::Test { StopBluetoothHidDetection(); } - void StartBluetoothHidDetection() { - bluetooth_hid_detector_.StartBluetoothHidDetection(); + void StartBluetoothHidDetection(bool pointer_is_missing = true, + bool keyboard_is_missing = true) { + bluetooth_hid_detector_.StartBluetoothHidDetection( + {.pointer_is_missing = pointer_is_missing, + .keyboard_is_missing = keyboard_is_missing}); base::RunLoop().RunUntilIdle(); } @@ -87,9 +95,53 @@ class BluetoothHidDetectorImplTest : public testing::Test { base::RunLoop().RunUntilIdle(); } + void AddUnpairedDevice(std::string* id_out, DeviceType device_type) { + // We use the number of devices created in this test as the id. + *id_out = base::NumberToString(num_devices_created_); + ++num_devices_created_; + + auto device = BluetoothDeviceProperties::New(); + device->id = *id_out; + device->device_type = device_type; + unpaired_devices_.push_back(device.Clone()); + + UpdateDiscoveredDevicesProviderDevices(); + base::RunLoop().RunUntilIdle(); + } + + void RemoveUnpairedDevice(const std::string& device_id) { + unpaired_devices_.erase( + std::remove_if(unpaired_devices_.begin(), unpaired_devices_.end(), + [device_id](BluetoothDevicePropertiesPtr const& device) { + return device->id == device_id; + }), + unpaired_devices_.end()); + + UpdateDiscoveredDevicesProviderDevices(); + base::RunLoop().RunUntilIdle(); + } + + std::vector GetDevicePairingHandlers() { + return scoped_bluetooth_config_test_helper_ + .fake_discovery_session_manager() + ->device_pairing_handlers(); + } + private: + void UpdateDiscoveredDevicesProviderDevices() { + std::vector unpaired_devices; + for (auto& device : unpaired_devices_) { + unpaired_devices.push_back(device.Clone()); + } + scoped_bluetooth_config_test_helper_.fake_discovered_devices_provider() + ->SetDiscoveredDevices(std::move(unpaired_devices)); + } + base::test::TaskEnvironment task_environment_; + std::vector unpaired_devices_; + size_t num_devices_created_ = 0u; + chromeos::bluetooth_config::ScopedBluetoothConfigTestHelper scoped_bluetooth_config_test_helper_; @@ -220,5 +272,185 @@ TEST_F(BluetoothHidDetectorImplTest, EXPECT_TRUE(IsDiscoverySessionActive()); } +TEST_F(BluetoothHidDetectorImplTest, AddDevices_TypeNotHid) { + std::string device_id1; + AddUnpairedDevice(&device_id1, DeviceType::kHeadset); + + std::string device_id2; + AddUnpairedDevice(&device_id2, DeviceType::kKeyboard); + + // Begin HID detection. |device_id1| should not be attempted to be paired + // with. + StartBluetoothHidDetection(); + EXPECT_TRUE(IsDiscoverySessionActive()); + EXPECT_EQ(1u, GetDevicePairingHandlers().size()); + EXPECT_EQ(device_id2, + GetDevicePairingHandlers()[0]->current_pairing_device_id()); +} + +TEST_F(BluetoothHidDetectorImplTest, AddDevices_TypeNotMissing) { + std::string device_id1; + AddUnpairedDevice(&device_id1, DeviceType::kMouse); + + std::string device_id2; + AddUnpairedDevice(&device_id2, DeviceType::kKeyboard); + + // Begin HID detection. |device_id1| should not be attempted to be paired + // with. + StartBluetoothHidDetection(/*is_pointer_missing=*/false); + EXPECT_TRUE(IsDiscoverySessionActive()); + EXPECT_EQ(1u, GetDevicePairingHandlers().size()); + EXPECT_EQ(device_id2, + GetDevicePairingHandlers()[0]->current_pairing_device_id()); +} + +TEST_F(BluetoothHidDetectorImplTest, AddDevices_BeforeStartingDetection) { + std::string device_id1; + AddUnpairedDevice(&device_id1, DeviceType::kMouse); + + std::string device_id2; + AddUnpairedDevice(&device_id2, DeviceType::kKeyboardMouseCombo); + + // Begin HID detection. |device_id1| should be attempted to be paired with. + StartBluetoothHidDetection(); + EXPECT_TRUE(IsDiscoverySessionActive()); + EXPECT_EQ(1u, GetDevicePairingHandlers().size()); + EXPECT_EQ(device_id1, + GetDevicePairingHandlers()[0]->current_pairing_device_id()); + + // Mock |device_id1| being paired. |device_id2| should be attempted to be + // paired with. + RemoveUnpairedDevice(device_id1); + GetDevicePairingHandlers()[0]->SimulatePairDeviceFinished( + /*failure_reason=*/absl::nullopt); + EXPECT_EQ(device_id2, + GetDevicePairingHandlers()[0]->current_pairing_device_id()); + + // Mock |device_id2| being paired. + RemoveUnpairedDevice(device_id2); + GetDevicePairingHandlers()[0]->SimulatePairDeviceFinished( + /*failure_reason=*/absl::nullopt); + EXPECT_TRUE( + GetDevicePairingHandlers()[0]->current_pairing_device_id().empty()); +} + +TEST_F(BluetoothHidDetectorImplTest, + AddDevices_SeriallyAfterStartingDetection) { + StartBluetoothHidDetection(); + EXPECT_TRUE(IsDiscoverySessionActive()); + EXPECT_EQ(1u, GetDevicePairingHandlers().size()); + EXPECT_TRUE( + GetDevicePairingHandlers()[0]->current_pairing_device_id().empty()); + + std::string device_id1; + AddUnpairedDevice(&device_id1, DeviceType::kTablet); + EXPECT_EQ(device_id1, + GetDevicePairingHandlers()[0]->current_pairing_device_id()); + + // Mock |device_id1| being paired. + RemoveUnpairedDevice(device_id1); + GetDevicePairingHandlers()[0]->SimulatePairDeviceFinished( + /*failure_reason=*/absl::nullopt); + EXPECT_TRUE( + GetDevicePairingHandlers()[0]->current_pairing_device_id().empty()); + + std::string device_id2; + AddUnpairedDevice(&device_id2, DeviceType::kKeyboard); + EXPECT_EQ(device_id2, + GetDevicePairingHandlers()[0]->current_pairing_device_id()); + + // Mock |device_id2| being paired. + RemoveUnpairedDevice(device_id2); + GetDevicePairingHandlers()[0]->SimulatePairDeviceFinished( + /*failure_reason=*/absl::nullopt); + EXPECT_TRUE( + GetDevicePairingHandlers()[0]->current_pairing_device_id().empty()); +} + +TEST_F(BluetoothHidDetectorImplTest, AddDevices_BatchAfterStartingDetection) { + StartBluetoothHidDetection(); + EXPECT_TRUE(IsDiscoverySessionActive()); + EXPECT_EQ(1u, GetDevicePairingHandlers().size()); + EXPECT_TRUE( + GetDevicePairingHandlers()[0]->current_pairing_device_id().empty()); + + std::string device_id1; + AddUnpairedDevice(&device_id1, DeviceType::kMouse); + EXPECT_EQ(device_id1, + GetDevicePairingHandlers()[0]->current_pairing_device_id()); + + std::string device_id2; + AddUnpairedDevice(&device_id2, DeviceType::kKeyboard); + + // Mock |device_id1| being paired. + RemoveUnpairedDevice(device_id1); + GetDevicePairingHandlers()[0]->SimulatePairDeviceFinished( + /*failure_reason=*/absl::nullopt); + EXPECT_EQ(device_id2, + GetDevicePairingHandlers()[0]->current_pairing_device_id()); + + // Mock |device_id2| being paired. + RemoveUnpairedDevice(device_id2); + GetDevicePairingHandlers()[0]->SimulatePairDeviceFinished( + /*failure_reason=*/absl::nullopt); + EXPECT_TRUE( + GetDevicePairingHandlers()[0]->current_pairing_device_id().empty()); +} + +TEST_F(BluetoothHidDetectorImplTest, AdapterDisablesDuringPairing) { + std::string device_id1; + AddUnpairedDevice(&device_id1, DeviceType::kMouse); + + std::string device_id2; + AddUnpairedDevice(&device_id2, DeviceType::kKeyboard); + + // Begin HID detection. |device_id1| should be attempted to be paired with. + StartBluetoothHidDetection(); + EXPECT_TRUE(IsDiscoverySessionActive()); + EXPECT_EQ(1u, GetDevicePairingHandlers().size()); + EXPECT_EQ(device_id1, + GetDevicePairingHandlers()[0]->current_pairing_device_id()); + + // Mock the adapter disabling. + SetAdapterState(BluetoothSystemState::kDisabled); + EXPECT_FALSE(IsDiscoverySessionActive()); + + // Mock the adapter re-enabling Bluetooth. This should cause + // BluetoothHidDetector to start discovery again. The first device should be + // attempted to be paired with again. + SetAdapterState(BluetoothSystemState::kEnabled); + EXPECT_TRUE(IsDiscoverySessionActive()); + EXPECT_EQ(2u, GetDevicePairingHandlers().size()); + EXPECT_EQ(device_id1, + GetDevicePairingHandlers()[1]->current_pairing_device_id()); +} + +TEST_F(BluetoothHidDetectorImplTest, DetectionStopsStartsDuringPairing) { + std::string device_id1; + AddUnpairedDevice(&device_id1, DeviceType::kMouse); + + std::string device_id2; + AddUnpairedDevice(&device_id2, DeviceType::kKeyboard); + + // Begin HID detection. |device_id1| should be attempted to be paired with. + StartBluetoothHidDetection(); + EXPECT_TRUE(IsDiscoverySessionActive()); + EXPECT_EQ(1u, GetDevicePairingHandlers().size()); + EXPECT_EQ(device_id1, + GetDevicePairingHandlers()[0]->current_pairing_device_id()); + + // Stop detection. + StopBluetoothHidDetection(); + EXPECT_FALSE(IsDiscoverySessionActive()); + + // Start detection again. The first device should be attempted to be paired + // with again. + StartBluetoothHidDetection(); + EXPECT_TRUE(IsDiscoverySessionActive()); + EXPECT_EQ(2u, GetDevicePairingHandlers().size()); + EXPECT_EQ(device_id1, + GetDevicePairingHandlers()[1]->current_pairing_device_id()); +} + } // namespace hid_detection } // namespace ash diff --git a/chromeos/services/bluetooth_config/discovery_session_manager_impl_unittest.cc b/chromeos/services/bluetooth_config/discovery_session_manager_impl_unittest.cc index c506dbba6acb1d..9e5fbe6778fed6 100644 --- a/chromeos/services/bluetooth_config/discovery_session_manager_impl_unittest.cc +++ b/chromeos/services/bluetooth_config/discovery_session_manager_impl_unittest.cc @@ -432,7 +432,6 @@ TEST_F(DiscoverySessionManagerImplTest, MultipleClientsAttemptPairing) { // Finish the pairing with failure. device_pairing_handler1->SimulatePairDeviceFinished( device::ConnectionFailureReason::kFailed); - base::RunLoop().RunUntilIdle(); EXPECT_EQ(result, mojom::PairingResult::kNonAuthFailure); EXPECT_TRUE(delegate1->IsMojoPipeConnected()); EXPECT_TRUE(delegate1->pairing_handler().is_connected()); @@ -455,7 +454,6 @@ TEST_F(DiscoverySessionManagerImplTest, MultipleClientsAttemptPairing) { // Finish the pairing with success. device_pairing_handler1->SimulatePairDeviceFinished( /*failure_reason=*/absl::nullopt); - base::RunLoop().RunUntilIdle(); EXPECT_EQ(result, mojom::PairingResult::kSuccess); EXPECT_TRUE(delegate1->IsMojoPipeConnected()); EXPECT_TRUE(delegate1->pairing_handler().is_connected()); @@ -488,7 +486,6 @@ TEST_F(DiscoverySessionManagerImplTest, MultipleClientsAttemptPairing) { // Finish the pairing with success. device_pairing_handler2->SimulatePairDeviceFinished( /*failure_reason=*/absl::nullopt); - base::RunLoop().RunUntilIdle(); EXPECT_EQ(result, mojom::PairingResult::kSuccess); EXPECT_TRUE(delegate2->IsMojoPipeConnected()); EXPECT_TRUE(delegate2->pairing_handler().is_connected()); @@ -622,7 +619,6 @@ TEST_F(DiscoverySessionManagerImplTest, device_pairing_handler->SimulatePairDeviceFinished( /*failure_reason=*/absl::nullopt); - base::RunLoop().RunUntilIdle(); EXPECT_EQ(result, mojom::PairingResult::kSuccess); // |delegate| will still be connected. diff --git a/chromeos/services/bluetooth_config/fake_device_pairing_handler.cc b/chromeos/services/bluetooth_config/fake_device_pairing_handler.cc index fd2d8eb621def0..1b59bbd84180ac 100644 --- a/chromeos/services/bluetooth_config/fake_device_pairing_handler.cc +++ b/chromeos/services/bluetooth_config/fake_device_pairing_handler.cc @@ -4,6 +4,7 @@ #include "chromeos/services/bluetooth_config/fake_device_pairing_handler.h" +#include "base/run_loop.h" #include "chromeos/services/bluetooth_config/device_conversion_util.h" namespace chromeos { @@ -28,6 +29,7 @@ void FakeDevicePairingHandler::SimulatePairDeviceFinished( absl::optional failure_reason) { DCHECK(!current_pairing_device_id().empty()); FinishCurrentPairingRequest(failure_reason); + base::RunLoop().RunUntilIdle(); } void FakeDevicePairingHandler::SimulateFetchDeviceFinished( diff --git a/chromeos/services/bluetooth_config/fake_discovery_session_manager.cc b/chromeos/services/bluetooth_config/fake_discovery_session_manager.cc index 66aa3b9a926baa..1421151eb05fd6 100644 --- a/chromeos/services/bluetooth_config/fake_discovery_session_manager.cc +++ b/chromeos/services/bluetooth_config/fake_discovery_session_manager.cc @@ -4,8 +4,6 @@ #include "chromeos/services/bluetooth_config/fake_discovery_session_manager.h" -#include "chromeos/services/bluetooth_config/fake_device_pairing_handler.h" - namespace chromeos { namespace bluetooth_config { @@ -26,6 +24,7 @@ void FakeDiscoverySessionManager::SetIsDiscoverySessionActive(bool is_active) { if (is_discovery_session_active_) { NotifyDiscoveryStarted(); NotifyHasAtLeastOneDiscoverySessionChanged(is_discovery_session_active_); + NotifyDiscoveredDevicesListChanged(); } else { NotifyDiscoveryStoppedAndClearActiveClients(); // DiscoverySessionStatusObservers would have been notified by the above @@ -47,8 +46,10 @@ std::unique_ptr FakeDiscoverySessionManager::CreateDevicePairingHandler( AdapterStateController* adapter_state_controller, mojo::PendingReceiver receiver) { - return std::make_unique(std::move(receiver), - adapter_state_controller); + auto fake_device_pairing_handler = std::make_unique( + std::move(receiver), adapter_state_controller); + device_pairing_handlers_.push_back(fake_device_pairing_handler.get()); + return fake_device_pairing_handler; } } // namespace bluetooth_config diff --git a/chromeos/services/bluetooth_config/fake_discovery_session_manager.h b/chromeos/services/bluetooth_config/fake_discovery_session_manager.h index 9e34ebac7e92a9..f242a4211e8abb 100644 --- a/chromeos/services/bluetooth_config/fake_discovery_session_manager.h +++ b/chromeos/services/bluetooth_config/fake_discovery_session_manager.h @@ -7,6 +7,7 @@ #include "chromeos/services/bluetooth_config/discovered_devices_provider.h" #include "chromeos/services/bluetooth_config/discovery_session_manager.h" +#include "chromeos/services/bluetooth_config/fake_device_pairing_handler.h" namespace chromeos { namespace bluetooth_config { @@ -25,6 +26,10 @@ class FakeDiscoverySessionManager : public DiscoverySessionManager { using DiscoverySessionManager::HasAtLeastOneDiscoveryClient; + std::vector& device_pairing_handlers() { + return device_pairing_handlers_; + } + private: // DiscoverySessionManager: void OnHasAtLeastOneDiscoveryClientChanged() override; @@ -33,6 +38,8 @@ class FakeDiscoverySessionManager : public DiscoverySessionManager { mojo::PendingReceiver receiver) override; bool is_discovery_session_active_ = false; + + std::vector device_pairing_handlers_; }; } // namespace bluetooth_config