123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173 |
- // Copyright 2022 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #include "ash/components/hid_detection/bluetooth_hid_detector_impl.h"
- #include "ash/constants/ash_features.h"
- #include "base/strings/strcat.h"
- #include "base/strings/utf_string_conversions.h"
- #include "base/test/metrics/histogram_tester.h"
- #include "base/test/scoped_feature_list.h"
- #include "base/test/task_environment.h"
- #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"
- namespace ash::hid_detection {
- namespace {
- using ash::hid_detection::BluetoothHidDetector;
- 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;
- using BluetoothHidMetadata = BluetoothHidDetector::BluetoothHidMetadata;
- using BluetoothHidType = BluetoothHidDetector::BluetoothHidType;
- const char kTestPinCode[] = "123456";
- const uint32_t kTestPasskey = 123456;
- const base::TimeDelta kTestDuration = base::Milliseconds(3000);
- class FakeBluetoothHidDetectorDelegate : public BluetoothHidDetector::Delegate {
- public:
- ~FakeBluetoothHidDetectorDelegate() override = default;
- size_t num_bluetooth_hid_status_changed_calls() const {
- return num_bluetooth_hid_status_changed_calls_;
- }
- private:
- // BluetoothHidDetector::Delegate:
- void OnBluetoothHidStatusChanged() override {
- ++num_bluetooth_hid_status_changed_calls_;
- }
- size_t num_bluetooth_hid_status_changed_calls_ = 0u;
- };
- } // namespace
- class BluetoothHidDetectorImplTest : public testing::Test {
- public:
- BluetoothHidDetectorImplTest(const BluetoothHidDetectorImplTest&) = delete;
- BluetoothHidDetectorImplTest& operator=(const BluetoothHidDetectorImplTest&) =
- delete;
- protected:
- BluetoothHidDetectorImplTest()
- : task_environment_(
- base::test::SingleThreadTaskEnvironment::MainThreadType::UI,
- base::test::TaskEnvironment::TimeSource::MOCK_TIME) {}
- ~BluetoothHidDetectorImplTest() override = default;
- // testing::Test:
- void SetUp() override {
- scoped_feature_list_.InitAndEnableFeature(
- ash::features::kOobeHidDetectionRevamp);
- bluetooth_hid_detector_ = std::make_unique<BluetoothHidDetectorImpl>();
- }
- void TearDown() override {
- // HID detection must be stopped before BluetoothHidDetectorImpl is
- // destroyed.
- if (IsDiscoverySessionActive())
- StopBluetoothHidDetection(/*is_using_bluetooth=*/false);
- }
- FakeBluetoothHidDetectorDelegate* StartBluetoothHidDetection(
- bool pointer_is_missing = true,
- bool keyboard_is_missing = true) {
- delegates_.push_back(std::make_unique<FakeBluetoothHidDetectorDelegate>());
- FakeBluetoothHidDetectorDelegate* delegate = delegates_.back().get();
- bluetooth_hid_detector()->StartBluetoothHidDetection(
- delegate, {.pointer_is_missing = pointer_is_missing,
- .keyboard_is_missing = keyboard_is_missing});
- base::RunLoop().RunUntilIdle();
- return delegate;
- }
- void StopBluetoothHidDetection(bool is_using_bluetooth) {
- bluetooth_hid_detector()->StopBluetoothHidDetection(is_using_bluetooth);
- base::RunLoop().RunUntilIdle();
- }
- void SetInputDevicesStatus(
- BluetoothHidDetector::InputDevicesStatus input_devices_status) {
- bluetooth_hid_detector()->SetInputDevicesStatus(input_devices_status);
- base::RunLoop().RunUntilIdle();
- }
- // Simulates Bluetooth being toggled by a UI surface. This sets the state of
- // the Bluetooth adapter and persists that state which is restored when HID
- // detection finishes.
- void SimulateBluetoothToggledByUi(bool enabled) {
- scoped_bluetooth_config_test_helper_.fake_bluetooth_power_controller()
- ->SetBluetoothEnabledState(enabled);
- }
- // Sets the state of the Bluetooth adapter without any persistence. This
- // simulates the adapter changing without any user interaction.
- void SetAdapterState(BluetoothSystemState system_state) {
- scoped_bluetooth_config_test_helper_.fake_adapter_state_controller()
- ->SetSystemState(system_state);
- }
- BluetoothSystemState GetAdapterState() {
- return scoped_bluetooth_config_test_helper_.fake_adapter_state_controller()
- ->GetAdapterState();
- }
- bool IsDiscoverySessionActive() {
- return scoped_bluetooth_config_test_helper_
- .fake_discovery_session_manager()
- ->IsDiscoverySessionActive();
- }
- // Updates a Bluetooth system property in order to trigger the
- // OnPropertiesUpdated() observer method in BluetoothHidDetectorImpl.
- void TriggerOnPropertiesUpdatedCall() {
- auto paired_device = PairedBluetoothDeviceProperties::New();
- paired_device->device_properties = BluetoothDeviceProperties::New();
- std::vector<PairedBluetoothDevicePropertiesPtr> paired_devices;
- paired_devices.push_back(mojo::Clone(paired_device));
- scoped_bluetooth_config_test_helper_.fake_device_cache()->SetPairedDevices(
- std::move(paired_devices));
- 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->public_name = base::UTF8ToUTF16(*id_out);
- device->device_type = device_type;
- unpaired_devices_.push_back(device.Clone());
- UpdateDiscoveredDevicesProviderDevices();
- base::RunLoop().RunUntilIdle();
- }
- void MockPairDeviceFinished(
- const std::string& device_id,
- FakeDevicePairingHandler* device_pairing_handler,
- absl::optional<device::ConnectionFailureReason> failure_reason) {
- // Mock time passing to measure pairing duration.
- task_environment_.FastForwardBy(kTestDuration);
- 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();
- device_pairing_handler->SimulatePairDeviceFinished(failure_reason);
- EXPECT_TRUE(device_pairing_handler->current_pairing_device_id().empty());
- }
- std::vector<FakeDevicePairingHandler*> GetDevicePairingHandlers() {
- return scoped_bluetooth_config_test_helper_
- .fake_discovery_session_manager()
- ->device_pairing_handlers();
- }
- void AssertBluetoothHidDetectionStatus(
- absl::optional<BluetoothHidDetector::BluetoothHidMetadata>
- current_pairing_device,
- absl::optional<BluetoothHidPairingState> pairing_state) {
- EXPECT_EQ(
- current_pairing_device.has_value(),
- GetBluetoothHidDetectionStatus().current_pairing_device.has_value());
- if (current_pairing_device.has_value()) {
- EXPECT_EQ(current_pairing_device->name,
- GetBluetoothHidDetectionStatus().current_pairing_device->name);
- EXPECT_EQ(current_pairing_device->type,
- GetBluetoothHidDetectionStatus().current_pairing_device->type);
- }
- EXPECT_EQ(pairing_state.has_value(),
- GetBluetoothHidDetectionStatus().pairing_state.has_value());
- if (pairing_state.has_value()) {
- EXPECT_EQ(pairing_state->code,
- GetBluetoothHidDetectionStatus().pairing_state->code);
- EXPECT_EQ(
- pairing_state->num_keys_entered,
- GetBluetoothHidDetectionStatus().pairing_state->num_keys_entered);
- }
- }
- void AssertBluetoothPairingResult(bool success, int count) {
- histogram_tester_.ExpectTimeBucketCount(
- base::StrCat({"OOBE.HidDetectionScreen.BluetoothPairing.Duration.",
- success ? "Success" : "Failure"}),
- kTestDuration, count);
- histogram_tester_.ExpectBucketCount(
- "OOBE.HidDetectionScreen.BluetoothPairing.Result", success, count);
- }
- void AssertBluetoothPairingAttemptsCount(int bucket,
- int count,
- int total_count) {
- histogram_tester_.ExpectBucketCount(
- "OOBE.HidDetectionScreen.BluetoothPairingAttempts", bucket, count);
- histogram_tester_.ExpectTotalCount(
- "OOBE.HidDetectionScreen.BluetoothPairingAttempts", total_count);
- }
- private:
- void UpdateDiscoveredDevicesProviderDevices() {
- std::vector<BluetoothDevicePropertiesPtr> 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));
- }
- const BluetoothHidDetector::BluetoothHidDetectionStatus
- GetBluetoothHidDetectionStatus() {
- return bluetooth_hid_detector()->GetBluetoothHidDetectionStatus();
- }
- BluetoothHidDetectorImpl* bluetooth_hid_detector() {
- return bluetooth_hid_detector_.get();
- }
- base::test::TaskEnvironment task_environment_;
- base::test::ScopedFeatureList scoped_feature_list_;
- base::HistogramTester histogram_tester_;
- std::vector<BluetoothDevicePropertiesPtr> unpaired_devices_;
- size_t num_devices_created_ = 0u;
- // Delegates because must be retained by the test for when HID
- // detection is stopped in TearDown().
- std::vector<std::unique_ptr<FakeBluetoothHidDetectorDelegate>> delegates_;
- chromeos::bluetooth_config::ScopedBluetoothConfigTestHelper
- scoped_bluetooth_config_test_helper_;
- std::unique_ptr<hid_detection::BluetoothHidDetectorImpl>
- bluetooth_hid_detector_;
- };
- TEST_F(BluetoothHidDetectorImplTest, StartStopStartDetection_BluetoothEnabled) {
- // Start with Bluetooth enabled.
- EXPECT_EQ(BluetoothSystemState::kEnabled, GetAdapterState());
- EXPECT_FALSE(IsDiscoverySessionActive());
- // Trigger an OnPropertiesUpdated() call. Nothing should happen.
- TriggerOnPropertiesUpdatedCall();
- EXPECT_FALSE(IsDiscoverySessionActive());
- // Begin HID detection. Discovery should have started and Bluetooth still
- // enabled.
- StartBluetoothHidDetection();
- EXPECT_TRUE(IsDiscoverySessionActive());
- EXPECT_EQ(BluetoothSystemState::kEnabled, GetAdapterState());
- // Trigger an OnPropertiesUpdated() call. Nothing should happen.
- TriggerOnPropertiesUpdatedCall();
- EXPECT_TRUE(IsDiscoverySessionActive());
- // Stop HID detection. Discovery should have stopped but Bluetooth still
- // enabled.
- StopBluetoothHidDetection(/*is_using_bluetooth=*/false);
- EXPECT_FALSE(IsDiscoverySessionActive());
- EXPECT_EQ(BluetoothSystemState::kEnabled, GetAdapterState());
- AssertBluetoothPairingAttemptsCount(/*bucket=*/0, /*count=*/1,
- /*total_count=*/1);
- // Trigger an OnPropertiesUpdated() call. Nothing should happen.
- TriggerOnPropertiesUpdatedCall();
- EXPECT_FALSE(IsDiscoverySessionActive());
- // Begin HID detection again. Discovery should have started and Bluetooth
- // still enabled.
- StartBluetoothHidDetection();
- EXPECT_TRUE(IsDiscoverySessionActive());
- EXPECT_EQ(BluetoothSystemState::kEnabled, GetAdapterState());
- }
- TEST_F(BluetoothHidDetectorImplTest,
- StartStopDetection_BluetoothDisabled_BluetoothUnused) {
- // Initiate disabling Bluetooth.
- SimulateBluetoothToggledByUi(/*enabled=*/false);
- EXPECT_EQ(BluetoothSystemState::kDisabling, GetAdapterState());
- // Complete adapter disabling.
- SetAdapterState(BluetoothSystemState::kDisabled);
- EXPECT_EQ(BluetoothSystemState::kDisabled, GetAdapterState());
- // Begin HID detection. The adapter state should switch to enabling.
- StartBluetoothHidDetection();
- EXPECT_EQ(BluetoothSystemState::kEnabling, GetAdapterState());
- EXPECT_FALSE(IsDiscoverySessionActive());
- // Mock the adapter becoming unavailable.
- SetAdapterState(BluetoothSystemState::kUnavailable);
- EXPECT_EQ(BluetoothSystemState::kUnavailable, GetAdapterState());
- EXPECT_FALSE(IsDiscoverySessionActive());
- // Mock the adapter becoming available again.
- SetAdapterState(BluetoothSystemState::kEnabling);
- EXPECT_EQ(BluetoothSystemState::kEnabling, GetAdapterState());
- EXPECT_FALSE(IsDiscoverySessionActive());
- // Mock the adapter enabling. Discovery should have started.
- SetAdapterState(BluetoothSystemState::kEnabled);
- EXPECT_EQ(BluetoothSystemState::kEnabled, GetAdapterState());
- EXPECT_TRUE(IsDiscoverySessionActive());
- // Trigger an OnPropertiesUpdated() call. Nothing should happen.
- TriggerOnPropertiesUpdatedCall();
- // Stop HID detection with no device using Bluetooth. Discovery should have
- // stopped and Bluetooth disabled.
- StopBluetoothHidDetection(/*is_using_bluetooth=*/false);
- EXPECT_FALSE(IsDiscoverySessionActive());
- EXPECT_EQ(BluetoothSystemState::kDisabling, GetAdapterState());
- }
- TEST_F(BluetoothHidDetectorImplTest,
- StartStopDetection_BluetoothDisabled_BluetoothUsed) {
- // Initiate disabling Bluetooth.
- SimulateBluetoothToggledByUi(/*enabled=*/false);
- EXPECT_EQ(BluetoothSystemState::kDisabling, GetAdapterState());
- // Complete adapter disabling.
- SetAdapterState(BluetoothSystemState::kDisabled);
- EXPECT_EQ(BluetoothSystemState::kDisabled, GetAdapterState());
- // Begin HID detection. The adapter state should switch to enabling.
- StartBluetoothHidDetection();
- EXPECT_EQ(BluetoothSystemState::kEnabling, GetAdapterState());
- EXPECT_FALSE(IsDiscoverySessionActive());
- // Stop HID detection with Bluetooth being used by a device. Discovery should
- // have stopped but the adapter state remained the same.
- StopBluetoothHidDetection(/*is_using_bluetooth=*/true);
- EXPECT_FALSE(IsDiscoverySessionActive());
- EXPECT_EQ(BluetoothSystemState::kEnabling, GetAdapterState());
- }
- TEST_F(BluetoothHidDetectorImplTest, StartDetection_BluetoothUnavailable) {
- // Set Bluetooth to unavailable.
- SetAdapterState(BluetoothSystemState::kUnavailable);
- EXPECT_EQ(BluetoothSystemState::kUnavailable, GetAdapterState());
- // Begin HID detection.
- StartBluetoothHidDetection();
- EXPECT_FALSE(IsDiscoverySessionActive());
- // Set Bluetooth to enabling.
- SetAdapterState(BluetoothSystemState::kEnabling);
- EXPECT_EQ(BluetoothSystemState::kEnabling, GetAdapterState());
- // Complete adapter enabling. Discovery should have started.
- SetAdapterState(BluetoothSystemState::kEnabled);
- EXPECT_EQ(BluetoothSystemState::kEnabled, GetAdapterState());
- EXPECT_TRUE(IsDiscoverySessionActive());
- }
- TEST_F(BluetoothHidDetectorImplTest,
- StartDetection_BluetoothDisabledEnabledExternally) {
- // Start with Bluetooth enabled.
- EXPECT_EQ(BluetoothSystemState::kEnabled, GetAdapterState());
- // Begin HID detection. Discovery should have started and Bluetooth still
- // enabled.
- StartBluetoothHidDetection();
- EXPECT_TRUE(IsDiscoverySessionActive());
- EXPECT_EQ(BluetoothSystemState::kEnabled, GetAdapterState());
- // Mock another client disabling Bluetooth.
- SimulateBluetoothToggledByUi(/*enabled=*/false);
- EXPECT_EQ(BluetoothSystemState::kDisabling, GetAdapterState());
- EXPECT_FALSE(IsDiscoverySessionActive());
- // Finish the adapter disabling.
- SetAdapterState(BluetoothSystemState::kDisabled);
- EXPECT_EQ(BluetoothSystemState::kDisabled, GetAdapterState());
- EXPECT_FALSE(IsDiscoverySessionActive());
- // Mock another client re-enabling Bluetooth. This should cause
- // BluetoothHidDetector to start discovery again.
- SimulateBluetoothToggledByUi(/*enabled=*/true);
- EXPECT_EQ(BluetoothSystemState::kEnabling, GetAdapterState());
- EXPECT_FALSE(IsDiscoverySessionActive());
- SetAdapterState(BluetoothSystemState::kEnabled);
- EXPECT_EQ(BluetoothSystemState::kEnabled, GetAdapterState());
- 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.
- FakeBluetoothHidDetectorDelegate* delegate = StartBluetoothHidDetection();
- EXPECT_TRUE(IsDiscoverySessionActive());
- EXPECT_EQ(1u, GetDevicePairingHandlers().size());
- EXPECT_EQ(device_id2,
- GetDevicePairingHandlers()[0]->current_pairing_device_id());
- EXPECT_EQ(1u, delegate->num_bluetooth_hid_status_changed_calls());
- AssertBluetoothHidDetectionStatus(
- BluetoothHidMetadata(device_id2, BluetoothHidType::kKeyboard),
- /*pairing_state=*/absl::nullopt);
- StopBluetoothHidDetection(/*is_using_bluetooth=*/false);
- AssertBluetoothPairingAttemptsCount(/*bucket=*/1, /*count=*/1,
- /*total_count=*/1);
- }
- 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.
- FakeBluetoothHidDetectorDelegate* delegate =
- StartBluetoothHidDetection(/*is_pointer_missing=*/false);
- EXPECT_TRUE(IsDiscoverySessionActive());
- EXPECT_EQ(1u, GetDevicePairingHandlers().size());
- EXPECT_EQ(device_id2,
- GetDevicePairingHandlers()[0]->current_pairing_device_id());
- EXPECT_EQ(1u, delegate->num_bluetooth_hid_status_changed_calls());
- AssertBluetoothHidDetectionStatus(
- BluetoothHidMetadata(device_id2, BluetoothHidType::kKeyboard),
- /*pairing_state=*/absl::nullopt);
- StopBluetoothHidDetection(/*is_using_bluetooth=*/false);
- AssertBluetoothPairingAttemptsCount(/*bucket=*/1, /*count=*/1,
- /*total_count=*/1);
- }
- TEST_F(BluetoothHidDetectorImplTest, AddDevices_NoTypeMissing) {
- std::string device_id1;
- AddUnpairedDevice(&device_id1, DeviceType::kMouse);
- std::string device_id2;
- AddUnpairedDevice(&device_id2, DeviceType::kKeyboard);
- // Begin HID detection with no types missing. No device should be attempted to
- // be paired with.
- FakeBluetoothHidDetectorDelegate* delegate = StartBluetoothHidDetection(
- /*is_pointer_missing=*/false, /*is_keyboard_missing=*/false);
- EXPECT_TRUE(IsDiscoverySessionActive());
- EXPECT_EQ(1u, GetDevicePairingHandlers().size());
- EXPECT_TRUE(
- GetDevicePairingHandlers()[0]->current_pairing_device_id().empty());
- EXPECT_EQ(0u, delegate->num_bluetooth_hid_status_changed_calls());
- AssertBluetoothHidDetectionStatus(
- /*current_pairing_device=*/absl::nullopt,
- /*pairing_state=*/absl::nullopt);
- // Mock the pointer disconnecting and add another device to trigger
- // OnDiscoveredDevicesListChanged(). |device_id1| should be attempted to be
- // paired with.
- SetInputDevicesStatus(
- {.pointer_is_missing = true, .keyboard_is_missing = false});
- std::string device_id3;
- AddUnpairedDevice(&device_id3, DeviceType::kMouse);
- EXPECT_EQ(device_id1,
- GetDevicePairingHandlers()[0]->current_pairing_device_id());
- EXPECT_EQ(1u, delegate->num_bluetooth_hid_status_changed_calls());
- AssertBluetoothHidDetectionStatus(
- BluetoothHidMetadata(device_id1, BluetoothHidType::kPointer),
- /*pairing_state=*/absl::nullopt);
- StopBluetoothHidDetection(/*is_using_bluetooth=*/false);
- AssertBluetoothPairingAttemptsCount(/*bucket=*/1, /*count=*/1,
- /*total_count=*/1);
- }
- TEST_F(BluetoothHidDetectorImplTest,
- AddDevices_SeriallyAfterStartingDetection) {
- FakeBluetoothHidDetectorDelegate* delegate = StartBluetoothHidDetection();
- EXPECT_TRUE(IsDiscoverySessionActive());
- EXPECT_EQ(1u, GetDevicePairingHandlers().size());
- EXPECT_TRUE(
- GetDevicePairingHandlers()[0]->current_pairing_device_id().empty());
- EXPECT_EQ(0u, delegate->num_bluetooth_hid_status_changed_calls());
- AssertBluetoothHidDetectionStatus(
- /*current_pairing_device=*/absl::nullopt,
- /*pairing_state=*/absl::nullopt);
- std::string device_id1;
- AddUnpairedDevice(&device_id1, DeviceType::kTablet);
- EXPECT_EQ(device_id1,
- GetDevicePairingHandlers()[0]->current_pairing_device_id());
- EXPECT_EQ(1u, delegate->num_bluetooth_hid_status_changed_calls());
- AssertBluetoothHidDetectionStatus(
- BluetoothHidMetadata(device_id1, BluetoothHidType::kPointer),
- /*pairing_state=*/absl::nullopt);
- AssertBluetoothPairingResult(/*success=*/true, /*count=*/0);
- // Mock |device_id1| being paired. BluetoothHidDetectorImpl should not inform
- // the delegate or move to the next device in queue until the input devices
- // status has been updated.
- MockPairDeviceFinished(device_id1, GetDevicePairingHandlers()[0],
- /*failure_reason=*/absl::nullopt);
- EXPECT_EQ(1u, delegate->num_bluetooth_hid_status_changed_calls());
- AssertBluetoothHidDetectionStatus(
- BluetoothHidMetadata(device_id1, BluetoothHidType::kPointer),
- /*pairing_state=*/absl::nullopt);
- // Mock |device_id1| being registered as connected. The next device in the
- // queue should now be processed.
- SetInputDevicesStatus(
- {.pointer_is_missing = false, .keyboard_is_missing = true});
- EXPECT_TRUE(
- GetDevicePairingHandlers()[0]->current_pairing_device_id().empty());
- EXPECT_EQ(2u, delegate->num_bluetooth_hid_status_changed_calls());
- AssertBluetoothHidDetectionStatus(
- /*current_pairing_device=*/absl::nullopt,
- /*pairing_state=*/absl::nullopt);
- AssertBluetoothPairingResult(/*success=*/true, /*count=*/1);
- std::string device_id2;
- AddUnpairedDevice(&device_id2, DeviceType::kKeyboard);
- EXPECT_EQ(device_id2,
- GetDevicePairingHandlers()[0]->current_pairing_device_id());
- EXPECT_EQ(3u, delegate->num_bluetooth_hid_status_changed_calls());
- AssertBluetoothHidDetectionStatus(
- BluetoothHidMetadata(device_id2, BluetoothHidType::kKeyboard),
- /*pairing_state=*/absl::nullopt);
- StopBluetoothHidDetection(/*is_using_bluetooth=*/false);
- AssertBluetoothPairingAttemptsCount(/*bucket=*/2, /*count=*/1,
- /*total_count=*/1);
- }
- TEST_F(BluetoothHidDetectorImplTest, AddDevices_BatchAfterStartingDetection) {
- FakeBluetoothHidDetectorDelegate* delegate = StartBluetoothHidDetection();
- EXPECT_TRUE(IsDiscoverySessionActive());
- EXPECT_EQ(1u, GetDevicePairingHandlers().size());
- EXPECT_TRUE(
- GetDevicePairingHandlers()[0]->current_pairing_device_id().empty());
- EXPECT_EQ(0u, delegate->num_bluetooth_hid_status_changed_calls());
- AssertBluetoothHidDetectionStatus(
- /*current_pairing_device=*/absl::nullopt,
- /*pairing_state=*/absl::nullopt);
- std::string device_id1;
- AddUnpairedDevice(&device_id1, DeviceType::kMouse);
- EXPECT_EQ(device_id1,
- GetDevicePairingHandlers()[0]->current_pairing_device_id());
- EXPECT_EQ(1u, delegate->num_bluetooth_hid_status_changed_calls());
- AssertBluetoothHidDetectionStatus(
- BluetoothHidMetadata(device_id1, BluetoothHidType::kPointer),
- /*pairing_state=*/absl::nullopt);
- std::string device_id2;
- AddUnpairedDevice(&device_id2, DeviceType::kKeyboardMouseCombo);
- EXPECT_EQ(1u, delegate->num_bluetooth_hid_status_changed_calls());
- AssertBluetoothPairingResult(/*success=*/true, /*count=*/0);
- // Mock |device_id1| being paired. BluetoothHidDetectorImpl should not inform
- // the delegate or move to the next device in queue until the input devices
- // status has been updated.
- MockPairDeviceFinished(device_id1, GetDevicePairingHandlers()[0],
- /*failure_reason=*/absl::nullopt);
- EXPECT_EQ(1u, delegate->num_bluetooth_hid_status_changed_calls());
- AssertBluetoothHidDetectionStatus(
- BluetoothHidMetadata(device_id1, BluetoothHidType::kPointer),
- /*pairing_state=*/absl::nullopt);
- // Mock |device_id1| being registered as connected. |device_id2| should be
- // attempted to be paired with.
- SetInputDevicesStatus(
- {.pointer_is_missing = false, .keyboard_is_missing = true});
- EXPECT_EQ(device_id2,
- GetDevicePairingHandlers()[0]->current_pairing_device_id());
- EXPECT_EQ(3u, delegate->num_bluetooth_hid_status_changed_calls());
- AssertBluetoothPairingResult(/*success=*/true, /*count=*/1);
- AssertBluetoothHidDetectionStatus(
- BluetoothHidMetadata(device_id2, BluetoothHidType::kKeyboardPointerCombo),
- /*pairing_state=*/absl::nullopt);
- // Mock |device_id2| being registered as connected. Two devices should be
- // paired successfully.
- MockPairDeviceFinished(device_id2, GetDevicePairingHandlers()[0],
- /*failure_reason=*/absl::nullopt);
- EXPECT_EQ(3u, delegate->num_bluetooth_hid_status_changed_calls());
- AssertBluetoothHidDetectionStatus(
- BluetoothHidMetadata(device_id2, BluetoothHidType::kKeyboardPointerCombo),
- /*pairing_state=*/absl::nullopt);
- SetInputDevicesStatus(
- {.pointer_is_missing = false, .keyboard_is_missing = false});
- EXPECT_EQ(4u, delegate->num_bluetooth_hid_status_changed_calls());
- AssertBluetoothHidDetectionStatus(
- /*current_pairing_device=*/absl::nullopt,
- /*pairing_state=*/absl::nullopt);
- AssertBluetoothPairingResult(/*success=*/true, /*count=*/2);
- StopBluetoothHidDetection(/*is_using_bluetooth=*/false);
- AssertBluetoothPairingAttemptsCount(/*bucket=*/2, /*count=*/1,
- /*total_count=*/1);
- }
- TEST_F(BluetoothHidDetectorImplTest,
- AddDevices_BeforeStartingDetectionSameType) {
- std::string device_id1;
- AddUnpairedDevice(&device_id1, DeviceType::kMouse);
- std::string device_id2;
- AddUnpairedDevice(&device_id2, DeviceType::kMouse);
- std::string device_id3;
- AddUnpairedDevice(&device_id3, DeviceType::kKeyboard);
- // Begin HID detection. |device_id1| should be attempted to be paired with.
- FakeBluetoothHidDetectorDelegate* delegate = StartBluetoothHidDetection();
- EXPECT_TRUE(IsDiscoverySessionActive());
- EXPECT_EQ(1u, GetDevicePairingHandlers().size());
- EXPECT_EQ(device_id1,
- GetDevicePairingHandlers()[0]->current_pairing_device_id());
- EXPECT_EQ(1u, delegate->num_bluetooth_hid_status_changed_calls());
- AssertBluetoothHidDetectionStatus(
- BluetoothHidMetadata(device_id1, BluetoothHidType::kPointer),
- /*pairing_state=*/absl::nullopt);
- AssertBluetoothPairingResult(/*success=*/true, /*count=*/0);
- // Mock |device_id1| being paired. BluetoothHidDetectorImpl should not inform
- // the delegate or move to the next device in queue until the input devices
- // status has been updated.
- MockPairDeviceFinished(device_id1, GetDevicePairingHandlers()[0],
- /*failure_reason=*/absl::nullopt);
- EXPECT_EQ(1u, delegate->num_bluetooth_hid_status_changed_calls());
- AssertBluetoothHidDetectionStatus(
- BluetoothHidMetadata(device_id1, BluetoothHidType::kPointer),
- /*pairing_state=*/absl::nullopt);
- // Mock |device_id1| being registered as connected. |device_id3| should be
- // attempted to be paired with.
- SetInputDevicesStatus(
- {.pointer_is_missing = false, .keyboard_is_missing = true});
- EXPECT_EQ(device_id3,
- GetDevicePairingHandlers()[0]->current_pairing_device_id());
- EXPECT_EQ(3u, delegate->num_bluetooth_hid_status_changed_calls());
- AssertBluetoothHidDetectionStatus(
- BluetoothHidMetadata(device_id3, BluetoothHidType::kKeyboard),
- /*pairing_state=*/absl::nullopt);
- AssertBluetoothPairingResult(/*success=*/true, /*count=*/1);
- AssertBluetoothPairingResult(/*success=*/false, /*count=*/0);
- // Mock |device_id3| pairing failing. BluetoothHidDetectorImpl should move to
- // the next device in the queue immediately.
- MockPairDeviceFinished(device_id3, GetDevicePairingHandlers()[0],
- device::ConnectionFailureReason::kFailed);
- EXPECT_EQ(4u, delegate->num_bluetooth_hid_status_changed_calls());
- AssertBluetoothHidDetectionStatus(
- /*current_pairing_device=*/absl::nullopt,
- /*pairing_state=*/absl::nullopt);
- AssertBluetoothPairingResult(/*success=*/false, /*count=*/1);
- StopBluetoothHidDetection(/*is_using_bluetooth=*/false);
- AssertBluetoothPairingAttemptsCount(/*bucket=*/2, /*count=*/1,
- /*total_count=*/1);
- }
- TEST_F(BluetoothHidDetectorImplTest, DisconnectDevice) {
- FakeBluetoothHidDetectorDelegate* delegate = StartBluetoothHidDetection();
- EXPECT_TRUE(IsDiscoverySessionActive());
- EXPECT_EQ(1u, GetDevicePairingHandlers().size());
- EXPECT_TRUE(
- GetDevicePairingHandlers()[0]->current_pairing_device_id().empty());
- EXPECT_EQ(0u, delegate->num_bluetooth_hid_status_changed_calls());
- AssertBluetoothHidDetectionStatus(
- /*current_pairing_device=*/absl::nullopt,
- /*pairing_state=*/absl::nullopt);
- // Set both devices to connected.
- SetInputDevicesStatus(
- {.pointer_is_missing = false, .keyboard_is_missing = false});
- EXPECT_EQ(0u, delegate->num_bluetooth_hid_status_changed_calls());
- AssertBluetoothHidDetectionStatus(
- /*current_pairing_device=*/absl::nullopt,
- /*pairing_state=*/absl::nullopt);
- // Add a discovered device. Nothing should happen.
- std::string device_id1;
- AddUnpairedDevice(&device_id1, DeviceType::kMouse);
- EXPECT_TRUE(
- GetDevicePairingHandlers()[0]->current_pairing_device_id().empty());
- EXPECT_EQ(0u, delegate->num_bluetooth_hid_status_changed_calls());
- AssertBluetoothHidDetectionStatus(
- /*current_pairing_device=*/absl::nullopt,
- /*pairing_state=*/absl::nullopt);
- // Mock the pointer no longer being connected.
- SetInputDevicesStatus(
- {.pointer_is_missing = true, .keyboard_is_missing = false});
- // Add another device to trigger OnDiscoveredDevicesListChanged().
- std::string device_id2;
- AddUnpairedDevice(&device_id2, DeviceType::kKeyboard);
- EXPECT_EQ(device_id1,
- GetDevicePairingHandlers()[0]->current_pairing_device_id());
- EXPECT_EQ(1u, delegate->num_bluetooth_hid_status_changed_calls());
- AssertBluetoothHidDetectionStatus(
- BluetoothHidMetadata(device_id1, BluetoothHidType::kPointer),
- /*pairing_state=*/absl::nullopt);
- StopBluetoothHidDetection(/*is_using_bluetooth=*/false);
- AssertBluetoothPairingAttemptsCount(/*bucket=*/1, /*count=*/1,
- /*total_count=*/1);
- }
- TEST_F(BluetoothHidDetectorImplTest, ConnectDeviceTypeDuringPairing) {
- 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.
- FakeBluetoothHidDetectorDelegate* delegate = StartBluetoothHidDetection();
- EXPECT_TRUE(IsDiscoverySessionActive());
- EXPECT_EQ(1u, GetDevicePairingHandlers().size());
- EXPECT_EQ(device_id1,
- GetDevicePairingHandlers()[0]->current_pairing_device_id());
- EXPECT_EQ(1u, delegate->num_bluetooth_hid_status_changed_calls());
- AssertBluetoothHidDetectionStatus(
- BluetoothHidMetadata(device_id1, BluetoothHidType::kPointer),
- /*pairing_state=*/absl::nullopt);
- // Mock a keyboard being connected. Nothing should happen.
- SetInputDevicesStatus(
- {.pointer_is_missing = true, .keyboard_is_missing = false});
- EXPECT_EQ(device_id1,
- GetDevicePairingHandlers()[0]->current_pairing_device_id());
- EXPECT_EQ(1u, delegate->num_bluetooth_hid_status_changed_calls());
- AssertBluetoothHidDetectionStatus(
- BluetoothHidMetadata(device_id1, BluetoothHidType::kPointer),
- /*pairing_state=*/absl::nullopt);
- // Mock keyboard being disconnected. Nothing should happen.
- SetInputDevicesStatus(
- {.pointer_is_missing = true, .keyboard_is_missing = true});
- EXPECT_EQ(device_id1,
- GetDevicePairingHandlers()[0]->current_pairing_device_id());
- EXPECT_EQ(1u, delegate->num_bluetooth_hid_status_changed_calls());
- AssertBluetoothHidDetectionStatus(
- BluetoothHidMetadata(device_id1, BluetoothHidType::kPointer),
- /*pairing_state=*/absl::nullopt);
- // Mock a pointer being connected. This should cancel pairing with
- // |device_id1|.
- SetInputDevicesStatus(
- {.pointer_is_missing = false, .keyboard_is_missing = true});
- EXPECT_EQ(device_id2,
- GetDevicePairingHandlers()[0]->current_pairing_device_id());
- EXPECT_EQ(3u, delegate->num_bluetooth_hid_status_changed_calls());
- AssertBluetoothHidDetectionStatus(
- BluetoothHidMetadata(device_id2, BluetoothHidType::kKeyboard),
- /*pairing_state=*/absl::nullopt);
- StopBluetoothHidDetection(/*is_using_bluetooth=*/false);
- AssertBluetoothPairingAttemptsCount(/*bucket=*/2, /*count=*/1,
- /*total_count=*/1);
- }
- TEST_F(BluetoothHidDetectorImplTest,
- ConnectDeviceTypeDuringKeyboardMouseComboPairing) {
- std::string device_id1;
- AddUnpairedDevice(&device_id1, DeviceType::kKeyboardMouseCombo);
- std::string device_id2;
- AddUnpairedDevice(&device_id2, DeviceType::kKeyboard);
- // Begin HID detection. |device_id1| should be attempted to be paired with.
- FakeBluetoothHidDetectorDelegate* delegate = StartBluetoothHidDetection();
- EXPECT_TRUE(IsDiscoverySessionActive());
- EXPECT_EQ(1u, GetDevicePairingHandlers().size());
- EXPECT_EQ(device_id1,
- GetDevicePairingHandlers()[0]->current_pairing_device_id());
- EXPECT_EQ(1u, delegate->num_bluetooth_hid_status_changed_calls());
- AssertBluetoothHidDetectionStatus(
- BluetoothHidMetadata(device_id1, BluetoothHidType::kKeyboardPointerCombo),
- /*pairing_state=*/absl::nullopt);
- // Mock a keyboard being connected. This should not cancel pairing with
- // |device_id1|.
- SetInputDevicesStatus(
- {.pointer_is_missing = true, .keyboard_is_missing = false});
- EXPECT_EQ(device_id1,
- GetDevicePairingHandlers()[0]->current_pairing_device_id());
- EXPECT_EQ(1u, delegate->num_bluetooth_hid_status_changed_calls());
- AssertBluetoothHidDetectionStatus(
- BluetoothHidMetadata(device_id1, BluetoothHidType::kKeyboardPointerCombo),
- /*pairing_state=*/absl::nullopt);
- // Mock a pointer also being connected. This should cancel pairing with
- // |device_id1|.
- SetInputDevicesStatus(
- {.pointer_is_missing = false, .keyboard_is_missing = false});
- EXPECT_TRUE(
- GetDevicePairingHandlers()[0]->current_pairing_device_id().empty());
- EXPECT_EQ(2u, delegate->num_bluetooth_hid_status_changed_calls());
- AssertBluetoothHidDetectionStatus(
- /*current_pairing_device=*/absl::nullopt,
- /*pairing_state=*/absl::nullopt);
- StopBluetoothHidDetection(/*is_using_bluetooth=*/false);
- AssertBluetoothPairingAttemptsCount(/*bucket=*/1, /*count=*/1,
- /*total_count=*/1);
- }
- 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.
- FakeBluetoothHidDetectorDelegate* delegate = StartBluetoothHidDetection();
- EXPECT_TRUE(IsDiscoverySessionActive());
- EXPECT_EQ(1u, GetDevicePairingHandlers().size());
- EXPECT_EQ(device_id1,
- GetDevicePairingHandlers()[0]->current_pairing_device_id());
- EXPECT_EQ(1u, delegate->num_bluetooth_hid_status_changed_calls());
- AssertBluetoothHidDetectionStatus(
- BluetoothHidMetadata(device_id1, BluetoothHidType::kPointer),
- /*pairing_state=*/absl::nullopt);
- // Simulate "DisplayPasskey" authorization required.
- GetDevicePairingHandlers()[0]->SimulateDisplayPasskey(kTestPasskey);
- EXPECT_EQ(device_id1,
- GetDevicePairingHandlers()[0]->current_pairing_device_id());
- EXPECT_EQ(2u, delegate->num_bluetooth_hid_status_changed_calls());
- AssertBluetoothHidDetectionStatus(
- BluetoothHidMetadata(device_id1, BluetoothHidType::kPointer),
- BluetoothHidPairingState(kTestPinCode, /*num_keys_entered=*/0u));
- // Mock the adapter disabling.
- SetAdapterState(BluetoothSystemState::kDisabled);
- EXPECT_FALSE(IsDiscoverySessionActive());
- EXPECT_EQ(3u, delegate->num_bluetooth_hid_status_changed_calls());
- AssertBluetoothHidDetectionStatus(
- /*current_pairing_device=*/absl::nullopt,
- /*pairing_state=*/absl::nullopt);
- // 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());
- EXPECT_EQ(4u, delegate->num_bluetooth_hid_status_changed_calls());
- AssertBluetoothHidDetectionStatus(
- BluetoothHidMetadata(device_id1, BluetoothHidType::kPointer),
- /*pairing_state=*/absl::nullopt);
- // Simulate "DisplayPincode" authorization required.
- GetDevicePairingHandlers()[1]->SimulateDisplayPinCode(kTestPinCode);
- EXPECT_EQ(device_id1,
- GetDevicePairingHandlers()[1]->current_pairing_device_id());
- EXPECT_EQ(5u, delegate->num_bluetooth_hid_status_changed_calls());
- AssertBluetoothHidDetectionStatus(
- BluetoothHidMetadata(device_id1, BluetoothHidType::kPointer),
- BluetoothHidPairingState(kTestPinCode, /*num_keys_entered=*/0u));
- StopBluetoothHidDetection(/*is_using_bluetooth=*/false);
- AssertBluetoothPairingAttemptsCount(/*bucket=*/2, /*count=*/1,
- /*total_count=*/1);
- }
- 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.
- FakeBluetoothHidDetectorDelegate* delegate1 = StartBluetoothHidDetection();
- EXPECT_TRUE(IsDiscoverySessionActive());
- EXPECT_EQ(1u, GetDevicePairingHandlers().size());
- EXPECT_EQ(device_id1,
- GetDevicePairingHandlers()[0]->current_pairing_device_id());
- EXPECT_EQ(1u, delegate1->num_bluetooth_hid_status_changed_calls());
- AssertBluetoothHidDetectionStatus(
- BluetoothHidMetadata(device_id1, BluetoothHidType::kPointer),
- /*pairing_state=*/absl::nullopt);
- // Simulate "DisplayPincode" authorization required.
- GetDevicePairingHandlers()[0]->SimulateDisplayPinCode(kTestPinCode);
- EXPECT_EQ(device_id1,
- GetDevicePairingHandlers()[0]->current_pairing_device_id());
- EXPECT_EQ(2u, delegate1->num_bluetooth_hid_status_changed_calls());
- AssertBluetoothHidDetectionStatus(
- BluetoothHidMetadata(device_id1, BluetoothHidType::kPointer),
- BluetoothHidPairingState(kTestPinCode, /*num_keys_entered=*/0u));
- // Stop detection.
- StopBluetoothHidDetection(/*is_using_bluetooth=*/false);
- AssertBluetoothPairingAttemptsCount(/*bucket=*/1, /*count=*/1,
- /*total_count=*/1);
- EXPECT_FALSE(IsDiscoverySessionActive());
- EXPECT_EQ(3u, delegate1->num_bluetooth_hid_status_changed_calls());
- AssertBluetoothHidDetectionStatus(
- /*current_pairing_device=*/absl::nullopt,
- /*pairing_state=*/absl::nullopt);
- // Start detection again. The first device should be attempted to be paired
- // with again.
- FakeBluetoothHidDetectorDelegate* delegate2 = StartBluetoothHidDetection();
- EXPECT_TRUE(IsDiscoverySessionActive());
- EXPECT_EQ(2u, GetDevicePairingHandlers().size());
- EXPECT_EQ(device_id1,
- GetDevicePairingHandlers()[1]->current_pairing_device_id());
- EXPECT_EQ(1u, delegate2->num_bluetooth_hid_status_changed_calls());
- AssertBluetoothHidDetectionStatus(
- BluetoothHidMetadata(device_id1, BluetoothHidType::kPointer),
- /*pairing_state=*/absl::nullopt);
- // Simulate "DisplayPasskey" authorization required.
- GetDevicePairingHandlers()[1]->SimulateDisplayPasskey(kTestPasskey);
- EXPECT_EQ(device_id1,
- GetDevicePairingHandlers()[1]->current_pairing_device_id());
- EXPECT_EQ(2u, delegate2->num_bluetooth_hid_status_changed_calls());
- AssertBluetoothHidDetectionStatus(
- BluetoothHidMetadata(device_id1, BluetoothHidType::kPointer),
- BluetoothHidPairingState(kTestPinCode, /*num_keys_entered=*/0u));
- StopBluetoothHidDetection(/*is_using_bluetooth=*/false);
- AssertBluetoothPairingAttemptsCount(/*bucket=*/1, /*count=*/2,
- /*total_count=*/2);
- }
- TEST_F(BluetoothHidDetectorImplTest, AddDevices_UnsupportedAuthorizations) {
- std::string device_id1;
- AddUnpairedDevice(&device_id1, DeviceType::kMouse);
- std::string device_id2;
- AddUnpairedDevice(&device_id2, DeviceType::kTablet);
- std::string device_id3;
- AddUnpairedDevice(&device_id3, DeviceType::kKeyboardMouseCombo);
- // Begin HID detection. |device_id1| should be attempted to be paired with.
- FakeBluetoothHidDetectorDelegate* delegate = StartBluetoothHidDetection();
- EXPECT_TRUE(IsDiscoverySessionActive());
- EXPECT_EQ(1u, GetDevicePairingHandlers().size());
- EXPECT_EQ(device_id1,
- GetDevicePairingHandlers()[0]->current_pairing_device_id());
- EXPECT_EQ(1u, delegate->num_bluetooth_hid_status_changed_calls());
- AssertBluetoothHidDetectionStatus(
- BluetoothHidMetadata(device_id1, BluetoothHidType::kPointer),
- /*pairing_state=*/absl::nullopt);
- // Simulate "RequestPinCode" authorization required. This should cancel the
- // pairing. |device_id2| should be attempted to be paired with.
- GetDevicePairingHandlers()[0]->SimulateRequestPinCode();
- EXPECT_EQ(device_id2,
- GetDevicePairingHandlers()[0]->current_pairing_device_id());
- EXPECT_EQ(3u, delegate->num_bluetooth_hid_status_changed_calls());
- AssertBluetoothHidDetectionStatus(
- BluetoothHidMetadata(device_id2, BluetoothHidType::kPointer),
- /*pairing_state=*/absl::nullopt);
- // Simulate "RequestPasskey" authorization required. This should cancel the
- // pairing. |device_id3| should be attempted to be paired with.
- GetDevicePairingHandlers()[0]->SimulateRequestPasskey();
- EXPECT_EQ(device_id3,
- GetDevicePairingHandlers()[0]->current_pairing_device_id());
- EXPECT_EQ(5u, delegate->num_bluetooth_hid_status_changed_calls());
- AssertBluetoothHidDetectionStatus(
- BluetoothHidMetadata(device_id3, BluetoothHidType::kKeyboardPointerCombo),
- /*pairing_state=*/absl::nullopt);
- // Simulate "ConfirmPasskey" authorization required. This should cancel the
- // pairing.
- GetDevicePairingHandlers()[0]->SimulateConfirmPasskey(kTestPasskey);
- EXPECT_FALSE(GetDevicePairingHandlers()[0]->last_confirm().has_value());
- EXPECT_TRUE(
- GetDevicePairingHandlers()[0]->current_pairing_device_id().empty());
- EXPECT_EQ(6u, delegate->num_bluetooth_hid_status_changed_calls());
- AssertBluetoothHidDetectionStatus(
- /*current_pairing_device=*/absl::nullopt,
- /*pairing_state=*/absl::nullopt);
- StopBluetoothHidDetection(/*is_using_bluetooth=*/false);
- AssertBluetoothPairingAttemptsCount(/*bucket=*/3, /*count=*/1,
- /*total_count=*/1);
- }
- TEST_F(BluetoothHidDetectorImplTest, AddDevice_AuthorizePairingAuth) {
- std::string device_id;
- AddUnpairedDevice(&device_id, DeviceType::kKeyboard);
- // Begin HID detection. |device_id| should be attempted to be paired with.
- FakeBluetoothHidDetectorDelegate* delegate = StartBluetoothHidDetection();
- EXPECT_TRUE(IsDiscoverySessionActive());
- EXPECT_EQ(1u, GetDevicePairingHandlers().size());
- EXPECT_EQ(device_id,
- GetDevicePairingHandlers()[0]->current_pairing_device_id());
- EXPECT_EQ(1u, delegate->num_bluetooth_hid_status_changed_calls());
- AssertBluetoothHidDetectionStatus(
- BluetoothHidMetadata(device_id, BluetoothHidType::kKeyboard),
- /*pairing_state=*/absl::nullopt);
- EXPECT_FALSE(GetDevicePairingHandlers()[0]->last_confirm());
- // Simulate "AuthorizePairing" authorization required. The pairing should be
- // automatically authorized. BluetoothHidDetectorImpl won't move onto the next
- // device because the device has not been registered as connected yet.
- GetDevicePairingHandlers()[0]->SimulateAuthorizePairing();
- EXPECT_TRUE(GetDevicePairingHandlers()[0]->last_confirm().has_value());
- EXPECT_TRUE(GetDevicePairingHandlers()[0]->last_confirm().value());
- EXPECT_TRUE(
- GetDevicePairingHandlers()[0]->current_pairing_device_id().empty());
- EXPECT_EQ(1u, delegate->num_bluetooth_hid_status_changed_calls());
- AssertBluetoothHidDetectionStatus(
- BluetoothHidMetadata(device_id, BluetoothHidType::kKeyboard),
- /*pairing_state=*/absl::nullopt);
- // Mock the device being registered as connected.
- SetInputDevicesStatus(
- {.pointer_is_missing = true, .keyboard_is_missing = false});
- EXPECT_TRUE(
- GetDevicePairingHandlers()[0]->current_pairing_device_id().empty());
- EXPECT_EQ(2u, delegate->num_bluetooth_hid_status_changed_calls());
- AssertBluetoothHidDetectionStatus(
- /*current_pairing_device=*/absl::nullopt,
- /*pairing_state=*/absl::nullopt);
- StopBluetoothHidDetection(/*is_using_bluetooth=*/false);
- AssertBluetoothPairingAttemptsCount(/*bucket=*/1, /*count=*/1,
- /*total_count=*/1);
- }
- TEST_F(BluetoothHidDetectorImplTest, AddDevice_DisplayCodeAuths) {
- std::string device_id1;
- AddUnpairedDevice(&device_id1, DeviceType::kKeyboard);
- std::string device_id2;
- AddUnpairedDevice(&device_id2, DeviceType::kMouse);
- // Begin HID detection. |device_id1| should be attempted to be paired with.
- FakeBluetoothHidDetectorDelegate* delegate = StartBluetoothHidDetection();
- EXPECT_TRUE(IsDiscoverySessionActive());
- EXPECT_EQ(1u, GetDevicePairingHandlers().size());
- EXPECT_EQ(device_id1,
- GetDevicePairingHandlers()[0]->current_pairing_device_id());
- EXPECT_EQ(1u, delegate->num_bluetooth_hid_status_changed_calls());
- AssertBluetoothHidDetectionStatus(
- BluetoothHidMetadata(device_id1, BluetoothHidType::kKeyboard),
- /*pairing_state=*/absl::nullopt);
- // Simulate "DisplayPinCode" authorization required.
- GetDevicePairingHandlers()[0]->SimulateDisplayPinCode(kTestPinCode);
- EXPECT_EQ(device_id1,
- GetDevicePairingHandlers()[0]->current_pairing_device_id());
- EXPECT_EQ(2u, delegate->num_bluetooth_hid_status_changed_calls());
- AssertBluetoothHidDetectionStatus(
- BluetoothHidMetadata(device_id1, BluetoothHidType::kKeyboard),
- BluetoothHidPairingState(kTestPinCode, /*num_keys_entered=*/0u));
- // Simulate keys being entered consecutively. The delegate should be informed
- // each time.
- for (uint32_t num_keys_entered = 1;
- num_keys_entered <= std::strlen(kTestPinCode); num_keys_entered++) {
- GetDevicePairingHandlers()[0]->SimulateKeysEntered(num_keys_entered);
- EXPECT_EQ(device_id1,
- GetDevicePairingHandlers()[0]->current_pairing_device_id());
- EXPECT_EQ(2u + num_keys_entered,
- delegate->num_bluetooth_hid_status_changed_calls());
- AssertBluetoothHidDetectionStatus(
- BluetoothHidMetadata(device_id1, BluetoothHidType::kKeyboard),
- BluetoothHidPairingState(kTestPinCode, num_keys_entered));
- }
- EXPECT_EQ(8u, delegate->num_bluetooth_hid_status_changed_calls());
- AssertBluetoothPairingResult(/*success=*/true, /*count=*/0);
- // Mock |device_id1| being paired. BluetoothHidDetectorImpl should not inform
- // the delegate or move to the next device in queue until the input devices
- // status has been updated.
- MockPairDeviceFinished(device_id1, GetDevicePairingHandlers()[0],
- /*failure_reason=*/absl::nullopt);
- EXPECT_EQ(8u, delegate->num_bluetooth_hid_status_changed_calls());
- AssertBluetoothHidDetectionStatus(
- BluetoothHidMetadata(device_id1, BluetoothHidType::kKeyboard),
- BluetoothHidPairingState(kTestPinCode, /*num_keys_entered=*/6u));
- // Mock |device_id1| being registered as connected. |device_id2| should be
- // attempted to be paired with.
- SetInputDevicesStatus(
- {.pointer_is_missing = true, .keyboard_is_missing = false});
- EXPECT_EQ(device_id2,
- GetDevicePairingHandlers()[0]->current_pairing_device_id());
- EXPECT_EQ(10u, delegate->num_bluetooth_hid_status_changed_calls());
- AssertBluetoothHidDetectionStatus(
- BluetoothHidMetadata(device_id2, BluetoothHidType::kPointer),
- /*pairing_state=*/absl::nullopt);
- AssertBluetoothPairingResult(/*success=*/true, /*count=*/1);
- // Simulate "DisplayPasskey" authorization required.
- GetDevicePairingHandlers()[0]->SimulateDisplayPasskey(kTestPasskey);
- EXPECT_EQ(device_id2,
- GetDevicePairingHandlers()[0]->current_pairing_device_id());
- EXPECT_EQ(11u, delegate->num_bluetooth_hid_status_changed_calls());
- AssertBluetoothHidDetectionStatus(
- BluetoothHidMetadata(device_id2, BluetoothHidType::kPointer),
- BluetoothHidPairingState(kTestPinCode, /*num_keys_entered=*/0u));
- // Simulate keys being entered consecutively. The delegate should be informed
- // each time.
- for (uint32_t num_keys_entered = 1; num_keys_entered <= 6u;
- num_keys_entered++) {
- GetDevicePairingHandlers()[0]->SimulateKeysEntered(num_keys_entered);
- EXPECT_EQ(device_id2,
- GetDevicePairingHandlers()[0]->current_pairing_device_id());
- EXPECT_EQ(11u + num_keys_entered,
- delegate->num_bluetooth_hid_status_changed_calls());
- AssertBluetoothHidDetectionStatus(
- BluetoothHidMetadata(device_id2, BluetoothHidType::kPointer),
- BluetoothHidPairingState(kTestPinCode, num_keys_entered));
- }
- EXPECT_EQ(17u, delegate->num_bluetooth_hid_status_changed_calls());
- AssertBluetoothPairingResult(/*success=*/false, /*count=*/0);
- // Mock |device_id2| pairing failing.
- MockPairDeviceFinished(device_id2, GetDevicePairingHandlers()[0],
- device::ConnectionFailureReason::kAuthFailed);
- EXPECT_EQ(18u, delegate->num_bluetooth_hid_status_changed_calls());
- AssertBluetoothHidDetectionStatus(/*current_pairing_device=*/absl::nullopt,
- /*pairing_state=*/absl::nullopt);
- AssertBluetoothPairingResult(/*success=*/false, /*count=*/1);
- StopBluetoothHidDetection(/*is_using_bluetooth=*/false);
- AssertBluetoothPairingAttemptsCount(/*bucket=*/2, /*count=*/1,
- /*total_count=*/1);
- }
- } // namespace ash::hid_detection
|