bluetooth_hid_detector_impl_unittest.cc 50 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173
  1. // Copyright 2022 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "ash/components/hid_detection/bluetooth_hid_detector_impl.h"
  5. #include "ash/constants/ash_features.h"
  6. #include "base/strings/strcat.h"
  7. #include "base/strings/utf_string_conversions.h"
  8. #include "base/test/metrics/histogram_tester.h"
  9. #include "base/test/scoped_feature_list.h"
  10. #include "base/test/task_environment.h"
  11. #include "chromeos/services/bluetooth_config/fake_adapter_state_controller.h"
  12. #include "chromeos/services/bluetooth_config/fake_bluetooth_power_controller.h"
  13. #include "chromeos/services/bluetooth_config/fake_device_cache.h"
  14. #include "chromeos/services/bluetooth_config/fake_device_pairing_handler.h"
  15. #include "chromeos/services/bluetooth_config/fake_discovered_devices_provider.h"
  16. #include "chromeos/services/bluetooth_config/fake_discovery_session_manager.h"
  17. #include "chromeos/services/bluetooth_config/public/mojom/cros_bluetooth_config.mojom.h"
  18. #include "chromeos/services/bluetooth_config/scoped_bluetooth_config_test_helper.h"
  19. #include "testing/gtest/include/gtest/gtest.h"
  20. namespace ash::hid_detection {
  21. namespace {
  22. using ash::hid_detection::BluetoothHidDetector;
  23. using chromeos::bluetooth_config::FakeDevicePairingHandler;
  24. using chromeos::bluetooth_config::mojom::BluetoothDeviceProperties;
  25. using chromeos::bluetooth_config::mojom::BluetoothDevicePropertiesPtr;
  26. using chromeos::bluetooth_config::mojom::BluetoothSystemState;
  27. using chromeos::bluetooth_config::mojom::DeviceType;
  28. using chromeos::bluetooth_config::mojom::PairedBluetoothDeviceProperties;
  29. using chromeos::bluetooth_config::mojom::PairedBluetoothDevicePropertiesPtr;
  30. using BluetoothHidMetadata = BluetoothHidDetector::BluetoothHidMetadata;
  31. using BluetoothHidType = BluetoothHidDetector::BluetoothHidType;
  32. const char kTestPinCode[] = "123456";
  33. const uint32_t kTestPasskey = 123456;
  34. const base::TimeDelta kTestDuration = base::Milliseconds(3000);
  35. class FakeBluetoothHidDetectorDelegate : public BluetoothHidDetector::Delegate {
  36. public:
  37. ~FakeBluetoothHidDetectorDelegate() override = default;
  38. size_t num_bluetooth_hid_status_changed_calls() const {
  39. return num_bluetooth_hid_status_changed_calls_;
  40. }
  41. private:
  42. // BluetoothHidDetector::Delegate:
  43. void OnBluetoothHidStatusChanged() override {
  44. ++num_bluetooth_hid_status_changed_calls_;
  45. }
  46. size_t num_bluetooth_hid_status_changed_calls_ = 0u;
  47. };
  48. } // namespace
  49. class BluetoothHidDetectorImplTest : public testing::Test {
  50. public:
  51. BluetoothHidDetectorImplTest(const BluetoothHidDetectorImplTest&) = delete;
  52. BluetoothHidDetectorImplTest& operator=(const BluetoothHidDetectorImplTest&) =
  53. delete;
  54. protected:
  55. BluetoothHidDetectorImplTest()
  56. : task_environment_(
  57. base::test::SingleThreadTaskEnvironment::MainThreadType::UI,
  58. base::test::TaskEnvironment::TimeSource::MOCK_TIME) {}
  59. ~BluetoothHidDetectorImplTest() override = default;
  60. // testing::Test:
  61. void SetUp() override {
  62. scoped_feature_list_.InitAndEnableFeature(
  63. ash::features::kOobeHidDetectionRevamp);
  64. bluetooth_hid_detector_ = std::make_unique<BluetoothHidDetectorImpl>();
  65. }
  66. void TearDown() override {
  67. // HID detection must be stopped before BluetoothHidDetectorImpl is
  68. // destroyed.
  69. if (IsDiscoverySessionActive())
  70. StopBluetoothHidDetection(/*is_using_bluetooth=*/false);
  71. }
  72. FakeBluetoothHidDetectorDelegate* StartBluetoothHidDetection(
  73. bool pointer_is_missing = true,
  74. bool keyboard_is_missing = true) {
  75. delegates_.push_back(std::make_unique<FakeBluetoothHidDetectorDelegate>());
  76. FakeBluetoothHidDetectorDelegate* delegate = delegates_.back().get();
  77. bluetooth_hid_detector()->StartBluetoothHidDetection(
  78. delegate, {.pointer_is_missing = pointer_is_missing,
  79. .keyboard_is_missing = keyboard_is_missing});
  80. base::RunLoop().RunUntilIdle();
  81. return delegate;
  82. }
  83. void StopBluetoothHidDetection(bool is_using_bluetooth) {
  84. bluetooth_hid_detector()->StopBluetoothHidDetection(is_using_bluetooth);
  85. base::RunLoop().RunUntilIdle();
  86. }
  87. void SetInputDevicesStatus(
  88. BluetoothHidDetector::InputDevicesStatus input_devices_status) {
  89. bluetooth_hid_detector()->SetInputDevicesStatus(input_devices_status);
  90. base::RunLoop().RunUntilIdle();
  91. }
  92. // Simulates Bluetooth being toggled by a UI surface. This sets the state of
  93. // the Bluetooth adapter and persists that state which is restored when HID
  94. // detection finishes.
  95. void SimulateBluetoothToggledByUi(bool enabled) {
  96. scoped_bluetooth_config_test_helper_.fake_bluetooth_power_controller()
  97. ->SetBluetoothEnabledState(enabled);
  98. }
  99. // Sets the state of the Bluetooth adapter without any persistence. This
  100. // simulates the adapter changing without any user interaction.
  101. void SetAdapterState(BluetoothSystemState system_state) {
  102. scoped_bluetooth_config_test_helper_.fake_adapter_state_controller()
  103. ->SetSystemState(system_state);
  104. }
  105. BluetoothSystemState GetAdapterState() {
  106. return scoped_bluetooth_config_test_helper_.fake_adapter_state_controller()
  107. ->GetAdapterState();
  108. }
  109. bool IsDiscoverySessionActive() {
  110. return scoped_bluetooth_config_test_helper_
  111. .fake_discovery_session_manager()
  112. ->IsDiscoverySessionActive();
  113. }
  114. // Updates a Bluetooth system property in order to trigger the
  115. // OnPropertiesUpdated() observer method in BluetoothHidDetectorImpl.
  116. void TriggerOnPropertiesUpdatedCall() {
  117. auto paired_device = PairedBluetoothDeviceProperties::New();
  118. paired_device->device_properties = BluetoothDeviceProperties::New();
  119. std::vector<PairedBluetoothDevicePropertiesPtr> paired_devices;
  120. paired_devices.push_back(mojo::Clone(paired_device));
  121. scoped_bluetooth_config_test_helper_.fake_device_cache()->SetPairedDevices(
  122. std::move(paired_devices));
  123. base::RunLoop().RunUntilIdle();
  124. }
  125. void AddUnpairedDevice(std::string* id_out, DeviceType device_type) {
  126. // We use the number of devices created in this test as the id.
  127. *id_out = base::NumberToString(num_devices_created_);
  128. ++num_devices_created_;
  129. auto device = BluetoothDeviceProperties::New();
  130. device->id = *id_out;
  131. device->public_name = base::UTF8ToUTF16(*id_out);
  132. device->device_type = device_type;
  133. unpaired_devices_.push_back(device.Clone());
  134. UpdateDiscoveredDevicesProviderDevices();
  135. base::RunLoop().RunUntilIdle();
  136. }
  137. void MockPairDeviceFinished(
  138. const std::string& device_id,
  139. FakeDevicePairingHandler* device_pairing_handler,
  140. absl::optional<device::ConnectionFailureReason> failure_reason) {
  141. // Mock time passing to measure pairing duration.
  142. task_environment_.FastForwardBy(kTestDuration);
  143. unpaired_devices_.erase(
  144. std::remove_if(unpaired_devices_.begin(), unpaired_devices_.end(),
  145. [device_id](BluetoothDevicePropertiesPtr const& device) {
  146. return device->id == device_id;
  147. }),
  148. unpaired_devices_.end());
  149. UpdateDiscoveredDevicesProviderDevices();
  150. base::RunLoop().RunUntilIdle();
  151. device_pairing_handler->SimulatePairDeviceFinished(failure_reason);
  152. EXPECT_TRUE(device_pairing_handler->current_pairing_device_id().empty());
  153. }
  154. std::vector<FakeDevicePairingHandler*> GetDevicePairingHandlers() {
  155. return scoped_bluetooth_config_test_helper_
  156. .fake_discovery_session_manager()
  157. ->device_pairing_handlers();
  158. }
  159. void AssertBluetoothHidDetectionStatus(
  160. absl::optional<BluetoothHidDetector::BluetoothHidMetadata>
  161. current_pairing_device,
  162. absl::optional<BluetoothHidPairingState> pairing_state) {
  163. EXPECT_EQ(
  164. current_pairing_device.has_value(),
  165. GetBluetoothHidDetectionStatus().current_pairing_device.has_value());
  166. if (current_pairing_device.has_value()) {
  167. EXPECT_EQ(current_pairing_device->name,
  168. GetBluetoothHidDetectionStatus().current_pairing_device->name);
  169. EXPECT_EQ(current_pairing_device->type,
  170. GetBluetoothHidDetectionStatus().current_pairing_device->type);
  171. }
  172. EXPECT_EQ(pairing_state.has_value(),
  173. GetBluetoothHidDetectionStatus().pairing_state.has_value());
  174. if (pairing_state.has_value()) {
  175. EXPECT_EQ(pairing_state->code,
  176. GetBluetoothHidDetectionStatus().pairing_state->code);
  177. EXPECT_EQ(
  178. pairing_state->num_keys_entered,
  179. GetBluetoothHidDetectionStatus().pairing_state->num_keys_entered);
  180. }
  181. }
  182. void AssertBluetoothPairingResult(bool success, int count) {
  183. histogram_tester_.ExpectTimeBucketCount(
  184. base::StrCat({"OOBE.HidDetectionScreen.BluetoothPairing.Duration.",
  185. success ? "Success" : "Failure"}),
  186. kTestDuration, count);
  187. histogram_tester_.ExpectBucketCount(
  188. "OOBE.HidDetectionScreen.BluetoothPairing.Result", success, count);
  189. }
  190. void AssertBluetoothPairingAttemptsCount(int bucket,
  191. int count,
  192. int total_count) {
  193. histogram_tester_.ExpectBucketCount(
  194. "OOBE.HidDetectionScreen.BluetoothPairingAttempts", bucket, count);
  195. histogram_tester_.ExpectTotalCount(
  196. "OOBE.HidDetectionScreen.BluetoothPairingAttempts", total_count);
  197. }
  198. private:
  199. void UpdateDiscoveredDevicesProviderDevices() {
  200. std::vector<BluetoothDevicePropertiesPtr> unpaired_devices;
  201. for (auto& device : unpaired_devices_) {
  202. unpaired_devices.push_back(device.Clone());
  203. }
  204. scoped_bluetooth_config_test_helper_.fake_discovered_devices_provider()
  205. ->SetDiscoveredDevices(std::move(unpaired_devices));
  206. }
  207. const BluetoothHidDetector::BluetoothHidDetectionStatus
  208. GetBluetoothHidDetectionStatus() {
  209. return bluetooth_hid_detector()->GetBluetoothHidDetectionStatus();
  210. }
  211. BluetoothHidDetectorImpl* bluetooth_hid_detector() {
  212. return bluetooth_hid_detector_.get();
  213. }
  214. base::test::TaskEnvironment task_environment_;
  215. base::test::ScopedFeatureList scoped_feature_list_;
  216. base::HistogramTester histogram_tester_;
  217. std::vector<BluetoothDevicePropertiesPtr> unpaired_devices_;
  218. size_t num_devices_created_ = 0u;
  219. // Delegates because must be retained by the test for when HID
  220. // detection is stopped in TearDown().
  221. std::vector<std::unique_ptr<FakeBluetoothHidDetectorDelegate>> delegates_;
  222. chromeos::bluetooth_config::ScopedBluetoothConfigTestHelper
  223. scoped_bluetooth_config_test_helper_;
  224. std::unique_ptr<hid_detection::BluetoothHidDetectorImpl>
  225. bluetooth_hid_detector_;
  226. };
  227. TEST_F(BluetoothHidDetectorImplTest, StartStopStartDetection_BluetoothEnabled) {
  228. // Start with Bluetooth enabled.
  229. EXPECT_EQ(BluetoothSystemState::kEnabled, GetAdapterState());
  230. EXPECT_FALSE(IsDiscoverySessionActive());
  231. // Trigger an OnPropertiesUpdated() call. Nothing should happen.
  232. TriggerOnPropertiesUpdatedCall();
  233. EXPECT_FALSE(IsDiscoverySessionActive());
  234. // Begin HID detection. Discovery should have started and Bluetooth still
  235. // enabled.
  236. StartBluetoothHidDetection();
  237. EXPECT_TRUE(IsDiscoverySessionActive());
  238. EXPECT_EQ(BluetoothSystemState::kEnabled, GetAdapterState());
  239. // Trigger an OnPropertiesUpdated() call. Nothing should happen.
  240. TriggerOnPropertiesUpdatedCall();
  241. EXPECT_TRUE(IsDiscoverySessionActive());
  242. // Stop HID detection. Discovery should have stopped but Bluetooth still
  243. // enabled.
  244. StopBluetoothHidDetection(/*is_using_bluetooth=*/false);
  245. EXPECT_FALSE(IsDiscoverySessionActive());
  246. EXPECT_EQ(BluetoothSystemState::kEnabled, GetAdapterState());
  247. AssertBluetoothPairingAttemptsCount(/*bucket=*/0, /*count=*/1,
  248. /*total_count=*/1);
  249. // Trigger an OnPropertiesUpdated() call. Nothing should happen.
  250. TriggerOnPropertiesUpdatedCall();
  251. EXPECT_FALSE(IsDiscoverySessionActive());
  252. // Begin HID detection again. Discovery should have started and Bluetooth
  253. // still enabled.
  254. StartBluetoothHidDetection();
  255. EXPECT_TRUE(IsDiscoverySessionActive());
  256. EXPECT_EQ(BluetoothSystemState::kEnabled, GetAdapterState());
  257. }
  258. TEST_F(BluetoothHidDetectorImplTest,
  259. StartStopDetection_BluetoothDisabled_BluetoothUnused) {
  260. // Initiate disabling Bluetooth.
  261. SimulateBluetoothToggledByUi(/*enabled=*/false);
  262. EXPECT_EQ(BluetoothSystemState::kDisabling, GetAdapterState());
  263. // Complete adapter disabling.
  264. SetAdapterState(BluetoothSystemState::kDisabled);
  265. EXPECT_EQ(BluetoothSystemState::kDisabled, GetAdapterState());
  266. // Begin HID detection. The adapter state should switch to enabling.
  267. StartBluetoothHidDetection();
  268. EXPECT_EQ(BluetoothSystemState::kEnabling, GetAdapterState());
  269. EXPECT_FALSE(IsDiscoverySessionActive());
  270. // Mock the adapter becoming unavailable.
  271. SetAdapterState(BluetoothSystemState::kUnavailable);
  272. EXPECT_EQ(BluetoothSystemState::kUnavailable, GetAdapterState());
  273. EXPECT_FALSE(IsDiscoverySessionActive());
  274. // Mock the adapter becoming available again.
  275. SetAdapterState(BluetoothSystemState::kEnabling);
  276. EXPECT_EQ(BluetoothSystemState::kEnabling, GetAdapterState());
  277. EXPECT_FALSE(IsDiscoverySessionActive());
  278. // Mock the adapter enabling. Discovery should have started.
  279. SetAdapterState(BluetoothSystemState::kEnabled);
  280. EXPECT_EQ(BluetoothSystemState::kEnabled, GetAdapterState());
  281. EXPECT_TRUE(IsDiscoverySessionActive());
  282. // Trigger an OnPropertiesUpdated() call. Nothing should happen.
  283. TriggerOnPropertiesUpdatedCall();
  284. // Stop HID detection with no device using Bluetooth. Discovery should have
  285. // stopped and Bluetooth disabled.
  286. StopBluetoothHidDetection(/*is_using_bluetooth=*/false);
  287. EXPECT_FALSE(IsDiscoverySessionActive());
  288. EXPECT_EQ(BluetoothSystemState::kDisabling, GetAdapterState());
  289. }
  290. TEST_F(BluetoothHidDetectorImplTest,
  291. StartStopDetection_BluetoothDisabled_BluetoothUsed) {
  292. // Initiate disabling Bluetooth.
  293. SimulateBluetoothToggledByUi(/*enabled=*/false);
  294. EXPECT_EQ(BluetoothSystemState::kDisabling, GetAdapterState());
  295. // Complete adapter disabling.
  296. SetAdapterState(BluetoothSystemState::kDisabled);
  297. EXPECT_EQ(BluetoothSystemState::kDisabled, GetAdapterState());
  298. // Begin HID detection. The adapter state should switch to enabling.
  299. StartBluetoothHidDetection();
  300. EXPECT_EQ(BluetoothSystemState::kEnabling, GetAdapterState());
  301. EXPECT_FALSE(IsDiscoverySessionActive());
  302. // Stop HID detection with Bluetooth being used by a device. Discovery should
  303. // have stopped but the adapter state remained the same.
  304. StopBluetoothHidDetection(/*is_using_bluetooth=*/true);
  305. EXPECT_FALSE(IsDiscoverySessionActive());
  306. EXPECT_EQ(BluetoothSystemState::kEnabling, GetAdapterState());
  307. }
  308. TEST_F(BluetoothHidDetectorImplTest, StartDetection_BluetoothUnavailable) {
  309. // Set Bluetooth to unavailable.
  310. SetAdapterState(BluetoothSystemState::kUnavailable);
  311. EXPECT_EQ(BluetoothSystemState::kUnavailable, GetAdapterState());
  312. // Begin HID detection.
  313. StartBluetoothHidDetection();
  314. EXPECT_FALSE(IsDiscoverySessionActive());
  315. // Set Bluetooth to enabling.
  316. SetAdapterState(BluetoothSystemState::kEnabling);
  317. EXPECT_EQ(BluetoothSystemState::kEnabling, GetAdapterState());
  318. // Complete adapter enabling. Discovery should have started.
  319. SetAdapterState(BluetoothSystemState::kEnabled);
  320. EXPECT_EQ(BluetoothSystemState::kEnabled, GetAdapterState());
  321. EXPECT_TRUE(IsDiscoverySessionActive());
  322. }
  323. TEST_F(BluetoothHidDetectorImplTest,
  324. StartDetection_BluetoothDisabledEnabledExternally) {
  325. // Start with Bluetooth enabled.
  326. EXPECT_EQ(BluetoothSystemState::kEnabled, GetAdapterState());
  327. // Begin HID detection. Discovery should have started and Bluetooth still
  328. // enabled.
  329. StartBluetoothHidDetection();
  330. EXPECT_TRUE(IsDiscoverySessionActive());
  331. EXPECT_EQ(BluetoothSystemState::kEnabled, GetAdapterState());
  332. // Mock another client disabling Bluetooth.
  333. SimulateBluetoothToggledByUi(/*enabled=*/false);
  334. EXPECT_EQ(BluetoothSystemState::kDisabling, GetAdapterState());
  335. EXPECT_FALSE(IsDiscoverySessionActive());
  336. // Finish the adapter disabling.
  337. SetAdapterState(BluetoothSystemState::kDisabled);
  338. EXPECT_EQ(BluetoothSystemState::kDisabled, GetAdapterState());
  339. EXPECT_FALSE(IsDiscoverySessionActive());
  340. // Mock another client re-enabling Bluetooth. This should cause
  341. // BluetoothHidDetector to start discovery again.
  342. SimulateBluetoothToggledByUi(/*enabled=*/true);
  343. EXPECT_EQ(BluetoothSystemState::kEnabling, GetAdapterState());
  344. EXPECT_FALSE(IsDiscoverySessionActive());
  345. SetAdapterState(BluetoothSystemState::kEnabled);
  346. EXPECT_EQ(BluetoothSystemState::kEnabled, GetAdapterState());
  347. EXPECT_TRUE(IsDiscoverySessionActive());
  348. }
  349. TEST_F(BluetoothHidDetectorImplTest, AddDevices_TypeNotHid) {
  350. std::string device_id1;
  351. AddUnpairedDevice(&device_id1, DeviceType::kHeadset);
  352. std::string device_id2;
  353. AddUnpairedDevice(&device_id2, DeviceType::kKeyboard);
  354. // Begin HID detection. |device_id1| should not be attempted to be paired
  355. // with.
  356. FakeBluetoothHidDetectorDelegate* delegate = StartBluetoothHidDetection();
  357. EXPECT_TRUE(IsDiscoverySessionActive());
  358. EXPECT_EQ(1u, GetDevicePairingHandlers().size());
  359. EXPECT_EQ(device_id2,
  360. GetDevicePairingHandlers()[0]->current_pairing_device_id());
  361. EXPECT_EQ(1u, delegate->num_bluetooth_hid_status_changed_calls());
  362. AssertBluetoothHidDetectionStatus(
  363. BluetoothHidMetadata(device_id2, BluetoothHidType::kKeyboard),
  364. /*pairing_state=*/absl::nullopt);
  365. StopBluetoothHidDetection(/*is_using_bluetooth=*/false);
  366. AssertBluetoothPairingAttemptsCount(/*bucket=*/1, /*count=*/1,
  367. /*total_count=*/1);
  368. }
  369. TEST_F(BluetoothHidDetectorImplTest, AddDevices_TypeNotMissing) {
  370. std::string device_id1;
  371. AddUnpairedDevice(&device_id1, DeviceType::kMouse);
  372. std::string device_id2;
  373. AddUnpairedDevice(&device_id2, DeviceType::kKeyboard);
  374. // Begin HID detection. |device_id1| should not be attempted to be paired
  375. // with.
  376. FakeBluetoothHidDetectorDelegate* delegate =
  377. StartBluetoothHidDetection(/*is_pointer_missing=*/false);
  378. EXPECT_TRUE(IsDiscoverySessionActive());
  379. EXPECT_EQ(1u, GetDevicePairingHandlers().size());
  380. EXPECT_EQ(device_id2,
  381. GetDevicePairingHandlers()[0]->current_pairing_device_id());
  382. EXPECT_EQ(1u, delegate->num_bluetooth_hid_status_changed_calls());
  383. AssertBluetoothHidDetectionStatus(
  384. BluetoothHidMetadata(device_id2, BluetoothHidType::kKeyboard),
  385. /*pairing_state=*/absl::nullopt);
  386. StopBluetoothHidDetection(/*is_using_bluetooth=*/false);
  387. AssertBluetoothPairingAttemptsCount(/*bucket=*/1, /*count=*/1,
  388. /*total_count=*/1);
  389. }
  390. TEST_F(BluetoothHidDetectorImplTest, AddDevices_NoTypeMissing) {
  391. std::string device_id1;
  392. AddUnpairedDevice(&device_id1, DeviceType::kMouse);
  393. std::string device_id2;
  394. AddUnpairedDevice(&device_id2, DeviceType::kKeyboard);
  395. // Begin HID detection with no types missing. No device should be attempted to
  396. // be paired with.
  397. FakeBluetoothHidDetectorDelegate* delegate = StartBluetoothHidDetection(
  398. /*is_pointer_missing=*/false, /*is_keyboard_missing=*/false);
  399. EXPECT_TRUE(IsDiscoverySessionActive());
  400. EXPECT_EQ(1u, GetDevicePairingHandlers().size());
  401. EXPECT_TRUE(
  402. GetDevicePairingHandlers()[0]->current_pairing_device_id().empty());
  403. EXPECT_EQ(0u, delegate->num_bluetooth_hid_status_changed_calls());
  404. AssertBluetoothHidDetectionStatus(
  405. /*current_pairing_device=*/absl::nullopt,
  406. /*pairing_state=*/absl::nullopt);
  407. // Mock the pointer disconnecting and add another device to trigger
  408. // OnDiscoveredDevicesListChanged(). |device_id1| should be attempted to be
  409. // paired with.
  410. SetInputDevicesStatus(
  411. {.pointer_is_missing = true, .keyboard_is_missing = false});
  412. std::string device_id3;
  413. AddUnpairedDevice(&device_id3, DeviceType::kMouse);
  414. EXPECT_EQ(device_id1,
  415. GetDevicePairingHandlers()[0]->current_pairing_device_id());
  416. EXPECT_EQ(1u, delegate->num_bluetooth_hid_status_changed_calls());
  417. AssertBluetoothHidDetectionStatus(
  418. BluetoothHidMetadata(device_id1, BluetoothHidType::kPointer),
  419. /*pairing_state=*/absl::nullopt);
  420. StopBluetoothHidDetection(/*is_using_bluetooth=*/false);
  421. AssertBluetoothPairingAttemptsCount(/*bucket=*/1, /*count=*/1,
  422. /*total_count=*/1);
  423. }
  424. TEST_F(BluetoothHidDetectorImplTest,
  425. AddDevices_SeriallyAfterStartingDetection) {
  426. FakeBluetoothHidDetectorDelegate* delegate = StartBluetoothHidDetection();
  427. EXPECT_TRUE(IsDiscoverySessionActive());
  428. EXPECT_EQ(1u, GetDevicePairingHandlers().size());
  429. EXPECT_TRUE(
  430. GetDevicePairingHandlers()[0]->current_pairing_device_id().empty());
  431. EXPECT_EQ(0u, delegate->num_bluetooth_hid_status_changed_calls());
  432. AssertBluetoothHidDetectionStatus(
  433. /*current_pairing_device=*/absl::nullopt,
  434. /*pairing_state=*/absl::nullopt);
  435. std::string device_id1;
  436. AddUnpairedDevice(&device_id1, DeviceType::kTablet);
  437. EXPECT_EQ(device_id1,
  438. GetDevicePairingHandlers()[0]->current_pairing_device_id());
  439. EXPECT_EQ(1u, delegate->num_bluetooth_hid_status_changed_calls());
  440. AssertBluetoothHidDetectionStatus(
  441. BluetoothHidMetadata(device_id1, BluetoothHidType::kPointer),
  442. /*pairing_state=*/absl::nullopt);
  443. AssertBluetoothPairingResult(/*success=*/true, /*count=*/0);
  444. // Mock |device_id1| being paired. BluetoothHidDetectorImpl should not inform
  445. // the delegate or move to the next device in queue until the input devices
  446. // status has been updated.
  447. MockPairDeviceFinished(device_id1, GetDevicePairingHandlers()[0],
  448. /*failure_reason=*/absl::nullopt);
  449. EXPECT_EQ(1u, delegate->num_bluetooth_hid_status_changed_calls());
  450. AssertBluetoothHidDetectionStatus(
  451. BluetoothHidMetadata(device_id1, BluetoothHidType::kPointer),
  452. /*pairing_state=*/absl::nullopt);
  453. // Mock |device_id1| being registered as connected. The next device in the
  454. // queue should now be processed.
  455. SetInputDevicesStatus(
  456. {.pointer_is_missing = false, .keyboard_is_missing = true});
  457. EXPECT_TRUE(
  458. GetDevicePairingHandlers()[0]->current_pairing_device_id().empty());
  459. EXPECT_EQ(2u, delegate->num_bluetooth_hid_status_changed_calls());
  460. AssertBluetoothHidDetectionStatus(
  461. /*current_pairing_device=*/absl::nullopt,
  462. /*pairing_state=*/absl::nullopt);
  463. AssertBluetoothPairingResult(/*success=*/true, /*count=*/1);
  464. std::string device_id2;
  465. AddUnpairedDevice(&device_id2, DeviceType::kKeyboard);
  466. EXPECT_EQ(device_id2,
  467. GetDevicePairingHandlers()[0]->current_pairing_device_id());
  468. EXPECT_EQ(3u, delegate->num_bluetooth_hid_status_changed_calls());
  469. AssertBluetoothHidDetectionStatus(
  470. BluetoothHidMetadata(device_id2, BluetoothHidType::kKeyboard),
  471. /*pairing_state=*/absl::nullopt);
  472. StopBluetoothHidDetection(/*is_using_bluetooth=*/false);
  473. AssertBluetoothPairingAttemptsCount(/*bucket=*/2, /*count=*/1,
  474. /*total_count=*/1);
  475. }
  476. TEST_F(BluetoothHidDetectorImplTest, AddDevices_BatchAfterStartingDetection) {
  477. FakeBluetoothHidDetectorDelegate* delegate = StartBluetoothHidDetection();
  478. EXPECT_TRUE(IsDiscoverySessionActive());
  479. EXPECT_EQ(1u, GetDevicePairingHandlers().size());
  480. EXPECT_TRUE(
  481. GetDevicePairingHandlers()[0]->current_pairing_device_id().empty());
  482. EXPECT_EQ(0u, delegate->num_bluetooth_hid_status_changed_calls());
  483. AssertBluetoothHidDetectionStatus(
  484. /*current_pairing_device=*/absl::nullopt,
  485. /*pairing_state=*/absl::nullopt);
  486. std::string device_id1;
  487. AddUnpairedDevice(&device_id1, DeviceType::kMouse);
  488. EXPECT_EQ(device_id1,
  489. GetDevicePairingHandlers()[0]->current_pairing_device_id());
  490. EXPECT_EQ(1u, delegate->num_bluetooth_hid_status_changed_calls());
  491. AssertBluetoothHidDetectionStatus(
  492. BluetoothHidMetadata(device_id1, BluetoothHidType::kPointer),
  493. /*pairing_state=*/absl::nullopt);
  494. std::string device_id2;
  495. AddUnpairedDevice(&device_id2, DeviceType::kKeyboardMouseCombo);
  496. EXPECT_EQ(1u, delegate->num_bluetooth_hid_status_changed_calls());
  497. AssertBluetoothPairingResult(/*success=*/true, /*count=*/0);
  498. // Mock |device_id1| being paired. BluetoothHidDetectorImpl should not inform
  499. // the delegate or move to the next device in queue until the input devices
  500. // status has been updated.
  501. MockPairDeviceFinished(device_id1, GetDevicePairingHandlers()[0],
  502. /*failure_reason=*/absl::nullopt);
  503. EXPECT_EQ(1u, delegate->num_bluetooth_hid_status_changed_calls());
  504. AssertBluetoothHidDetectionStatus(
  505. BluetoothHidMetadata(device_id1, BluetoothHidType::kPointer),
  506. /*pairing_state=*/absl::nullopt);
  507. // Mock |device_id1| being registered as connected. |device_id2| should be
  508. // attempted to be paired with.
  509. SetInputDevicesStatus(
  510. {.pointer_is_missing = false, .keyboard_is_missing = true});
  511. EXPECT_EQ(device_id2,
  512. GetDevicePairingHandlers()[0]->current_pairing_device_id());
  513. EXPECT_EQ(3u, delegate->num_bluetooth_hid_status_changed_calls());
  514. AssertBluetoothPairingResult(/*success=*/true, /*count=*/1);
  515. AssertBluetoothHidDetectionStatus(
  516. BluetoothHidMetadata(device_id2, BluetoothHidType::kKeyboardPointerCombo),
  517. /*pairing_state=*/absl::nullopt);
  518. // Mock |device_id2| being registered as connected. Two devices should be
  519. // paired successfully.
  520. MockPairDeviceFinished(device_id2, GetDevicePairingHandlers()[0],
  521. /*failure_reason=*/absl::nullopt);
  522. EXPECT_EQ(3u, delegate->num_bluetooth_hid_status_changed_calls());
  523. AssertBluetoothHidDetectionStatus(
  524. BluetoothHidMetadata(device_id2, BluetoothHidType::kKeyboardPointerCombo),
  525. /*pairing_state=*/absl::nullopt);
  526. SetInputDevicesStatus(
  527. {.pointer_is_missing = false, .keyboard_is_missing = false});
  528. EXPECT_EQ(4u, delegate->num_bluetooth_hid_status_changed_calls());
  529. AssertBluetoothHidDetectionStatus(
  530. /*current_pairing_device=*/absl::nullopt,
  531. /*pairing_state=*/absl::nullopt);
  532. AssertBluetoothPairingResult(/*success=*/true, /*count=*/2);
  533. StopBluetoothHidDetection(/*is_using_bluetooth=*/false);
  534. AssertBluetoothPairingAttemptsCount(/*bucket=*/2, /*count=*/1,
  535. /*total_count=*/1);
  536. }
  537. TEST_F(BluetoothHidDetectorImplTest,
  538. AddDevices_BeforeStartingDetectionSameType) {
  539. std::string device_id1;
  540. AddUnpairedDevice(&device_id1, DeviceType::kMouse);
  541. std::string device_id2;
  542. AddUnpairedDevice(&device_id2, DeviceType::kMouse);
  543. std::string device_id3;
  544. AddUnpairedDevice(&device_id3, DeviceType::kKeyboard);
  545. // Begin HID detection. |device_id1| should be attempted to be paired with.
  546. FakeBluetoothHidDetectorDelegate* delegate = StartBluetoothHidDetection();
  547. EXPECT_TRUE(IsDiscoverySessionActive());
  548. EXPECT_EQ(1u, GetDevicePairingHandlers().size());
  549. EXPECT_EQ(device_id1,
  550. GetDevicePairingHandlers()[0]->current_pairing_device_id());
  551. EXPECT_EQ(1u, delegate->num_bluetooth_hid_status_changed_calls());
  552. AssertBluetoothHidDetectionStatus(
  553. BluetoothHidMetadata(device_id1, BluetoothHidType::kPointer),
  554. /*pairing_state=*/absl::nullopt);
  555. AssertBluetoothPairingResult(/*success=*/true, /*count=*/0);
  556. // Mock |device_id1| being paired. BluetoothHidDetectorImpl should not inform
  557. // the delegate or move to the next device in queue until the input devices
  558. // status has been updated.
  559. MockPairDeviceFinished(device_id1, GetDevicePairingHandlers()[0],
  560. /*failure_reason=*/absl::nullopt);
  561. EXPECT_EQ(1u, delegate->num_bluetooth_hid_status_changed_calls());
  562. AssertBluetoothHidDetectionStatus(
  563. BluetoothHidMetadata(device_id1, BluetoothHidType::kPointer),
  564. /*pairing_state=*/absl::nullopt);
  565. // Mock |device_id1| being registered as connected. |device_id3| should be
  566. // attempted to be paired with.
  567. SetInputDevicesStatus(
  568. {.pointer_is_missing = false, .keyboard_is_missing = true});
  569. EXPECT_EQ(device_id3,
  570. GetDevicePairingHandlers()[0]->current_pairing_device_id());
  571. EXPECT_EQ(3u, delegate->num_bluetooth_hid_status_changed_calls());
  572. AssertBluetoothHidDetectionStatus(
  573. BluetoothHidMetadata(device_id3, BluetoothHidType::kKeyboard),
  574. /*pairing_state=*/absl::nullopt);
  575. AssertBluetoothPairingResult(/*success=*/true, /*count=*/1);
  576. AssertBluetoothPairingResult(/*success=*/false, /*count=*/0);
  577. // Mock |device_id3| pairing failing. BluetoothHidDetectorImpl should move to
  578. // the next device in the queue immediately.
  579. MockPairDeviceFinished(device_id3, GetDevicePairingHandlers()[0],
  580. device::ConnectionFailureReason::kFailed);
  581. EXPECT_EQ(4u, delegate->num_bluetooth_hid_status_changed_calls());
  582. AssertBluetoothHidDetectionStatus(
  583. /*current_pairing_device=*/absl::nullopt,
  584. /*pairing_state=*/absl::nullopt);
  585. AssertBluetoothPairingResult(/*success=*/false, /*count=*/1);
  586. StopBluetoothHidDetection(/*is_using_bluetooth=*/false);
  587. AssertBluetoothPairingAttemptsCount(/*bucket=*/2, /*count=*/1,
  588. /*total_count=*/1);
  589. }
  590. TEST_F(BluetoothHidDetectorImplTest, DisconnectDevice) {
  591. FakeBluetoothHidDetectorDelegate* delegate = StartBluetoothHidDetection();
  592. EXPECT_TRUE(IsDiscoverySessionActive());
  593. EXPECT_EQ(1u, GetDevicePairingHandlers().size());
  594. EXPECT_TRUE(
  595. GetDevicePairingHandlers()[0]->current_pairing_device_id().empty());
  596. EXPECT_EQ(0u, delegate->num_bluetooth_hid_status_changed_calls());
  597. AssertBluetoothHidDetectionStatus(
  598. /*current_pairing_device=*/absl::nullopt,
  599. /*pairing_state=*/absl::nullopt);
  600. // Set both devices to connected.
  601. SetInputDevicesStatus(
  602. {.pointer_is_missing = false, .keyboard_is_missing = false});
  603. EXPECT_EQ(0u, delegate->num_bluetooth_hid_status_changed_calls());
  604. AssertBluetoothHidDetectionStatus(
  605. /*current_pairing_device=*/absl::nullopt,
  606. /*pairing_state=*/absl::nullopt);
  607. // Add a discovered device. Nothing should happen.
  608. std::string device_id1;
  609. AddUnpairedDevice(&device_id1, DeviceType::kMouse);
  610. EXPECT_TRUE(
  611. GetDevicePairingHandlers()[0]->current_pairing_device_id().empty());
  612. EXPECT_EQ(0u, delegate->num_bluetooth_hid_status_changed_calls());
  613. AssertBluetoothHidDetectionStatus(
  614. /*current_pairing_device=*/absl::nullopt,
  615. /*pairing_state=*/absl::nullopt);
  616. // Mock the pointer no longer being connected.
  617. SetInputDevicesStatus(
  618. {.pointer_is_missing = true, .keyboard_is_missing = false});
  619. // Add another device to trigger OnDiscoveredDevicesListChanged().
  620. std::string device_id2;
  621. AddUnpairedDevice(&device_id2, DeviceType::kKeyboard);
  622. EXPECT_EQ(device_id1,
  623. GetDevicePairingHandlers()[0]->current_pairing_device_id());
  624. EXPECT_EQ(1u, delegate->num_bluetooth_hid_status_changed_calls());
  625. AssertBluetoothHidDetectionStatus(
  626. BluetoothHidMetadata(device_id1, BluetoothHidType::kPointer),
  627. /*pairing_state=*/absl::nullopt);
  628. StopBluetoothHidDetection(/*is_using_bluetooth=*/false);
  629. AssertBluetoothPairingAttemptsCount(/*bucket=*/1, /*count=*/1,
  630. /*total_count=*/1);
  631. }
  632. TEST_F(BluetoothHidDetectorImplTest, ConnectDeviceTypeDuringPairing) {
  633. std::string device_id1;
  634. AddUnpairedDevice(&device_id1, DeviceType::kMouse);
  635. std::string device_id2;
  636. AddUnpairedDevice(&device_id2, DeviceType::kKeyboard);
  637. // Begin HID detection. |device_id1| should be attempted to be paired with.
  638. FakeBluetoothHidDetectorDelegate* delegate = StartBluetoothHidDetection();
  639. EXPECT_TRUE(IsDiscoverySessionActive());
  640. EXPECT_EQ(1u, GetDevicePairingHandlers().size());
  641. EXPECT_EQ(device_id1,
  642. GetDevicePairingHandlers()[0]->current_pairing_device_id());
  643. EXPECT_EQ(1u, delegate->num_bluetooth_hid_status_changed_calls());
  644. AssertBluetoothHidDetectionStatus(
  645. BluetoothHidMetadata(device_id1, BluetoothHidType::kPointer),
  646. /*pairing_state=*/absl::nullopt);
  647. // Mock a keyboard being connected. Nothing should happen.
  648. SetInputDevicesStatus(
  649. {.pointer_is_missing = true, .keyboard_is_missing = false});
  650. EXPECT_EQ(device_id1,
  651. GetDevicePairingHandlers()[0]->current_pairing_device_id());
  652. EXPECT_EQ(1u, delegate->num_bluetooth_hid_status_changed_calls());
  653. AssertBluetoothHidDetectionStatus(
  654. BluetoothHidMetadata(device_id1, BluetoothHidType::kPointer),
  655. /*pairing_state=*/absl::nullopt);
  656. // Mock keyboard being disconnected. Nothing should happen.
  657. SetInputDevicesStatus(
  658. {.pointer_is_missing = true, .keyboard_is_missing = true});
  659. EXPECT_EQ(device_id1,
  660. GetDevicePairingHandlers()[0]->current_pairing_device_id());
  661. EXPECT_EQ(1u, delegate->num_bluetooth_hid_status_changed_calls());
  662. AssertBluetoothHidDetectionStatus(
  663. BluetoothHidMetadata(device_id1, BluetoothHidType::kPointer),
  664. /*pairing_state=*/absl::nullopt);
  665. // Mock a pointer being connected. This should cancel pairing with
  666. // |device_id1|.
  667. SetInputDevicesStatus(
  668. {.pointer_is_missing = false, .keyboard_is_missing = true});
  669. EXPECT_EQ(device_id2,
  670. GetDevicePairingHandlers()[0]->current_pairing_device_id());
  671. EXPECT_EQ(3u, delegate->num_bluetooth_hid_status_changed_calls());
  672. AssertBluetoothHidDetectionStatus(
  673. BluetoothHidMetadata(device_id2, BluetoothHidType::kKeyboard),
  674. /*pairing_state=*/absl::nullopt);
  675. StopBluetoothHidDetection(/*is_using_bluetooth=*/false);
  676. AssertBluetoothPairingAttemptsCount(/*bucket=*/2, /*count=*/1,
  677. /*total_count=*/1);
  678. }
  679. TEST_F(BluetoothHidDetectorImplTest,
  680. ConnectDeviceTypeDuringKeyboardMouseComboPairing) {
  681. std::string device_id1;
  682. AddUnpairedDevice(&device_id1, DeviceType::kKeyboardMouseCombo);
  683. std::string device_id2;
  684. AddUnpairedDevice(&device_id2, DeviceType::kKeyboard);
  685. // Begin HID detection. |device_id1| should be attempted to be paired with.
  686. FakeBluetoothHidDetectorDelegate* delegate = StartBluetoothHidDetection();
  687. EXPECT_TRUE(IsDiscoverySessionActive());
  688. EXPECT_EQ(1u, GetDevicePairingHandlers().size());
  689. EXPECT_EQ(device_id1,
  690. GetDevicePairingHandlers()[0]->current_pairing_device_id());
  691. EXPECT_EQ(1u, delegate->num_bluetooth_hid_status_changed_calls());
  692. AssertBluetoothHidDetectionStatus(
  693. BluetoothHidMetadata(device_id1, BluetoothHidType::kKeyboardPointerCombo),
  694. /*pairing_state=*/absl::nullopt);
  695. // Mock a keyboard being connected. This should not cancel pairing with
  696. // |device_id1|.
  697. SetInputDevicesStatus(
  698. {.pointer_is_missing = true, .keyboard_is_missing = false});
  699. EXPECT_EQ(device_id1,
  700. GetDevicePairingHandlers()[0]->current_pairing_device_id());
  701. EXPECT_EQ(1u, delegate->num_bluetooth_hid_status_changed_calls());
  702. AssertBluetoothHidDetectionStatus(
  703. BluetoothHidMetadata(device_id1, BluetoothHidType::kKeyboardPointerCombo),
  704. /*pairing_state=*/absl::nullopt);
  705. // Mock a pointer also being connected. This should cancel pairing with
  706. // |device_id1|.
  707. SetInputDevicesStatus(
  708. {.pointer_is_missing = false, .keyboard_is_missing = false});
  709. EXPECT_TRUE(
  710. GetDevicePairingHandlers()[0]->current_pairing_device_id().empty());
  711. EXPECT_EQ(2u, delegate->num_bluetooth_hid_status_changed_calls());
  712. AssertBluetoothHidDetectionStatus(
  713. /*current_pairing_device=*/absl::nullopt,
  714. /*pairing_state=*/absl::nullopt);
  715. StopBluetoothHidDetection(/*is_using_bluetooth=*/false);
  716. AssertBluetoothPairingAttemptsCount(/*bucket=*/1, /*count=*/1,
  717. /*total_count=*/1);
  718. }
  719. TEST_F(BluetoothHidDetectorImplTest, AdapterDisablesDuringPairing) {
  720. std::string device_id1;
  721. AddUnpairedDevice(&device_id1, DeviceType::kMouse);
  722. std::string device_id2;
  723. AddUnpairedDevice(&device_id2, DeviceType::kKeyboard);
  724. // Begin HID detection. |device_id1| should be attempted to be paired with.
  725. FakeBluetoothHidDetectorDelegate* delegate = StartBluetoothHidDetection();
  726. EXPECT_TRUE(IsDiscoverySessionActive());
  727. EXPECT_EQ(1u, GetDevicePairingHandlers().size());
  728. EXPECT_EQ(device_id1,
  729. GetDevicePairingHandlers()[0]->current_pairing_device_id());
  730. EXPECT_EQ(1u, delegate->num_bluetooth_hid_status_changed_calls());
  731. AssertBluetoothHidDetectionStatus(
  732. BluetoothHidMetadata(device_id1, BluetoothHidType::kPointer),
  733. /*pairing_state=*/absl::nullopt);
  734. // Simulate "DisplayPasskey" authorization required.
  735. GetDevicePairingHandlers()[0]->SimulateDisplayPasskey(kTestPasskey);
  736. EXPECT_EQ(device_id1,
  737. GetDevicePairingHandlers()[0]->current_pairing_device_id());
  738. EXPECT_EQ(2u, delegate->num_bluetooth_hid_status_changed_calls());
  739. AssertBluetoothHidDetectionStatus(
  740. BluetoothHidMetadata(device_id1, BluetoothHidType::kPointer),
  741. BluetoothHidPairingState(kTestPinCode, /*num_keys_entered=*/0u));
  742. // Mock the adapter disabling.
  743. SetAdapterState(BluetoothSystemState::kDisabled);
  744. EXPECT_FALSE(IsDiscoverySessionActive());
  745. EXPECT_EQ(3u, delegate->num_bluetooth_hid_status_changed_calls());
  746. AssertBluetoothHidDetectionStatus(
  747. /*current_pairing_device=*/absl::nullopt,
  748. /*pairing_state=*/absl::nullopt);
  749. // Mock the adapter re-enabling Bluetooth. This should cause
  750. // BluetoothHidDetector to start discovery again. The first device should be
  751. // attempted to be paired with again.
  752. SetAdapterState(BluetoothSystemState::kEnabled);
  753. EXPECT_TRUE(IsDiscoverySessionActive());
  754. EXPECT_EQ(2u, GetDevicePairingHandlers().size());
  755. EXPECT_EQ(device_id1,
  756. GetDevicePairingHandlers()[1]->current_pairing_device_id());
  757. EXPECT_EQ(4u, delegate->num_bluetooth_hid_status_changed_calls());
  758. AssertBluetoothHidDetectionStatus(
  759. BluetoothHidMetadata(device_id1, BluetoothHidType::kPointer),
  760. /*pairing_state=*/absl::nullopt);
  761. // Simulate "DisplayPincode" authorization required.
  762. GetDevicePairingHandlers()[1]->SimulateDisplayPinCode(kTestPinCode);
  763. EXPECT_EQ(device_id1,
  764. GetDevicePairingHandlers()[1]->current_pairing_device_id());
  765. EXPECT_EQ(5u, delegate->num_bluetooth_hid_status_changed_calls());
  766. AssertBluetoothHidDetectionStatus(
  767. BluetoothHidMetadata(device_id1, BluetoothHidType::kPointer),
  768. BluetoothHidPairingState(kTestPinCode, /*num_keys_entered=*/0u));
  769. StopBluetoothHidDetection(/*is_using_bluetooth=*/false);
  770. AssertBluetoothPairingAttemptsCount(/*bucket=*/2, /*count=*/1,
  771. /*total_count=*/1);
  772. }
  773. TEST_F(BluetoothHidDetectorImplTest, DetectionStopsStartsDuringPairing) {
  774. std::string device_id1;
  775. AddUnpairedDevice(&device_id1, DeviceType::kMouse);
  776. std::string device_id2;
  777. AddUnpairedDevice(&device_id2, DeviceType::kKeyboard);
  778. // Begin HID detection. |device_id1| should be attempted to be paired with.
  779. FakeBluetoothHidDetectorDelegate* delegate1 = StartBluetoothHidDetection();
  780. EXPECT_TRUE(IsDiscoverySessionActive());
  781. EXPECT_EQ(1u, GetDevicePairingHandlers().size());
  782. EXPECT_EQ(device_id1,
  783. GetDevicePairingHandlers()[0]->current_pairing_device_id());
  784. EXPECT_EQ(1u, delegate1->num_bluetooth_hid_status_changed_calls());
  785. AssertBluetoothHidDetectionStatus(
  786. BluetoothHidMetadata(device_id1, BluetoothHidType::kPointer),
  787. /*pairing_state=*/absl::nullopt);
  788. // Simulate "DisplayPincode" authorization required.
  789. GetDevicePairingHandlers()[0]->SimulateDisplayPinCode(kTestPinCode);
  790. EXPECT_EQ(device_id1,
  791. GetDevicePairingHandlers()[0]->current_pairing_device_id());
  792. EXPECT_EQ(2u, delegate1->num_bluetooth_hid_status_changed_calls());
  793. AssertBluetoothHidDetectionStatus(
  794. BluetoothHidMetadata(device_id1, BluetoothHidType::kPointer),
  795. BluetoothHidPairingState(kTestPinCode, /*num_keys_entered=*/0u));
  796. // Stop detection.
  797. StopBluetoothHidDetection(/*is_using_bluetooth=*/false);
  798. AssertBluetoothPairingAttemptsCount(/*bucket=*/1, /*count=*/1,
  799. /*total_count=*/1);
  800. EXPECT_FALSE(IsDiscoverySessionActive());
  801. EXPECT_EQ(3u, delegate1->num_bluetooth_hid_status_changed_calls());
  802. AssertBluetoothHidDetectionStatus(
  803. /*current_pairing_device=*/absl::nullopt,
  804. /*pairing_state=*/absl::nullopt);
  805. // Start detection again. The first device should be attempted to be paired
  806. // with again.
  807. FakeBluetoothHidDetectorDelegate* delegate2 = StartBluetoothHidDetection();
  808. EXPECT_TRUE(IsDiscoverySessionActive());
  809. EXPECT_EQ(2u, GetDevicePairingHandlers().size());
  810. EXPECT_EQ(device_id1,
  811. GetDevicePairingHandlers()[1]->current_pairing_device_id());
  812. EXPECT_EQ(1u, delegate2->num_bluetooth_hid_status_changed_calls());
  813. AssertBluetoothHidDetectionStatus(
  814. BluetoothHidMetadata(device_id1, BluetoothHidType::kPointer),
  815. /*pairing_state=*/absl::nullopt);
  816. // Simulate "DisplayPasskey" authorization required.
  817. GetDevicePairingHandlers()[1]->SimulateDisplayPasskey(kTestPasskey);
  818. EXPECT_EQ(device_id1,
  819. GetDevicePairingHandlers()[1]->current_pairing_device_id());
  820. EXPECT_EQ(2u, delegate2->num_bluetooth_hid_status_changed_calls());
  821. AssertBluetoothHidDetectionStatus(
  822. BluetoothHidMetadata(device_id1, BluetoothHidType::kPointer),
  823. BluetoothHidPairingState(kTestPinCode, /*num_keys_entered=*/0u));
  824. StopBluetoothHidDetection(/*is_using_bluetooth=*/false);
  825. AssertBluetoothPairingAttemptsCount(/*bucket=*/1, /*count=*/2,
  826. /*total_count=*/2);
  827. }
  828. TEST_F(BluetoothHidDetectorImplTest, AddDevices_UnsupportedAuthorizations) {
  829. std::string device_id1;
  830. AddUnpairedDevice(&device_id1, DeviceType::kMouse);
  831. std::string device_id2;
  832. AddUnpairedDevice(&device_id2, DeviceType::kTablet);
  833. std::string device_id3;
  834. AddUnpairedDevice(&device_id3, DeviceType::kKeyboardMouseCombo);
  835. // Begin HID detection. |device_id1| should be attempted to be paired with.
  836. FakeBluetoothHidDetectorDelegate* delegate = StartBluetoothHidDetection();
  837. EXPECT_TRUE(IsDiscoverySessionActive());
  838. EXPECT_EQ(1u, GetDevicePairingHandlers().size());
  839. EXPECT_EQ(device_id1,
  840. GetDevicePairingHandlers()[0]->current_pairing_device_id());
  841. EXPECT_EQ(1u, delegate->num_bluetooth_hid_status_changed_calls());
  842. AssertBluetoothHidDetectionStatus(
  843. BluetoothHidMetadata(device_id1, BluetoothHidType::kPointer),
  844. /*pairing_state=*/absl::nullopt);
  845. // Simulate "RequestPinCode" authorization required. This should cancel the
  846. // pairing. |device_id2| should be attempted to be paired with.
  847. GetDevicePairingHandlers()[0]->SimulateRequestPinCode();
  848. EXPECT_EQ(device_id2,
  849. GetDevicePairingHandlers()[0]->current_pairing_device_id());
  850. EXPECT_EQ(3u, delegate->num_bluetooth_hid_status_changed_calls());
  851. AssertBluetoothHidDetectionStatus(
  852. BluetoothHidMetadata(device_id2, BluetoothHidType::kPointer),
  853. /*pairing_state=*/absl::nullopt);
  854. // Simulate "RequestPasskey" authorization required. This should cancel the
  855. // pairing. |device_id3| should be attempted to be paired with.
  856. GetDevicePairingHandlers()[0]->SimulateRequestPasskey();
  857. EXPECT_EQ(device_id3,
  858. GetDevicePairingHandlers()[0]->current_pairing_device_id());
  859. EXPECT_EQ(5u, delegate->num_bluetooth_hid_status_changed_calls());
  860. AssertBluetoothHidDetectionStatus(
  861. BluetoothHidMetadata(device_id3, BluetoothHidType::kKeyboardPointerCombo),
  862. /*pairing_state=*/absl::nullopt);
  863. // Simulate "ConfirmPasskey" authorization required. This should cancel the
  864. // pairing.
  865. GetDevicePairingHandlers()[0]->SimulateConfirmPasskey(kTestPasskey);
  866. EXPECT_FALSE(GetDevicePairingHandlers()[0]->last_confirm().has_value());
  867. EXPECT_TRUE(
  868. GetDevicePairingHandlers()[0]->current_pairing_device_id().empty());
  869. EXPECT_EQ(6u, delegate->num_bluetooth_hid_status_changed_calls());
  870. AssertBluetoothHidDetectionStatus(
  871. /*current_pairing_device=*/absl::nullopt,
  872. /*pairing_state=*/absl::nullopt);
  873. StopBluetoothHidDetection(/*is_using_bluetooth=*/false);
  874. AssertBluetoothPairingAttemptsCount(/*bucket=*/3, /*count=*/1,
  875. /*total_count=*/1);
  876. }
  877. TEST_F(BluetoothHidDetectorImplTest, AddDevice_AuthorizePairingAuth) {
  878. std::string device_id;
  879. AddUnpairedDevice(&device_id, DeviceType::kKeyboard);
  880. // Begin HID detection. |device_id| should be attempted to be paired with.
  881. FakeBluetoothHidDetectorDelegate* delegate = StartBluetoothHidDetection();
  882. EXPECT_TRUE(IsDiscoverySessionActive());
  883. EXPECT_EQ(1u, GetDevicePairingHandlers().size());
  884. EXPECT_EQ(device_id,
  885. GetDevicePairingHandlers()[0]->current_pairing_device_id());
  886. EXPECT_EQ(1u, delegate->num_bluetooth_hid_status_changed_calls());
  887. AssertBluetoothHidDetectionStatus(
  888. BluetoothHidMetadata(device_id, BluetoothHidType::kKeyboard),
  889. /*pairing_state=*/absl::nullopt);
  890. EXPECT_FALSE(GetDevicePairingHandlers()[0]->last_confirm());
  891. // Simulate "AuthorizePairing" authorization required. The pairing should be
  892. // automatically authorized. BluetoothHidDetectorImpl won't move onto the next
  893. // device because the device has not been registered as connected yet.
  894. GetDevicePairingHandlers()[0]->SimulateAuthorizePairing();
  895. EXPECT_TRUE(GetDevicePairingHandlers()[0]->last_confirm().has_value());
  896. EXPECT_TRUE(GetDevicePairingHandlers()[0]->last_confirm().value());
  897. EXPECT_TRUE(
  898. GetDevicePairingHandlers()[0]->current_pairing_device_id().empty());
  899. EXPECT_EQ(1u, delegate->num_bluetooth_hid_status_changed_calls());
  900. AssertBluetoothHidDetectionStatus(
  901. BluetoothHidMetadata(device_id, BluetoothHidType::kKeyboard),
  902. /*pairing_state=*/absl::nullopt);
  903. // Mock the device being registered as connected.
  904. SetInputDevicesStatus(
  905. {.pointer_is_missing = true, .keyboard_is_missing = false});
  906. EXPECT_TRUE(
  907. GetDevicePairingHandlers()[0]->current_pairing_device_id().empty());
  908. EXPECT_EQ(2u, delegate->num_bluetooth_hid_status_changed_calls());
  909. AssertBluetoothHidDetectionStatus(
  910. /*current_pairing_device=*/absl::nullopt,
  911. /*pairing_state=*/absl::nullopt);
  912. StopBluetoothHidDetection(/*is_using_bluetooth=*/false);
  913. AssertBluetoothPairingAttemptsCount(/*bucket=*/1, /*count=*/1,
  914. /*total_count=*/1);
  915. }
  916. TEST_F(BluetoothHidDetectorImplTest, AddDevice_DisplayCodeAuths) {
  917. std::string device_id1;
  918. AddUnpairedDevice(&device_id1, DeviceType::kKeyboard);
  919. std::string device_id2;
  920. AddUnpairedDevice(&device_id2, DeviceType::kMouse);
  921. // Begin HID detection. |device_id1| should be attempted to be paired with.
  922. FakeBluetoothHidDetectorDelegate* delegate = StartBluetoothHidDetection();
  923. EXPECT_TRUE(IsDiscoverySessionActive());
  924. EXPECT_EQ(1u, GetDevicePairingHandlers().size());
  925. EXPECT_EQ(device_id1,
  926. GetDevicePairingHandlers()[0]->current_pairing_device_id());
  927. EXPECT_EQ(1u, delegate->num_bluetooth_hid_status_changed_calls());
  928. AssertBluetoothHidDetectionStatus(
  929. BluetoothHidMetadata(device_id1, BluetoothHidType::kKeyboard),
  930. /*pairing_state=*/absl::nullopt);
  931. // Simulate "DisplayPinCode" authorization required.
  932. GetDevicePairingHandlers()[0]->SimulateDisplayPinCode(kTestPinCode);
  933. EXPECT_EQ(device_id1,
  934. GetDevicePairingHandlers()[0]->current_pairing_device_id());
  935. EXPECT_EQ(2u, delegate->num_bluetooth_hid_status_changed_calls());
  936. AssertBluetoothHidDetectionStatus(
  937. BluetoothHidMetadata(device_id1, BluetoothHidType::kKeyboard),
  938. BluetoothHidPairingState(kTestPinCode, /*num_keys_entered=*/0u));
  939. // Simulate keys being entered consecutively. The delegate should be informed
  940. // each time.
  941. for (uint32_t num_keys_entered = 1;
  942. num_keys_entered <= std::strlen(kTestPinCode); num_keys_entered++) {
  943. GetDevicePairingHandlers()[0]->SimulateKeysEntered(num_keys_entered);
  944. EXPECT_EQ(device_id1,
  945. GetDevicePairingHandlers()[0]->current_pairing_device_id());
  946. EXPECT_EQ(2u + num_keys_entered,
  947. delegate->num_bluetooth_hid_status_changed_calls());
  948. AssertBluetoothHidDetectionStatus(
  949. BluetoothHidMetadata(device_id1, BluetoothHidType::kKeyboard),
  950. BluetoothHidPairingState(kTestPinCode, num_keys_entered));
  951. }
  952. EXPECT_EQ(8u, delegate->num_bluetooth_hid_status_changed_calls());
  953. AssertBluetoothPairingResult(/*success=*/true, /*count=*/0);
  954. // Mock |device_id1| being paired. BluetoothHidDetectorImpl should not inform
  955. // the delegate or move to the next device in queue until the input devices
  956. // status has been updated.
  957. MockPairDeviceFinished(device_id1, GetDevicePairingHandlers()[0],
  958. /*failure_reason=*/absl::nullopt);
  959. EXPECT_EQ(8u, delegate->num_bluetooth_hid_status_changed_calls());
  960. AssertBluetoothHidDetectionStatus(
  961. BluetoothHidMetadata(device_id1, BluetoothHidType::kKeyboard),
  962. BluetoothHidPairingState(kTestPinCode, /*num_keys_entered=*/6u));
  963. // Mock |device_id1| being registered as connected. |device_id2| should be
  964. // attempted to be paired with.
  965. SetInputDevicesStatus(
  966. {.pointer_is_missing = true, .keyboard_is_missing = false});
  967. EXPECT_EQ(device_id2,
  968. GetDevicePairingHandlers()[0]->current_pairing_device_id());
  969. EXPECT_EQ(10u, delegate->num_bluetooth_hid_status_changed_calls());
  970. AssertBluetoothHidDetectionStatus(
  971. BluetoothHidMetadata(device_id2, BluetoothHidType::kPointer),
  972. /*pairing_state=*/absl::nullopt);
  973. AssertBluetoothPairingResult(/*success=*/true, /*count=*/1);
  974. // Simulate "DisplayPasskey" authorization required.
  975. GetDevicePairingHandlers()[0]->SimulateDisplayPasskey(kTestPasskey);
  976. EXPECT_EQ(device_id2,
  977. GetDevicePairingHandlers()[0]->current_pairing_device_id());
  978. EXPECT_EQ(11u, delegate->num_bluetooth_hid_status_changed_calls());
  979. AssertBluetoothHidDetectionStatus(
  980. BluetoothHidMetadata(device_id2, BluetoothHidType::kPointer),
  981. BluetoothHidPairingState(kTestPinCode, /*num_keys_entered=*/0u));
  982. // Simulate keys being entered consecutively. The delegate should be informed
  983. // each time.
  984. for (uint32_t num_keys_entered = 1; num_keys_entered <= 6u;
  985. num_keys_entered++) {
  986. GetDevicePairingHandlers()[0]->SimulateKeysEntered(num_keys_entered);
  987. EXPECT_EQ(device_id2,
  988. GetDevicePairingHandlers()[0]->current_pairing_device_id());
  989. EXPECT_EQ(11u + num_keys_entered,
  990. delegate->num_bluetooth_hid_status_changed_calls());
  991. AssertBluetoothHidDetectionStatus(
  992. BluetoothHidMetadata(device_id2, BluetoothHidType::kPointer),
  993. BluetoothHidPairingState(kTestPinCode, num_keys_entered));
  994. }
  995. EXPECT_EQ(17u, delegate->num_bluetooth_hid_status_changed_calls());
  996. AssertBluetoothPairingResult(/*success=*/false, /*count=*/0);
  997. // Mock |device_id2| pairing failing.
  998. MockPairDeviceFinished(device_id2, GetDevicePairingHandlers()[0],
  999. device::ConnectionFailureReason::kAuthFailed);
  1000. EXPECT_EQ(18u, delegate->num_bluetooth_hid_status_changed_calls());
  1001. AssertBluetoothHidDetectionStatus(/*current_pairing_device=*/absl::nullopt,
  1002. /*pairing_state=*/absl::nullopt);
  1003. AssertBluetoothPairingResult(/*success=*/false, /*count=*/1);
  1004. StopBluetoothHidDetection(/*is_using_bluetooth=*/false);
  1005. AssertBluetoothPairingAttemptsCount(/*bucket=*/2, /*count=*/1,
  1006. /*total_count=*/1);
  1007. }
  1008. } // namespace ash::hid_detection