| // Copyright 2021 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "ash/quick_pair/pairing/retroactive_pairing_detector.h" |
| |
| #include <memory> |
| #include <optional> |
| |
| #include "ash/constants/ash_features.h" |
| #include "ash/quick_pair/common/constants.h" |
| #include "ash/quick_pair/common/device.h" |
| #include "ash/quick_pair/common/fake_bluetooth_adapter.h" |
| #include "ash/quick_pair/common/logging.h" |
| #include "ash/quick_pair/common/pair_failure.h" |
| #include "ash/quick_pair/common/protocol.h" |
| #include "ash/quick_pair/fast_pair_handshake/fake_fast_pair_gatt_service_client.h" |
| #include "ash/quick_pair/fast_pair_handshake/fast_pair_gatt_service_client_impl.h" |
| #include "ash/quick_pair/fast_pair_handshake/fast_pair_gatt_service_client_lookup_impl.h" |
| #include "ash/quick_pair/message_stream/fake_bluetooth_socket.h" |
| #include "ash/quick_pair/message_stream/fake_message_stream_lookup.h" |
| #include "ash/quick_pair/message_stream/message_stream.h" |
| #include "ash/quick_pair/message_stream/message_stream_lookup.h" |
| #include "ash/quick_pair/pairing/mock_pairer_broker.h" |
| #include "ash/quick_pair/pairing/pairer_broker.h" |
| #include "ash/quick_pair/pairing/retroactive_pairing_detector_impl.h" |
| #include "ash/quick_pair/proto/fastpair.pb.h" |
| #include "ash/quick_pair/repository/fake_fast_pair_repository.h" |
| #include "ash/shell.h" |
| #include "ash/test/ash_test_base.h" |
| #include "base/memory/raw_ptr.h" |
| #include "base/memory/scoped_refptr.h" |
| #include "base/run_loop.h" |
| #include "base/test/scoped_feature_list.h" |
| #include "base/test/task_environment.h" |
| #include "chromeos/ash/services/quick_pair/fast_pair_data_parser.h" |
| #include "chromeos/ash/services/quick_pair/mock_quick_pair_process_manager.h" |
| #include "chromeos/ash/services/quick_pair/quick_pair_process.h" |
| #include "chromeos/ash/services/quick_pair/quick_pair_process_manager.h" |
| #include "chromeos/ash/services/quick_pair/quick_pair_process_manager_impl.h" |
| #include "device/bluetooth/bluetooth_adapter_factory.h" |
| #include "device/bluetooth/floss/floss_features.h" |
| #include "device/bluetooth/test/mock_bluetooth_adapter.h" |
| #include "device/bluetooth/test/mock_bluetooth_device.h" |
| #include "mojo/public/cpp/bindings/shared_remote.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| namespace { |
| |
| constexpr base::TimeDelta kRetroactiveDevicePairingTimeout = base::Seconds(60); |
| constexpr char kTestDeviceAddress[] = "11:12:13:14:15:16"; |
| constexpr char kTestDeviceAddress2[] = "11:12:13:14:15:17"; |
| constexpr char kTestDeviceAddress3[] = "11:12:13:14:15:27"; |
| constexpr char kTestBleDeviceName[] = "Test Device Name"; |
| constexpr char kValidModelId[] = "718c17"; |
| const std::string kUserEmail = "test@test.test"; |
| |
| const std::vector<uint8_t> kModelIdBytes = { |
| /*message_group=*/0x03, |
| /*message_code=*/0x01, |
| /*additional_data_length=*/0x00, 0x03, |
| /*additional_data=*/0xAA, 0xBB, 0xCC}; |
| const std::vector<uint8_t> kModelIdBytesNoMetadata = {0xAA, 0xBB, 0xCC}; |
| const std::string kModelId = "AABBCC"; |
| |
| const std::vector<uint8_t> kBleAddressBytes = { |
| /*message_group=*/0x03, |
| /*message_code=*/0x02, |
| /*additional_data_length=*/0x00, |
| 0x06, |
| /*additional_data=*/0xAA, |
| 0xBB, |
| 0xCC, |
| 0xDD, |
| 0xEE, |
| 0xFF}; |
| const std::string kBleAddress = "AA:BB:CC:DD:EE:FF"; |
| |
| const std::vector<uint8_t> kModelIdBleAddressBytes = { |
| /*mesage_group=*/0x03, |
| /*mesage_code=*/0x01, |
| /*additional_data_length=*/0x00, |
| 0x03, |
| /*additional_data=*/0xAA, |
| 0xBB, |
| 0xCC, |
| /*message_group=*/0x03, |
| /*message_code=*/0x02, |
| /*additional_data_length=*/0x00, |
| 0x06, |
| /*additional_data=*/0xAA, |
| 0xBB, |
| 0xCC, |
| 0xDD, |
| 0xEE, |
| 0xFF}; |
| |
| std::unique_ptr<testing::NiceMock<device::MockBluetoothDevice>> |
| CreateTestBluetoothDevice(std::string address) { |
| return std::make_unique<testing::NiceMock<device::MockBluetoothDevice>>( |
| /*adapter=*/nullptr, /*bluetooth_class=*/0, kTestBleDeviceName, address, |
| /*paired=*/true, /*connected=*/false); |
| } |
| |
| class FakeFastPairGattServiceClientImplFactory |
| : public ash::quick_pair::FastPairGattServiceClientImpl::Factory { |
| public: |
| ~FakeFastPairGattServiceClientImplFactory() override = default; |
| |
| ash::quick_pair::FakeFastPairGattServiceClient* |
| fake_fast_pair_gatt_service_client() { |
| return fake_fast_pair_gatt_service_client_; |
| } |
| |
| private: |
| // FastPairGattServiceClientImpl::Factory: |
| std::unique_ptr<ash::quick_pair::FastPairGattServiceClient> CreateInstance( |
| device::BluetoothDevice* device, |
| scoped_refptr<device::BluetoothAdapter> adapter, |
| base::OnceCallback<void(std::optional<ash::quick_pair::PairFailure>)> |
| on_initialized_callback) override { |
| auto fake_fast_pair_gatt_service_client = |
| std::make_unique<ash::quick_pair::FakeFastPairGattServiceClient>( |
| device, adapter, std::move(on_initialized_callback)); |
| fake_fast_pair_gatt_service_client_ = |
| fake_fast_pair_gatt_service_client.get(); |
| return fake_fast_pair_gatt_service_client; |
| } |
| |
| raw_ptr<ash::quick_pair::FakeFastPairGattServiceClient, DanglingUntriaged> |
| fake_fast_pair_gatt_service_client_ = nullptr; |
| }; |
| |
| } // namespace |
| |
| namespace ash { |
| namespace quick_pair { |
| |
| class RetroactivePairingDetectorTest |
| : public AshTestBase, |
| public RetroactivePairingDetector::Observer { |
| public: |
| RetroactivePairingDetectorTest() |
| : AshTestBase(base::test::TaskEnvironment::TimeSource::MOCK_TIME) {} |
| |
| void SetUp() override { |
| AshTestBase::SetUp(); |
| FastPairGattServiceClientImpl::Factory::SetFactoryForTesting( |
| &fast_pair_gatt_service_factory_); |
| |
| adapter_ = base::MakeRefCounted<FakeBluetoothAdapter>(); |
| device::BluetoothAdapterFactory::SetAdapterForTesting(adapter_); |
| |
| fast_pair_repository_ = std::make_unique<FakeFastPairRepository>(); |
| pairer_broker_ = std::make_unique<MockPairerBroker>(); |
| mock_pairer_broker_ = static_cast<MockPairerBroker*>(pairer_broker_.get()); |
| |
| message_stream_lookup_ = std::make_unique<FakeMessageStreamLookup>(); |
| fake_message_stream_lookup_ = |
| static_cast<FakeMessageStreamLookup*>(message_stream_lookup_.get()); |
| message_stream_ = |
| std::make_unique<MessageStream>(kTestDeviceAddress, fake_socket_.get()); |
| |
| process_manager_ = std::make_unique<MockQuickPairProcessManager>(); |
| quick_pair_process::SetProcessManager(process_manager_.get()); |
| data_parser_ = std::make_unique<FastPairDataParser>( |
| fast_pair_data_parser_.InitWithNewPipeAndPassReceiver()); |
| data_parser_remote_.Bind(std::move(fast_pair_data_parser_), |
| task_environment()->GetMainThreadTaskRunner()); |
| EXPECT_CALL(*mock_process_manager(), GetProcessReference) |
| .WillRepeatedly([&](QuickPairProcessManager::ProcessStoppedCallback) { |
| return std::make_unique< |
| QuickPairProcessManagerImpl::ProcessReferenceImpl>( |
| data_parser_remote_, base::DoNothing()); |
| }); |
| } |
| |
| void TearDown() override { |
| fast_pair_repository_.reset(); |
| retroactive_pairing_detector_.reset(); |
| ClearLogin(); |
| AshTestBase::TearDown(); |
| } |
| |
| void CreateRetroactivePairingDetector() { |
| retroactive_pairing_detector_ = |
| std::make_unique<RetroactivePairingDetectorImpl>( |
| pairer_broker_.get(), message_stream_lookup_.get()); |
| retroactive_pairing_detector_->AddObserver(this); |
| } |
| |
| MockQuickPairProcessManager* mock_process_manager() { |
| return static_cast<MockQuickPairProcessManager*>(process_manager_.get()); |
| } |
| |
| void OnRetroactivePairFound(scoped_refptr<Device> device) override { |
| retroactive_pair_found_ = true; |
| retroactive_device_ = device; |
| } |
| |
| void PairFastPairDeviceWithFastPair(std::string address) { |
| auto fp_device = base::MakeRefCounted<Device>(kValidModelId, address, |
| Protocol::kFastPairInitial); |
| fp_device->set_classic_address(address); |
| mock_pairer_broker_->NotifyDevicePaired(fp_device); |
| } |
| |
| void PairFastPairDeviceWithClassicBluetooth( |
| bool new_paired_status, |
| std::string classic_address, |
| bool test_hid_already_connected = false) { |
| bluetooth_device_ = CreateTestBluetoothDevice(classic_address); |
| bluetooth_device_->AddUUID(ash::quick_pair::kFastPairBluetoothUuid); |
| bluetooth_device_->SetType( |
| device::BluetoothTransport::BLUETOOTH_TRANSPORT_LE); |
| auto* bt_device_ptr = bluetooth_device_.get(); |
| if (test_hid_already_connected) { |
| // Simulate a GATT service client connection already open and connected |
| auto gatt_service_client = FastPairGattServiceClientImpl::Factory::Create( |
| bt_device_ptr, adapter_.get(), base::DoNothing()); |
| FastPairGattServiceClientLookup::GetInstance()->InsertFakeForTesting( |
| bt_device_ptr, std::move(gatt_service_client)); |
| SetGattServiceClientConnected(true); |
| } |
| adapter_->AddMockDevice(std::move(bluetooth_device_)); |
| adapter_->NotifyDevicePairedChanged(bt_device_ptr, new_paired_status); |
| } |
| |
| void SetMessageStream(const std::vector<uint8_t>& message_bytes) { |
| fake_socket_->SetIOBufferFromBytes(message_bytes); |
| message_stream_ = |
| std::make_unique<MessageStream>(kTestDeviceAddress, fake_socket_.get()); |
| } |
| |
| void AddMessageStream(const std::vector<uint8_t>& message_bytes) { |
| fake_socket_->SetIOBufferFromBytes(message_bytes); |
| message_stream_ = |
| std::make_unique<MessageStream>(kTestDeviceAddress, fake_socket_.get()); |
| fake_message_stream_lookup_->AddMessageStream(kTestDeviceAddress, |
| message_stream_.get()); |
| } |
| |
| void NotifyMessageStreamConnected(std::string device_address) { |
| fake_message_stream_lookup_->NotifyMessageStreamConnected( |
| device_address, message_stream_.get()); |
| } |
| |
| void Login(user_manager::UserType user_type) { |
| SimulateUserLogin(kUserEmail, user_type); |
| } |
| |
| void SetGattServiceClientConnected(bool connected) { |
| fast_pair_gatt_service_factory_.fake_fast_pair_gatt_service_client() |
| ->SetConnected(connected); |
| } |
| |
| void RunGattClientInitializedCallback( |
| std::optional<PairFailure> pair_failure) { |
| fast_pair_gatt_service_factory_.fake_fast_pair_gatt_service_client() |
| ->RunOnGattClientInitializedCallback(pair_failure); |
| } |
| |
| void RunReadModelIdCallback( |
| std::optional<device::BluetoothGattService::GattErrorCode> error_code, |
| const std::vector<uint8_t>& value) { |
| fast_pair_gatt_service_factory_.fake_fast_pair_gatt_service_client() |
| ->RunReadModelIdCallback(error_code, value); |
| } |
| |
| protected: |
| bool retroactive_pair_found_ = false; |
| scoped_refptr<Device> retroactive_device_; |
| |
| scoped_refptr<FakeBluetoothAdapter> adapter_; |
| std::unique_ptr<PairerBroker> pairer_broker_; |
| raw_ptr<MockPairerBroker> mock_pairer_broker_ = nullptr; |
| |
| scoped_refptr<FakeBluetoothSocket> fake_socket_ = |
| base::MakeRefCounted<FakeBluetoothSocket>(); |
| std::unique_ptr<MessageStream> message_stream_; |
| std::unique_ptr<MessageStreamLookup> message_stream_lookup_; |
| raw_ptr<FakeMessageStreamLookup> fake_message_stream_lookup_ = nullptr; |
| std::unique_ptr<FakeFastPairRepository> fast_pair_repository_; |
| |
| FakeFastPairGattServiceClientImplFactory fast_pair_gatt_service_factory_; |
| |
| mojo::SharedRemote<mojom::FastPairDataParser> data_parser_remote_; |
| mojo::PendingRemote<mojom::FastPairDataParser> fast_pair_data_parser_; |
| std::unique_ptr<FastPairDataParser> data_parser_; |
| std::unique_ptr<QuickPairProcessManager> process_manager_; |
| |
| scoped_refptr<Device> device_; |
| std::unique_ptr<testing::NiceMock<device::MockBluetoothDevice>> |
| bluetooth_device_; |
| |
| std::unique_ptr<RetroactivePairingDetector> retroactive_pairing_detector_; |
| }; |
| |
| TEST_F(RetroactivePairingDetectorTest, |
| DevicedPaired_FastPair_BluetoothEventFiresFirst) { |
| Login(user_manager::UserType::kRegular); |
| fast_pair_repository_->SetOptInStatus( |
| nearby::fastpair::OptInStatus::STATUS_OPTED_IN); |
| base::RunLoop().RunUntilIdle(); |
| CreateRetroactivePairingDetector(); |
| |
| EXPECT_FALSE(retroactive_pair_found_); |
| |
| PairFastPairDeviceWithClassicBluetooth( |
| /*new_paired_status=*/true, kTestDeviceAddress); |
| PairFastPairDeviceWithFastPair(kTestDeviceAddress); |
| |
| EXPECT_FALSE(retroactive_pair_found_); |
| } |
| |
| // Regression test for b/261041950 |
| TEST_F(RetroactivePairingDetectorTest, |
| FastPairPairingEventCalledDuringBluetoothAdapterPairingEvent) { |
| Login(user_manager::UserType::kRegular); |
| fast_pair_repository_->SetOptInStatus( |
| nearby::fastpair::OptInStatus::STATUS_OPTED_IN); |
| CreateRetroactivePairingDetector(); |
| |
| EXPECT_FALSE(retroactive_pair_found_); |
| |
| SetMessageStream(kModelIdBleAddressBytes); |
| |
| // Simulate the Bluetooth Adapter event firing, with the callback to |
| // `IsDeviceSavedToAccount` delayed. |
| fast_pair_repository_->SetIsDeviceSavedToAccountCallbackDelayed( |
| /*is_delayed=*/true); |
| PairFastPairDeviceWithClassicBluetooth( |
| /*new_paired_status=*/true, kTestDeviceAddress); |
| |
| // Simulate the Fast Pair pairing event firing during the Bluetooth Adapter |
| // pairing event call stack. The Bluetooth Adapter system |
| // event response has not finished completing because of the delay set in |
| // `SetIsDeviceSavedToAccountCallbackDelayed`. |
| PairFastPairDeviceWithFastPair(kTestDeviceAddress); |
| |
| // Trigger the callback to check the repository after the Fast Pair pairing |
| // event fires. This will conclude the BluetoothAdapter pairing event call |
| // stack. |
| fast_pair_repository_->TriggerIsDeviceSavedToAccountCallback(); |
| |
| // Simulate data being received via Message Stream for the device. It should |
| // not be detected since the Fast Pair event has been fired, removing it |
| // as a possible retroactive device. |
| fake_socket_->TriggerReceiveCallback(); |
| NotifyMessageStreamConnected(kTestDeviceAddress); |
| base::RunLoop().RunUntilIdle(); |
| |
| EXPECT_FALSE(retroactive_pair_found_); |
| } |
| |
| TEST_F(RetroactivePairingDetectorTest, DeviceUnpaired) { |
| Login(user_manager::UserType::kRegular); |
| fast_pair_repository_->SetOptInStatus( |
| nearby::fastpair::OptInStatus::STATUS_OPTED_IN); |
| base::RunLoop().RunUntilIdle(); |
| CreateRetroactivePairingDetector(); |
| |
| EXPECT_FALSE(retroactive_pair_found_); |
| |
| PairFastPairDeviceWithClassicBluetooth( |
| /*new_paired_status=*/false, kTestDeviceAddress); |
| EXPECT_FALSE(retroactive_pair_found_); |
| } |
| |
| TEST_F(RetroactivePairingDetectorTest, NoMessageStream) { |
| Login(user_manager::UserType::kRegular); |
| fast_pair_repository_->SetOptInStatus( |
| nearby::fastpair::OptInStatus::STATUS_OPTED_IN); |
| base::RunLoop().RunUntilIdle(); |
| CreateRetroactivePairingDetector(); |
| |
| EXPECT_FALSE(retroactive_pair_found_); |
| |
| PairFastPairDeviceWithClassicBluetooth( |
| /*new_paired_status=*/true, kTestDeviceAddress); |
| NotifyMessageStreamConnected(kTestDeviceAddress); |
| base::RunLoop().RunUntilIdle(); |
| |
| EXPECT_FALSE(retroactive_pair_found_); |
| } |
| |
| TEST_F(RetroactivePairingDetectorTest, MessageStream_NoBle) { |
| Login(user_manager::UserType::kRegular); |
| fast_pair_repository_->SetOptInStatus( |
| nearby::fastpair::OptInStatus::STATUS_OPTED_IN); |
| base::RunLoop().RunUntilIdle(); |
| CreateRetroactivePairingDetector(); |
| |
| EXPECT_FALSE(retroactive_pair_found_); |
| |
| SetMessageStream(kModelIdBytes); |
| PairFastPairDeviceWithClassicBluetooth( |
| /*new_paired_status=*/true, kTestDeviceAddress); |
| |
| fake_socket_->TriggerReceiveCallback(); |
| base::RunLoop().RunUntilIdle(); |
| NotifyMessageStreamConnected(kTestDeviceAddress); |
| base::RunLoop().RunUntilIdle(); |
| |
| EXPECT_FALSE(retroactive_pair_found_); |
| } |
| |
| TEST_F(RetroactivePairingDetectorTest, MessageStream_NoModelId) { |
| Login(user_manager::UserType::kRegular); |
| fast_pair_repository_->SetOptInStatus( |
| nearby::fastpair::OptInStatus::STATUS_OPTED_IN); |
| base::RunLoop().RunUntilIdle(); |
| CreateRetroactivePairingDetector(); |
| |
| EXPECT_FALSE(retroactive_pair_found_); |
| |
| SetMessageStream(kBleAddressBytes); |
| PairFastPairDeviceWithClassicBluetooth( |
| /*new_paired_status=*/true, kTestDeviceAddress); |
| |
| fake_socket_->TriggerReceiveCallback(); |
| base::RunLoop().RunUntilIdle(); |
| |
| NotifyMessageStreamConnected(kTestDeviceAddress); |
| base::RunLoop().RunUntilIdle(); |
| |
| EXPECT_FALSE(retroactive_pair_found_); |
| } |
| |
| TEST_F(RetroactivePairingDetectorTest, MessageStream_SocketError) { |
| Login(user_manager::UserType::kRegular); |
| fast_pair_repository_->SetOptInStatus( |
| nearby::fastpair::OptInStatus::STATUS_OPTED_IN); |
| base::RunLoop().RunUntilIdle(); |
| CreateRetroactivePairingDetector(); |
| |
| EXPECT_FALSE(retroactive_pair_found_); |
| |
| std::vector<uint8_t> data; |
| SetMessageStream(data); |
| PairFastPairDeviceWithClassicBluetooth( |
| /*new_paired_status=*/true, kTestDeviceAddress); |
| |
| fake_socket_->TriggerReceiveCallback(); |
| base::RunLoop().RunUntilIdle(); |
| NotifyMessageStreamConnected(kTestDeviceAddress); |
| base::RunLoop().RunUntilIdle(); |
| |
| EXPECT_FALSE(retroactive_pair_found_); |
| } |
| |
| TEST_F(RetroactivePairingDetectorTest, MessageStream_NoBytes) { |
| Login(user_manager::UserType::kRegular); |
| fast_pair_repository_->SetOptInStatus( |
| nearby::fastpair::OptInStatus::STATUS_OPTED_IN); |
| base::RunLoop().RunUntilIdle(); |
| CreateRetroactivePairingDetector(); |
| |
| EXPECT_FALSE(retroactive_pair_found_); |
| |
| std::vector<uint8_t> data; |
| SetMessageStream(data); |
| fake_socket_->SetEmptyBuffer(); |
| PairFastPairDeviceWithClassicBluetooth( |
| /*new_paired_status=*/true, kTestDeviceAddress); |
| |
| fake_socket_->TriggerReceiveCallback(); |
| base::RunLoop().RunUntilIdle(); |
| NotifyMessageStreamConnected(kTestDeviceAddress); |
| base::RunLoop().RunUntilIdle(); |
| |
| EXPECT_FALSE(retroactive_pair_found_); |
| } |
| |
| TEST_F(RetroactivePairingDetectorTest, MessageStream_Ble_ModelId_Lost) { |
| Login(user_manager::UserType::kRegular); |
| fast_pair_repository_->SetOptInStatus( |
| nearby::fastpair::OptInStatus::STATUS_OPTED_IN); |
| base::RunLoop().RunUntilIdle(); |
| CreateRetroactivePairingDetector(); |
| |
| EXPECT_FALSE(retroactive_pair_found_); |
| |
| SetMessageStream(kModelIdBleAddressBytes); |
| PairFastPairDeviceWithClassicBluetooth( |
| /*new_paired_status=*/true, kTestDeviceAddress); |
| |
| fake_socket_->TriggerReceiveCallback(); |
| base::RunLoop().RunUntilIdle(); |
| adapter_->RemoveMockDevice(kTestDeviceAddress); |
| |
| NotifyMessageStreamConnected(kTestDeviceAddress); |
| base::RunLoop().RunUntilIdle(); |
| |
| EXPECT_FALSE(retroactive_pair_found_); |
| } |
| |
| TEST_F(RetroactivePairingDetectorTest, MessageStream_Ble_ModelId_FlagEnabled) { |
| Login(user_manager::UserType::kRegular); |
| base::test::ScopedFeatureList feature_list; |
| feature_list.InitWithFeatures( |
| /*enabled_features=*/{features::kFastPairSavedDevices, |
| features::kFastPairSavedDevicesStrictOptIn}, |
| /*disabled_features=*/{}); |
| |
| // Strict interpretation of opt-in status while opted in means that we |
| // expect to be notified of retroactive pairing when the MessageStream |
| // connects after pairing is completed. This test is for the scenario |
| // when we receive both the model id and the BLE address bytes over the |
| // Message Stream. |
| fast_pair_repository_->SetOptInStatus( |
| nearby::fastpair::OptInStatus::STATUS_OPTED_IN); |
| base::RunLoop().RunUntilIdle(); |
| CreateRetroactivePairingDetector(); |
| |
| EXPECT_FALSE(retroactive_pair_found_); |
| |
| SetMessageStream(kModelIdBleAddressBytes); |
| PairFastPairDeviceWithClassicBluetooth( |
| /*new_paired_status=*/true, kTestDeviceAddress); |
| |
| fake_socket_->TriggerReceiveCallback(); |
| base::RunLoop().RunUntilIdle(); |
| NotifyMessageStreamConnected(kTestDeviceAddress); |
| base::RunLoop().RunUntilIdle(); |
| |
| EXPECT_TRUE(retroactive_pair_found_); |
| EXPECT_EQ(retroactive_device_->ble_address(), kBleAddress); |
| EXPECT_EQ(retroactive_device_->metadata_id(), kModelId); |
| } |
| |
| TEST_F(RetroactivePairingDetectorTest, MessageStream_Ble_ModelId_FlagDisabled) { |
| Login(user_manager::UserType::kRegular); |
| base::test::ScopedFeatureList feature_list; |
| feature_list.InitWithFeatures( |
| /*enabled_features=*/{}, |
| /*disabled_features=*/{features::kFastPairSavedDevices, |
| features::kFastPairSavedDevicesStrictOptIn}); |
| |
| // Without the SavedDevices or StrictOptIn flags, we expect that opt-in |
| // status being opted out does not matter and should not impact whether or |
| // not we detect a retroactive pairing scenario. We expect to still receive |
| // the model id and BLE bytes once the Message Stream connects, and be |
| // notified of retroactive pairing found. |
| fast_pair_repository_->SetOptInStatus( |
| nearby::fastpair::OptInStatus::STATUS_OPTED_OUT); |
| base::RunLoop().RunUntilIdle(); |
| CreateRetroactivePairingDetector(); |
| |
| EXPECT_FALSE(retroactive_pair_found_); |
| |
| SetMessageStream(kModelIdBleAddressBytes); |
| PairFastPairDeviceWithClassicBluetooth( |
| /*new_paired_status=*/true, kTestDeviceAddress); |
| |
| fake_socket_->TriggerReceiveCallback(); |
| base::RunLoop().RunUntilIdle(); |
| NotifyMessageStreamConnected(kTestDeviceAddress); |
| base::RunLoop().RunUntilIdle(); |
| |
| EXPECT_TRUE(retroactive_pair_found_); |
| EXPECT_EQ(retroactive_device_->ble_address(), kBleAddress); |
| EXPECT_EQ(retroactive_device_->metadata_id(), kModelId); |
| } |
| |
| TEST_F(RetroactivePairingDetectorTest, |
| MessageStream_Ble_ModelId_StrictFlagDisabled) { |
| Login(user_manager::UserType::kRegular); |
| base::test::ScopedFeatureList feature_list; |
| feature_list.InitWithFeatures( |
| /*enabled_features=*/{features::kFastPairSavedDevices}, |
| /*disabled_features=*/{features::kFastPairSavedDevicesStrictOptIn}); |
| |
| // With the SavedDevices flag but without the StrictOptIn flag, we expect that |
| // opt-in status being opted out does not matter and should not impact whether |
| // or not we detect a retroactive pairing scenario. We expect to still receive |
| // the model id and BLE bytes once the Message Stream connects, and be |
| // notified of retroactive pairing found. |
| fast_pair_repository_->SetOptInStatus( |
| nearby::fastpair::OptInStatus::STATUS_OPTED_OUT); |
| base::RunLoop().RunUntilIdle(); |
| CreateRetroactivePairingDetector(); |
| |
| EXPECT_FALSE(retroactive_pair_found_); |
| |
| SetMessageStream(kModelIdBleAddressBytes); |
| PairFastPairDeviceWithClassicBluetooth( |
| /*new_paired_status=*/true, kTestDeviceAddress); |
| |
| fake_socket_->TriggerReceiveCallback(); |
| base::RunLoop().RunUntilIdle(); |
| NotifyMessageStreamConnected(kTestDeviceAddress); |
| base::RunLoop().RunUntilIdle(); |
| |
| EXPECT_TRUE(retroactive_pair_found_); |
| EXPECT_EQ(retroactive_device_->ble_address(), kBleAddress); |
| EXPECT_EQ(retroactive_device_->metadata_id(), kModelId); |
| } |
| |
| TEST_F(RetroactivePairingDetectorTest, |
| MessageStream_Ble_ModelId_SavedFlagDisabled) { |
| Login(user_manager::UserType::kRegular); |
| base::test::ScopedFeatureList feature_list; |
| feature_list.InitWithFeatures( |
| /*enabled_features=*/{features::kFastPairSavedDevicesStrictOptIn}, |
| /*disabled_features=*/{features::kFastPairSavedDevices}); |
| |
| // With the StrictOptIn flag but without the SavedDevices flag, we expect that |
| // opt-in status being opted out does not matter and should not impact whether |
| // or not we detect a retroactive pairing scenario. We expect to still receive |
| // the model id and BLE bytes once the Message Stream connects, and be |
| // notified of retroactive pairing found. |
| fast_pair_repository_->SetOptInStatus( |
| nearby::fastpair::OptInStatus::STATUS_OPTED_OUT); |
| base::RunLoop().RunUntilIdle(); |
| CreateRetroactivePairingDetector(); |
| |
| EXPECT_FALSE(retroactive_pair_found_); |
| |
| SetMessageStream(kModelIdBleAddressBytes); |
| PairFastPairDeviceWithClassicBluetooth( |
| /*new_paired_status=*/true, kTestDeviceAddress); |
| |
| fake_socket_->TriggerReceiveCallback(); |
| base::RunLoop().RunUntilIdle(); |
| NotifyMessageStreamConnected(kTestDeviceAddress); |
| base::RunLoop().RunUntilIdle(); |
| |
| EXPECT_TRUE(retroactive_pair_found_); |
| EXPECT_EQ(retroactive_device_->ble_address(), kBleAddress); |
| EXPECT_EQ(retroactive_device_->metadata_id(), kModelId); |
| } |
| |
| TEST_F(RetroactivePairingDetectorTest, |
| MessageStream_Ble_ModelId_GuestUserLoggedIn) { |
| Login(user_manager::UserType::kGuest); |
| fast_pair_repository_->SetOptInStatus( |
| nearby::fastpair::OptInStatus::STATUS_OPTED_IN); |
| base::RunLoop().RunUntilIdle(); |
| CreateRetroactivePairingDetector(); |
| |
| EXPECT_FALSE(retroactive_pair_found_); |
| |
| SetMessageStream(kModelIdBleAddressBytes); |
| PairFastPairDeviceWithClassicBluetooth( |
| /*new_paired_status=*/true, kTestDeviceAddress); |
| |
| fake_socket_->TriggerReceiveCallback(); |
| base::RunLoop().RunUntilIdle(); |
| NotifyMessageStreamConnected(kTestDeviceAddress); |
| base::RunLoop().RunUntilIdle(); |
| |
| EXPECT_FALSE(retroactive_pair_found_); |
| } |
| |
| TEST_F(RetroactivePairingDetectorTest, |
| MessageStream_Ble_ModelId_KioskUserLoggedIn) { |
| Login(user_manager::UserType::kKioskApp); |
| fast_pair_repository_->SetOptInStatus( |
| nearby::fastpair::OptInStatus::STATUS_OPTED_IN); |
| base::RunLoop().RunUntilIdle(); |
| CreateRetroactivePairingDetector(); |
| |
| EXPECT_FALSE(retroactive_pair_found_); |
| |
| SetMessageStream(kModelIdBleAddressBytes); |
| PairFastPairDeviceWithClassicBluetooth( |
| /*new_paired_status=*/true, kTestDeviceAddress); |
| |
| fake_socket_->TriggerReceiveCallback(); |
| base::RunLoop().RunUntilIdle(); |
| NotifyMessageStreamConnected(kTestDeviceAddress); |
| base::RunLoop().RunUntilIdle(); |
| |
| EXPECT_FALSE(retroactive_pair_found_); |
| } |
| |
| TEST_F(RetroactivePairingDetectorTest, |
| MessageStream_GetMessageStream_Ble_ModelId_FlagEnabled) { |
| Login(user_manager::UserType::kRegular); |
| base::test::ScopedFeatureList feature_list; |
| feature_list.InitWithFeatures( |
| /*enabled_features=*/{features::kFastPairSavedDevices, |
| features::kFastPairSavedDevicesStrictOptIn}, |
| /*disabled_features=*/{}); |
| |
| // Strict interpretation of opt-in status while opted in means that we |
| // expect to be notified of retroactive pairing when the Message Stream |
| // connects after pairing is completed. This test is for the scenario |
| // when we receive both the model id and the BLE address bytes over the |
| // Message Stream. The case where we are not notified when opted out is |
| // tested in Notify_OptedOut_* tests below. |
| fast_pair_repository_->SetOptInStatus( |
| nearby::fastpair::OptInStatus::STATUS_OPTED_IN); |
| base::RunLoop().RunUntilIdle(); |
| CreateRetroactivePairingDetector(); |
| |
| EXPECT_FALSE(retroactive_pair_found_); |
| |
| AddMessageStream(kModelIdBleAddressBytes); |
| PairFastPairDeviceWithClassicBluetooth( |
| /*new_paired_status=*/true, kTestDeviceAddress); |
| fake_socket_->TriggerReceiveCallback(); |
| base::RunLoop().RunUntilIdle(); |
| |
| EXPECT_TRUE(retroactive_pair_found_); |
| EXPECT_EQ(retroactive_device_->ble_address(), kBleAddress); |
| EXPECT_EQ(retroactive_device_->metadata_id(), kModelId); |
| } |
| |
| TEST_F(RetroactivePairingDetectorTest, |
| MessageStream_GetMessageStream_Ble_ModelId_FlagDisabled) { |
| Login(user_manager::UserType::kRegular); |
| base::test::ScopedFeatureList feature_list; |
| |
| // With SavedDevices and StrictOptIn flags disabled, the user's opt-in status |
| // of opted out should not impact the notification of a retroactive pairing |
| // found. |
| feature_list.InitWithFeatures( |
| /*enabled_features=*/{}, |
| /*disabled_features=*/{features::kFastPairSavedDevices, |
| features::kFastPairSavedDevicesStrictOptIn}); |
| fast_pair_repository_->SetOptInStatus( |
| nearby::fastpair::OptInStatus::STATUS_OPTED_OUT); |
| base::RunLoop().RunUntilIdle(); |
| CreateRetroactivePairingDetector(); |
| |
| EXPECT_FALSE(retroactive_pair_found_); |
| |
| AddMessageStream(kModelIdBleAddressBytes); |
| PairFastPairDeviceWithClassicBluetooth( |
| /*new_paired_status=*/true, kTestDeviceAddress); |
| fake_socket_->TriggerReceiveCallback(); |
| base::RunLoop().RunUntilIdle(); |
| |
| EXPECT_TRUE(retroactive_pair_found_); |
| EXPECT_EQ(retroactive_device_->ble_address(), kBleAddress); |
| EXPECT_EQ(retroactive_device_->metadata_id(), kModelId); |
| } |
| |
| TEST_F(RetroactivePairingDetectorTest, |
| MessageStream_GetMessageStream_Ble_ModelId_StrictFlagDisabled) { |
| Login(user_manager::UserType::kRegular); |
| base::test::ScopedFeatureList feature_list; |
| |
| // With only one flag enabled and the other disabled, the user's opt-in status |
| // of opted out should not impact the notification of a retroactive pairing |
| // found. |
| feature_list.InitWithFeatures( |
| /*enabled_features=*/{features::kFastPairSavedDevices}, |
| /*disabled_features=*/{features::kFastPairSavedDevicesStrictOptIn}); |
| fast_pair_repository_->SetOptInStatus( |
| nearby::fastpair::OptInStatus::STATUS_OPTED_OUT); |
| base::RunLoop().RunUntilIdle(); |
| CreateRetroactivePairingDetector(); |
| |
| EXPECT_FALSE(retroactive_pair_found_); |
| |
| AddMessageStream(kModelIdBleAddressBytes); |
| PairFastPairDeviceWithClassicBluetooth( |
| /*new_paired_status=*/true, kTestDeviceAddress); |
| fake_socket_->TriggerReceiveCallback(); |
| base::RunLoop().RunUntilIdle(); |
| |
| EXPECT_TRUE(retroactive_pair_found_); |
| EXPECT_EQ(retroactive_device_->ble_address(), kBleAddress); |
| EXPECT_EQ(retroactive_device_->metadata_id(), kModelId); |
| } |
| |
| TEST_F(RetroactivePairingDetectorTest, |
| MessageStream_GetMessageStream_Ble_ModelId_SavedFlagDisabled) { |
| Login(user_manager::UserType::kRegular); |
| base::test::ScopedFeatureList feature_list; |
| |
| // With only one flag enabled and the other disabled, the user's opt-in status |
| // of opted out should not impact the notification of a retroactive pairing |
| // found. |
| feature_list.InitWithFeatures( |
| /*enabled_features=*/{features::kFastPairSavedDevicesStrictOptIn}, |
| /*disabled_features=*/{features::kFastPairSavedDevices}); |
| fast_pair_repository_->SetOptInStatus( |
| nearby::fastpair::OptInStatus::STATUS_OPTED_OUT); |
| base::RunLoop().RunUntilIdle(); |
| CreateRetroactivePairingDetector(); |
| |
| EXPECT_FALSE(retroactive_pair_found_); |
| |
| AddMessageStream(kModelIdBleAddressBytes); |
| PairFastPairDeviceWithClassicBluetooth( |
| /*new_paired_status=*/true, kTestDeviceAddress); |
| fake_socket_->TriggerReceiveCallback(); |
| base::RunLoop().RunUntilIdle(); |
| |
| EXPECT_TRUE(retroactive_pair_found_); |
| EXPECT_EQ(retroactive_device_->ble_address(), kBleAddress); |
| EXPECT_EQ(retroactive_device_->metadata_id(), kModelId); |
| } |
| |
| TEST_F(RetroactivePairingDetectorTest, |
| EnableScenarioIfLoggedInLater_FlagEnabled) { |
| Login(user_manager::UserType::kGuest); |
| base::test::ScopedFeatureList feature_list; |
| feature_list.InitWithFeatures( |
| /*enabled_features=*/{features::kFastPairSavedDevices, |
| features::kFastPairSavedDevicesStrictOptIn}, |
| /*disabled_features=*/{}); |
| fast_pair_repository_->SetOptInStatus( |
| nearby::fastpair::OptInStatus::STATUS_OPTED_IN); |
| EXPECT_FALSE(retroactive_pair_found_); |
| |
| CreateRetroactivePairingDetector(); |
| base::RunLoop().RunUntilIdle(); |
| |
| Login(user_manager::UserType::kRegular); |
| AddMessageStream(kModelIdBleAddressBytes); |
| PairFastPairDeviceWithClassicBluetooth( |
| /*new_paired_status=*/true, kTestDeviceAddress); |
| fake_socket_->TriggerReceiveCallback(); |
| base::RunLoop().RunUntilIdle(); |
| |
| EXPECT_TRUE(retroactive_pair_found_); |
| EXPECT_EQ(retroactive_device_->ble_address(), kBleAddress); |
| EXPECT_EQ(retroactive_device_->metadata_id(), kModelId); |
| } |
| |
| TEST_F(RetroactivePairingDetectorTest, |
| EnableScenarioIfLoggedInLater_FlagDisabled) { |
| Login(user_manager::UserType::kGuest); |
| base::test::ScopedFeatureList feature_list; |
| feature_list.InitWithFeatures( |
| /*enabled_features=*/{}, |
| /*disabled_features=*/{features::kFastPairSavedDevices, |
| features::kFastPairSavedDevicesStrictOptIn}); |
| fast_pair_repository_->SetOptInStatus( |
| nearby::fastpair::OptInStatus::STATUS_OPTED_OUT); |
| EXPECT_FALSE(retroactive_pair_found_); |
| |
| CreateRetroactivePairingDetector(); |
| base::RunLoop().RunUntilIdle(); |
| |
| Login(user_manager::UserType::kRegular); |
| AddMessageStream(kModelIdBleAddressBytes); |
| PairFastPairDeviceWithClassicBluetooth( |
| /*new_paired_status=*/true, kTestDeviceAddress); |
| fake_socket_->TriggerReceiveCallback(); |
| base::RunLoop().RunUntilIdle(); |
| |
| EXPECT_TRUE(retroactive_pair_found_); |
| EXPECT_EQ(retroactive_device_->ble_address(), kBleAddress); |
| EXPECT_EQ(retroactive_device_->metadata_id(), kModelId); |
| } |
| |
| TEST_F(RetroactivePairingDetectorTest, |
| EnableScenarioIfLoggedInLater_StrictFlagDisabled) { |
| Login(user_manager::UserType::kGuest); |
| base::test::ScopedFeatureList feature_list; |
| feature_list.InitWithFeatures( |
| /*enabled_features=*/{features::kFastPairSavedDevices}, |
| /*disabled_features=*/{features::kFastPairSavedDevicesStrictOptIn}); |
| fast_pair_repository_->SetOptInStatus( |
| nearby::fastpair::OptInStatus::STATUS_OPTED_OUT); |
| EXPECT_FALSE(retroactive_pair_found_); |
| |
| CreateRetroactivePairingDetector(); |
| base::RunLoop().RunUntilIdle(); |
| |
| Login(user_manager::UserType::kRegular); |
| AddMessageStream(kModelIdBleAddressBytes); |
| PairFastPairDeviceWithClassicBluetooth( |
| /*new_paired_status=*/true, kTestDeviceAddress); |
| fake_socket_->TriggerReceiveCallback(); |
| base::RunLoop().RunUntilIdle(); |
| |
| EXPECT_TRUE(retroactive_pair_found_); |
| EXPECT_EQ(retroactive_device_->ble_address(), kBleAddress); |
| EXPECT_EQ(retroactive_device_->metadata_id(), kModelId); |
| } |
| |
| TEST_F(RetroactivePairingDetectorTest, |
| EnableScenarioIfLoggedInLater_SavedFlagDisabled) { |
| Login(user_manager::UserType::kGuest); |
| base::test::ScopedFeatureList feature_list; |
| feature_list.InitWithFeatures( |
| /*enabled_features=*/{features::kFastPairSavedDevicesStrictOptIn}, |
| /*disabled_features=*/{features::kFastPairSavedDevices}); |
| fast_pair_repository_->SetOptInStatus( |
| nearby::fastpair::OptInStatus::STATUS_OPTED_OUT); |
| EXPECT_FALSE(retroactive_pair_found_); |
| |
| CreateRetroactivePairingDetector(); |
| base::RunLoop().RunUntilIdle(); |
| |
| Login(user_manager::UserType::kRegular); |
| AddMessageStream(kModelIdBleAddressBytes); |
| PairFastPairDeviceWithClassicBluetooth( |
| /*new_paired_status=*/true, kTestDeviceAddress); |
| fake_socket_->TriggerReceiveCallback(); |
| base::RunLoop().RunUntilIdle(); |
| |
| EXPECT_TRUE(retroactive_pair_found_); |
| EXPECT_EQ(retroactive_device_->ble_address(), kBleAddress); |
| EXPECT_EQ(retroactive_device_->metadata_id(), kModelId); |
| } |
| |
| TEST_F(RetroactivePairingDetectorTest, |
| DontEnableScenarioIfLoggedInLaterAsGuest) { |
| Login(user_manager::UserType::kGuest); |
| EXPECT_FALSE(retroactive_pair_found_); |
| |
| CreateRetroactivePairingDetector(); |
| base::RunLoop().RunUntilIdle(); |
| |
| Login(user_manager::UserType::kGuest); |
| base::RunLoop().RunUntilIdle(); |
| |
| EXPECT_FALSE(retroactive_pair_found_); |
| } |
| |
| TEST_F(RetroactivePairingDetectorTest, |
| MessageStream_GetMessageStream_Ble_ModelId_GuestUser) { |
| Login(user_manager::UserType::kGuest); |
| base::RunLoop().RunUntilIdle(); |
| CreateRetroactivePairingDetector(); |
| |
| EXPECT_FALSE(retroactive_pair_found_); |
| |
| AddMessageStream(kModelIdBleAddressBytes); |
| PairFastPairDeviceWithClassicBluetooth( |
| /*new_paired_status=*/true, kTestDeviceAddress); |
| fake_socket_->TriggerReceiveCallback(); |
| |
| base::RunLoop().RunUntilIdle(); |
| EXPECT_FALSE(retroactive_pair_found_); |
| } |
| |
| TEST_F(RetroactivePairingDetectorTest, |
| MessageStream_GetMessageStream_ModelId_FlagEnabled) { |
| Login(user_manager::UserType::kRegular); |
| base::test::ScopedFeatureList feature_list; |
| feature_list.InitWithFeatures( |
| /*enabled_features=*/{features::kFastPairSavedDevices, |
| features::kFastPairSavedDevicesStrictOptIn}, |
| /*disabled_features=*/{}); |
| |
| // With both SavedDevices and StrictOptIn enabled, we expect to be notified |
| // when the Message Stream is connected before we are notified that the |
| // pairing is complete, and retrieving the model id and BLE address |
| // after the fact by parsing the previous messages received if the user |
| // is opted in to saving devices to their account. The case where we are not |
| // notified when opted out is tested in Notify_OptedOut_* tests below. |
| fast_pair_repository_->SetOptInStatus( |
| nearby::fastpair::OptInStatus::STATUS_OPTED_IN); |
| base::RunLoop().RunUntilIdle(); |
| CreateRetroactivePairingDetector(); |
| |
| EXPECT_FALSE(retroactive_pair_found_); |
| |
| AddMessageStream(kModelIdBytes); |
| PairFastPairDeviceWithClassicBluetooth( |
| /*new_paired_status=*/true, kTestDeviceAddress); |
| fake_socket_->TriggerReceiveCallback(); |
| base::RunLoop().RunUntilIdle(); |
| |
| EXPECT_FALSE(retroactive_pair_found_); |
| } |
| |
| TEST_F(RetroactivePairingDetectorTest, |
| MessageStream_GetMessageStream_ModelId_FlagDisabled) { |
| Login(user_manager::UserType::kRegular); |
| base::test::ScopedFeatureList feature_list; |
| |
| // With both SavedDevices and StrictOptIn disabled, we expect to be notified |
| // when the Message Stream is connected before we are notified that the |
| // pairing is complete, and retrieving the model id and BLE address |
| // after the fact by parsing the previous messages received even if the |
| // user is opted out of saving devices to their account. |
| feature_list.InitWithFeatures( |
| /*enabled_features=*/{}, |
| /*disabled_features=*/{features::kFastPairSavedDevices, |
| features::kFastPairSavedDevicesStrictOptIn}); |
| fast_pair_repository_->SetOptInStatus( |
| nearby::fastpair::OptInStatus::STATUS_OPTED_OUT); |
| base::RunLoop().RunUntilIdle(); |
| CreateRetroactivePairingDetector(); |
| |
| EXPECT_FALSE(retroactive_pair_found_); |
| |
| AddMessageStream(kModelIdBytes); |
| PairFastPairDeviceWithClassicBluetooth( |
| /*new_paired_status=*/true, kTestDeviceAddress); |
| fake_socket_->TriggerReceiveCallback(); |
| base::RunLoop().RunUntilIdle(); |
| |
| EXPECT_FALSE(retroactive_pair_found_); |
| } |
| |
| TEST_F(RetroactivePairingDetectorTest, |
| MessageStream_GetMessageStream_ModelId_StrictFlagDisabled) { |
| Login(user_manager::UserType::kRegular); |
| base::test::ScopedFeatureList feature_list; |
| |
| // With the SavedDevices flag enabled but the StrictOptIn disabled, we |
| // expect to not consider the user's status of opted out and still be |
| // notified when a MessageStream is connected before we are notified of |
| // pairing, and successfully parse a model id and BLE address to confirm |
| // retroactive pairing has been found. |
| feature_list.InitWithFeatures( |
| /*enabled_features=*/{features::kFastPairSavedDevices}, |
| /*disabled_features=*/{features::kFastPairSavedDevicesStrictOptIn}); |
| fast_pair_repository_->SetOptInStatus( |
| nearby::fastpair::OptInStatus::STATUS_OPTED_OUT); |
| base::RunLoop().RunUntilIdle(); |
| CreateRetroactivePairingDetector(); |
| |
| EXPECT_FALSE(retroactive_pair_found_); |
| |
| AddMessageStream(kModelIdBytes); |
| PairFastPairDeviceWithClassicBluetooth( |
| /*new_paired_status=*/true, kTestDeviceAddress); |
| fake_socket_->TriggerReceiveCallback(); |
| base::RunLoop().RunUntilIdle(); |
| |
| EXPECT_FALSE(retroactive_pair_found_); |
| } |
| |
| TEST_F(RetroactivePairingDetectorTest, |
| MessageStream_GetMessageStream_ModelId_SavedFlagDisabled) { |
| Login(user_manager::UserType::kRegular); |
| base::test::ScopedFeatureList feature_list; |
| |
| // With the StrictOptIn flag enabled but the SavedDevices disabled, we |
| // expect to not consider the user's status of opted out and still be |
| // notified when a MessageStream is connected before we are notified of |
| // pairing, and successfully parse a model id and BLE address to confirm |
| // retroactive pairing has been found. |
| feature_list.InitWithFeatures( |
| /*enabled_features=*/{features::kFastPairSavedDevicesStrictOptIn}, |
| /*disabled_features=*/{features::kFastPairSavedDevices}); |
| fast_pair_repository_->SetOptInStatus( |
| nearby::fastpair::OptInStatus::STATUS_OPTED_OUT); |
| base::RunLoop().RunUntilIdle(); |
| CreateRetroactivePairingDetector(); |
| |
| EXPECT_FALSE(retroactive_pair_found_); |
| |
| AddMessageStream(kModelIdBytes); |
| PairFastPairDeviceWithClassicBluetooth( |
| /*new_paired_status=*/true, kTestDeviceAddress); |
| fake_socket_->TriggerReceiveCallback(); |
| base::RunLoop().RunUntilIdle(); |
| |
| EXPECT_FALSE(retroactive_pair_found_); |
| } |
| |
| TEST_F(RetroactivePairingDetectorTest, |
| MessageStream_Observer_Ble_ModelId_FlagEnabled) { |
| Login(user_manager::UserType::kRegular); |
| base::test::ScopedFeatureList feature_list; |
| feature_list.InitWithFeatures( |
| /*enabled_features=*/{features::kFastPairSavedDevices, |
| features::kFastPairSavedDevicesStrictOptIn}, |
| /*disabled_features=*/{}); |
| |
| // This test is for the scenario where the Message Stream receives messages |
| // for the BLE address and model id after it is connected and paired, and |
| // the detector should observe these messages and notify us of the device. |
| fast_pair_repository_->SetOptInStatus( |
| nearby::fastpair::OptInStatus::STATUS_OPTED_IN); |
| base::RunLoop().RunUntilIdle(); |
| CreateRetroactivePairingDetector(); |
| |
| EXPECT_FALSE(retroactive_pair_found_); |
| |
| fake_socket_->SetIOBufferFromBytes(kModelIdBleAddressBytes); |
| PairFastPairDeviceWithClassicBluetooth( |
| /*new_paired_status=*/true, kTestDeviceAddress); |
| base::RunLoop().RunUntilIdle(); |
| |
| NotifyMessageStreamConnected(kTestDeviceAddress); |
| base::RunLoop().RunUntilIdle(); |
| |
| fake_socket_->TriggerReceiveCallback(); |
| base::RunLoop().RunUntilIdle(); |
| |
| EXPECT_TRUE(retroactive_pair_found_); |
| EXPECT_EQ(retroactive_device_->ble_address(), kBleAddress); |
| EXPECT_EQ(retroactive_device_->metadata_id(), kModelId); |
| } |
| |
| TEST_F(RetroactivePairingDetectorTest, |
| MessageStream_Observer_Ble_ModelId_GuestAccount) { |
| Login(user_manager::UserType::kGuest); |
| base::RunLoop().RunUntilIdle(); |
| CreateRetroactivePairingDetector(); |
| |
| EXPECT_FALSE(retroactive_pair_found_); |
| |
| fake_socket_->SetIOBufferFromBytes(kModelIdBleAddressBytes); |
| PairFastPairDeviceWithClassicBluetooth( |
| /*new_paired_status=*/true, kTestDeviceAddress); |
| base::RunLoop().RunUntilIdle(); |
| |
| NotifyMessageStreamConnected(kTestDeviceAddress); |
| base::RunLoop().RunUntilIdle(); |
| |
| fake_socket_->TriggerReceiveCallback(); |
| base::RunLoop().RunUntilIdle(); |
| |
| EXPECT_FALSE(retroactive_pair_found_); |
| } |
| |
| TEST_F(RetroactivePairingDetectorTest, |
| MessageStream_Observer_ModelId_FlagEnabled) { |
| Login(user_manager::UserType::kRegular); |
| base::test::ScopedFeatureList feature_list; |
| |
| // With the SavedDevices and StrictOptIn flags enabled, we do not expect |
| // to be notified if we only receive the model id (no BLE address) even if |
| // the user is opted in. |
| feature_list.InitWithFeatures( |
| /*enabled_features=*/{features::kFastPairSavedDevices, |
| features::kFastPairSavedDevicesStrictOptIn}, |
| /*disabled_features=*/{}); |
| fast_pair_repository_->SetOptInStatus( |
| nearby::fastpair::OptInStatus::STATUS_OPTED_IN); |
| base::RunLoop().RunUntilIdle(); |
| CreateRetroactivePairingDetector(); |
| |
| EXPECT_FALSE(retroactive_pair_found_); |
| |
| fake_socket_->SetIOBufferFromBytes(kModelIdBytes); |
| PairFastPairDeviceWithClassicBluetooth( |
| /*new_paired_status=*/true, kTestDeviceAddress); |
| base::RunLoop().RunUntilIdle(); |
| |
| NotifyMessageStreamConnected(kTestDeviceAddress); |
| base::RunLoop().RunUntilIdle(); |
| |
| fake_socket_->TriggerReceiveCallback(); |
| base::RunLoop().RunUntilIdle(); |
| |
| EXPECT_FALSE(retroactive_pair_found_); |
| } |
| |
| TEST_F(RetroactivePairingDetectorTest, |
| MessageStream_Observer_ModelId_FlagDisabled) { |
| Login(user_manager::UserType::kRegular); |
| base::test::ScopedFeatureList feature_list; |
| |
| // With the SavedDevices and StrictOptIn flags disabled, we do not expect |
| // to be notified if we only receive the model id (no BLE address) even if |
| // the user is opted out. Opt-in status shouldn't matter for notifying with |
| // the flags disabled, but here, since we don't have the information we need |
| // from the device for retroactive pairing, then we expect to not be |
| // notified. |
| feature_list.InitWithFeatures( |
| /*enabled_features=*/{}, |
| /*disabled_features=*/{features::kFastPairSavedDevices, |
| features::kFastPairSavedDevicesStrictOptIn}); |
| fast_pair_repository_->SetOptInStatus( |
| nearby::fastpair::OptInStatus::STATUS_OPTED_OUT); |
| base::RunLoop().RunUntilIdle(); |
| CreateRetroactivePairingDetector(); |
| |
| EXPECT_FALSE(retroactive_pair_found_); |
| |
| fake_socket_->SetIOBufferFromBytes(kModelIdBytes); |
| PairFastPairDeviceWithClassicBluetooth( |
| /*new_paired_status=*/true, kTestDeviceAddress); |
| base::RunLoop().RunUntilIdle(); |
| |
| NotifyMessageStreamConnected(kTestDeviceAddress); |
| base::RunLoop().RunUntilIdle(); |
| |
| fake_socket_->TriggerReceiveCallback(); |
| base::RunLoop().RunUntilIdle(); |
| |
| EXPECT_FALSE(retroactive_pair_found_); |
| } |
| |
| TEST_F(RetroactivePairingDetectorTest, |
| MessageStream_Observer_ModelId_StrictFlagDisabled) { |
| Login(user_manager::UserType::kRegular); |
| base::test::ScopedFeatureList feature_list; |
| |
| // With only the StrictOptIn flag disabled, we do not expect |
| // to be notified if we only receive the model id (no BLE address) even if |
| // the user is opted out. Opt-in status shouldn't matter for notifying with |
| // the flags disabled, but here, since we don't have the information we need |
| // from the device for retroactive pairing, then we expect to not be |
| // notified. |
| feature_list.InitWithFeatures( |
| /*enabled_features=*/{features::kFastPairSavedDevices}, |
| /*disabled_features=*/{features::kFastPairSavedDevicesStrictOptIn}); |
| fast_pair_repository_->SetOptInStatus( |
| nearby::fastpair::OptInStatus::STATUS_OPTED_OUT); |
| base::RunLoop().RunUntilIdle(); |
| CreateRetroactivePairingDetector(); |
| |
| EXPECT_FALSE(retroactive_pair_found_); |
| |
| fake_socket_->SetIOBufferFromBytes(kModelIdBytes); |
| PairFastPairDeviceWithClassicBluetooth( |
| /*new_paired_status=*/true, kTestDeviceAddress); |
| base::RunLoop().RunUntilIdle(); |
| |
| NotifyMessageStreamConnected(kTestDeviceAddress); |
| base::RunLoop().RunUntilIdle(); |
| |
| fake_socket_->TriggerReceiveCallback(); |
| base::RunLoop().RunUntilIdle(); |
| |
| EXPECT_FALSE(retroactive_pair_found_); |
| } |
| |
| TEST_F(RetroactivePairingDetectorTest, |
| MessageStream_Observer_ModelId_SavedFlagDisabled) { |
| Login(user_manager::UserType::kRegular); |
| base::test::ScopedFeatureList feature_list; |
| |
| // With only the SavedDevices flag disabled, we do not expect |
| // to be notified if we only receive the model id (no BLE address) even if |
| // the user is opted out. Opt-in status shouldn't matter for notifying with |
| // the flags disabled, but here, since we don't have the information we need |
| // from the device for retroactive pairing, then we expect to not be |
| // notified. |
| feature_list.InitWithFeatures( |
| /*enabled_features=*/{features::kFastPairSavedDevicesStrictOptIn}, |
| /*disabled_features=*/{features::kFastPairSavedDevices}); |
| fast_pair_repository_->SetOptInStatus( |
| nearby::fastpair::OptInStatus::STATUS_OPTED_OUT); |
| base::RunLoop().RunUntilIdle(); |
| CreateRetroactivePairingDetector(); |
| |
| EXPECT_FALSE(retroactive_pair_found_); |
| |
| fake_socket_->SetIOBufferFromBytes(kModelIdBytes); |
| PairFastPairDeviceWithClassicBluetooth( |
| /*new_paired_status=*/true, kTestDeviceAddress); |
| base::RunLoop().RunUntilIdle(); |
| |
| NotifyMessageStreamConnected(kTestDeviceAddress); |
| base::RunLoop().RunUntilIdle(); |
| |
| fake_socket_->TriggerReceiveCallback(); |
| base::RunLoop().RunUntilIdle(); |
| |
| EXPECT_FALSE(retroactive_pair_found_); |
| } |
| |
| TEST_F(RetroactivePairingDetectorTest, |
| MessageStreamRemovedOnDestroyed_FlagEnabled) { |
| Login(user_manager::UserType::kRegular); |
| fast_pair_repository_->SetOptInStatus( |
| nearby::fastpair::OptInStatus::STATUS_OPTED_IN); |
| base::test::ScopedFeatureList feature_list; |
| |
| // This test is verifying that we are notified when the MessageStream |
| // is destroyed, and properly remove the MessageStream. The opt-in status |
| // and flags set should not impact this behavior. |
| feature_list.InitWithFeatures( |
| /*enabled_features=*/{features::kFastPairSavedDevices, |
| features::kFastPairSavedDevicesStrictOptIn}, |
| /*disabled_features=*/{}); |
| base::RunLoop().RunUntilIdle(); |
| CreateRetroactivePairingDetector(); |
| |
| EXPECT_FALSE(retroactive_pair_found_); |
| |
| SetMessageStream(kModelIdBleAddressBytes); |
| PairFastPairDeviceWithClassicBluetooth( |
| /*new_paired_status=*/true, kTestDeviceAddress); |
| |
| NotifyMessageStreamConnected(kTestDeviceAddress); |
| base::RunLoop().RunUntilIdle(); |
| |
| message_stream_.reset(); |
| fake_socket_->TriggerReceiveCallback(); |
| base::RunLoop().RunUntilIdle(); |
| |
| EXPECT_FALSE(retroactive_pair_found_); |
| } |
| |
| TEST_F(RetroactivePairingDetectorTest, |
| MessageStreamRemovedOnDestroyed_FlagDisabled) { |
| Login(user_manager::UserType::kRegular); |
| fast_pair_repository_->SetOptInStatus( |
| nearby::fastpair::OptInStatus::STATUS_OPTED_OUT); |
| base::test::ScopedFeatureList feature_list; |
| |
| // This test is verifying that we are notified when the MessageStream |
| // is destroyed, and properly remove the MessageStream. The opt-in status |
| // and flags set should not impact this behavior. |
| feature_list.InitWithFeatures( |
| /*enabled_features=*/{}, |
| /*disabled_features=*/{features::kFastPairSavedDevices, |
| features::kFastPairSavedDevicesStrictOptIn}); |
| base::RunLoop().RunUntilIdle(); |
| CreateRetroactivePairingDetector(); |
| |
| EXPECT_FALSE(retroactive_pair_found_); |
| |
| SetMessageStream(kModelIdBleAddressBytes); |
| PairFastPairDeviceWithClassicBluetooth( |
| /*new_paired_status=*/true, kTestDeviceAddress); |
| |
| NotifyMessageStreamConnected(kTestDeviceAddress); |
| base::RunLoop().RunUntilIdle(); |
| |
| message_stream_.reset(); |
| fake_socket_->TriggerReceiveCallback(); |
| base::RunLoop().RunUntilIdle(); |
| |
| EXPECT_FALSE(retroactive_pair_found_); |
| } |
| |
| TEST_F(RetroactivePairingDetectorTest, |
| MessageStreamRemovedOnDestroyed_StrictFlagDisabled) { |
| Login(user_manager::UserType::kRegular); |
| fast_pair_repository_->SetOptInStatus( |
| nearby::fastpair::OptInStatus::STATUS_OPTED_OUT); |
| base::test::ScopedFeatureList feature_list; |
| |
| // This test is verifying that we are notified when the MessageStream |
| // is destroyed, and properly remove the MessageStream. The opt-in status |
| // and flags set should not impact this behavior. |
| feature_list.InitWithFeatures( |
| /*enabled_features=*/{features::kFastPairSavedDevices}, |
| /*disabled_features=*/{features::kFastPairSavedDevicesStrictOptIn}); |
| base::RunLoop().RunUntilIdle(); |
| CreateRetroactivePairingDetector(); |
| |
| EXPECT_FALSE(retroactive_pair_found_); |
| |
| SetMessageStream(kModelIdBleAddressBytes); |
| PairFastPairDeviceWithClassicBluetooth( |
| /*new_paired_status=*/true, kTestDeviceAddress); |
| |
| NotifyMessageStreamConnected(kTestDeviceAddress); |
| base::RunLoop().RunUntilIdle(); |
| |
| message_stream_.reset(); |
| fake_socket_->TriggerReceiveCallback(); |
| base::RunLoop().RunUntilIdle(); |
| |
| EXPECT_FALSE(retroactive_pair_found_); |
| } |
| |
| TEST_F(RetroactivePairingDetectorTest, |
| MessageStreamRemovedOnDestroyed_SavedFlagDisabled) { |
| Login(user_manager::UserType::kRegular); |
| fast_pair_repository_->SetOptInStatus( |
| nearby::fastpair::OptInStatus::STATUS_OPTED_OUT); |
| base::test::ScopedFeatureList feature_list; |
| |
| // This test is verifying that we are notified when the Message Stream |
| // is destroyed, and properly remove the Message Stream. The opt-in status |
| // and flags set should not impact this behavior. |
| feature_list.InitWithFeatures( |
| /*enabled_features=*/{features::kFastPairSavedDevicesStrictOptIn}, |
| /*disabled_features=*/{features::kFastPairSavedDevices}); |
| base::RunLoop().RunUntilIdle(); |
| CreateRetroactivePairingDetector(); |
| |
| EXPECT_FALSE(retroactive_pair_found_); |
| |
| SetMessageStream(kModelIdBleAddressBytes); |
| PairFastPairDeviceWithClassicBluetooth( |
| /*new_paired_status=*/true, kTestDeviceAddress); |
| |
| NotifyMessageStreamConnected(kTestDeviceAddress); |
| base::RunLoop().RunUntilIdle(); |
| |
| message_stream_.reset(); |
| fake_socket_->TriggerReceiveCallback(); |
| base::RunLoop().RunUntilIdle(); |
| |
| EXPECT_FALSE(retroactive_pair_found_); |
| } |
| |
| TEST_F(RetroactivePairingDetectorTest, |
| MessageStreamRemovedOnDisconnect_FlagEnabled) { |
| Login(user_manager::UserType::kRegular); |
| base::test::ScopedFeatureList feature_list; |
| |
| // This test is verifying that we are notified when the Message Stream |
| // is destroyed, and properly remove the Message Stream. The opt-in status |
| // and flags set should not impact this behavior. |
| feature_list.InitWithFeatures( |
| /*enabled_features=*/{features::kFastPairSavedDevices, |
| features::kFastPairSavedDevicesStrictOptIn}, |
| /*disabled_features=*/{}); |
| fast_pair_repository_->SetOptInStatus( |
| nearby::fastpair::OptInStatus::STATUS_OPTED_IN); |
| base::RunLoop().RunUntilIdle(); |
| CreateRetroactivePairingDetector(); |
| |
| EXPECT_FALSE(retroactive_pair_found_); |
| |
| fake_socket_->SetErrorReason( |
| device::BluetoothSocket::ErrorReason::kDisconnected); |
| fake_socket_->TriggerReceiveCallback(); |
| base::RunLoop().RunUntilIdle(); |
| |
| message_stream_ = |
| std::make_unique<MessageStream>(kTestDeviceAddress, fake_socket_.get()); |
| PairFastPairDeviceWithClassicBluetooth( |
| /*new_paired_status=*/true, kTestDeviceAddress); |
| base::RunLoop().RunUntilIdle(); |
| |
| NotifyMessageStreamConnected(kTestDeviceAddress); |
| base::RunLoop().RunUntilIdle(); |
| |
| fake_socket_->SetIOBufferFromBytes(kModelIdBytes); |
| fake_socket_->TriggerReceiveCallback(); |
| base::RunLoop().RunUntilIdle(); |
| |
| EXPECT_FALSE(retroactive_pair_found_); |
| } |
| |
| TEST_F(RetroactivePairingDetectorTest, |
| MessageStreamRemovedOnDisconnect_FlagDisabled) { |
| Login(user_manager::UserType::kRegular); |
| base::test::ScopedFeatureList feature_list; |
| |
| // This test is verifying that we are notified when the Message Stream |
| // is destroyed, and properly remove the Message Stream. The opt-in status |
| // and flags set should not impact this behavior. |
| feature_list.InitWithFeatures( |
| /*enabled_features=*/{}, |
| /*disabled_features=*/{features::kFastPairSavedDevices, |
| features::kFastPairSavedDevicesStrictOptIn}); |
| fast_pair_repository_->SetOptInStatus( |
| nearby::fastpair::OptInStatus::STATUS_OPTED_OUT); |
| base::RunLoop().RunUntilIdle(); |
| CreateRetroactivePairingDetector(); |
| |
| EXPECT_FALSE(retroactive_pair_found_); |
| |
| fake_socket_->SetErrorReason( |
| device::BluetoothSocket::ErrorReason::kDisconnected); |
| fake_socket_->TriggerReceiveCallback(); |
| base::RunLoop().RunUntilIdle(); |
| |
| message_stream_ = |
| std::make_unique<MessageStream>(kTestDeviceAddress, fake_socket_.get()); |
| PairFastPairDeviceWithClassicBluetooth( |
| /*new_paired_status=*/true, kTestDeviceAddress); |
| base::RunLoop().RunUntilIdle(); |
| |
| NotifyMessageStreamConnected(kTestDeviceAddress); |
| base::RunLoop().RunUntilIdle(); |
| |
| fake_socket_->SetIOBufferFromBytes(kModelIdBytes); |
| fake_socket_->TriggerReceiveCallback(); |
| base::RunLoop().RunUntilIdle(); |
| |
| EXPECT_FALSE(retroactive_pair_found_); |
| } |
| |
| TEST_F(RetroactivePairingDetectorTest, |
| MessageStreamRemovedOnDisconnect_StrictFlagDisabled) { |
| Login(user_manager::UserType::kRegular); |
| base::test::ScopedFeatureList feature_list; |
| |
| // This test is verifying that we are notified when the Message Stream |
| // is destroyed, and properly remove the Message Stream. The opt-in status |
| // and flags set should not impact this behavior. |
| feature_list.InitWithFeatures( |
| /*enabled_features=*/{features::kFastPairSavedDevices}, |
| /*disabled_features=*/{features::kFastPairSavedDevicesStrictOptIn}); |
| fast_pair_repository_->SetOptInStatus( |
| nearby::fastpair::OptInStatus::STATUS_OPTED_OUT); |
| base::RunLoop().RunUntilIdle(); |
| CreateRetroactivePairingDetector(); |
| |
| EXPECT_FALSE(retroactive_pair_found_); |
| |
| fake_socket_->SetErrorReason( |
| device::BluetoothSocket::ErrorReason::kDisconnected); |
| fake_socket_->TriggerReceiveCallback(); |
| base::RunLoop().RunUntilIdle(); |
| |
| message_stream_ = |
| std::make_unique<MessageStream>(kTestDeviceAddress, fake_socket_.get()); |
| PairFastPairDeviceWithClassicBluetooth( |
| /*new_paired_status=*/true, kTestDeviceAddress); |
| base::RunLoop().RunUntilIdle(); |
| |
| NotifyMessageStreamConnected(kTestDeviceAddress); |
| base::RunLoop().RunUntilIdle(); |
| |
| fake_socket_->SetIOBufferFromBytes(kModelIdBytes); |
| fake_socket_->TriggerReceiveCallback(); |
| base::RunLoop().RunUntilIdle(); |
| |
| EXPECT_FALSE(retroactive_pair_found_); |
| } |
| |
| TEST_F(RetroactivePairingDetectorTest, |
| MessageStreamRemovedOnDisconnect_SavedFlagDisabled) { |
| Login(user_manager::UserType::kRegular); |
| base::test::ScopedFeatureList feature_list; |
| |
| // This test is verifying that we are notified when the Message Stream |
| // is destroyed, and properly remove the Message Stream. The opt-in status |
| // and flags set should not impact this behavior. |
| feature_list.InitWithFeatures( |
| /*enabled_features=*/{features::kFastPairSavedDevicesStrictOptIn}, |
| /*disabled_features=*/{features::kFastPairSavedDevices}); |
| fast_pair_repository_->SetOptInStatus( |
| nearby::fastpair::OptInStatus::STATUS_OPTED_OUT); |
| base::RunLoop().RunUntilIdle(); |
| CreateRetroactivePairingDetector(); |
| |
| EXPECT_FALSE(retroactive_pair_found_); |
| |
| fake_socket_->SetErrorReason( |
| device::BluetoothSocket::ErrorReason::kDisconnected); |
| fake_socket_->TriggerReceiveCallback(); |
| base::RunLoop().RunUntilIdle(); |
| |
| message_stream_ = |
| std::make_unique<MessageStream>(kTestDeviceAddress, fake_socket_.get()); |
| PairFastPairDeviceWithClassicBluetooth( |
| /*new_paired_status=*/true, kTestDeviceAddress); |
| base::RunLoop().RunUntilIdle(); |
| |
| NotifyMessageStreamConnected(kTestDeviceAddress); |
| base::RunLoop().RunUntilIdle(); |
| |
| fake_socket_->SetIOBufferFromBytes(kModelIdBytes); |
| fake_socket_->TriggerReceiveCallback(); |
| base::RunLoop().RunUntilIdle(); |
| |
| EXPECT_FALSE(retroactive_pair_found_); |
| } |
| |
| TEST_F(RetroactivePairingDetectorTest, DontNotify_OptedOut_FlagEnabled) { |
| Login(user_manager::UserType::kRegular); |
| base::test::ScopedFeatureList feature_list; |
| |
| // If the SavedDevices and StrictOptIn flags are enabled and the user is |
| // opted out, we expect not to be notified for retroactive pairing even if |
| // a potential one is found. |
| feature_list.InitWithFeatures( |
| /*enabled_features=*/{features::kFastPairSavedDevices, |
| features::kFastPairSavedDevicesStrictOptIn}, |
| /*disabled_features=*/{}); |
| fast_pair_repository_->SetOptInStatus( |
| nearby::fastpair::OptInStatus::STATUS_OPTED_OUT); |
| base::RunLoop().RunUntilIdle(); |
| CreateRetroactivePairingDetector(); |
| |
| EXPECT_FALSE(retroactive_pair_found_); |
| |
| fake_socket_->SetIOBufferFromBytes(kModelIdBleAddressBytes); |
| PairFastPairDeviceWithClassicBluetooth( |
| /*new_paired_status=*/true, kTestDeviceAddress); |
| base::RunLoop().RunUntilIdle(); |
| |
| NotifyMessageStreamConnected(kTestDeviceAddress); |
| base::RunLoop().RunUntilIdle(); |
| |
| fake_socket_->TriggerReceiveCallback(); |
| base::RunLoop().RunUntilIdle(); |
| |
| EXPECT_FALSE(retroactive_pair_found_); |
| } |
| |
| TEST_F(RetroactivePairingDetectorTest, Notify_OptedOut_FlagDisabled) { |
| Login(user_manager::UserType::kRegular); |
| base::test::ScopedFeatureList feature_list; |
| |
| // If the SavedDevices and StrictOptIn flags are disabled, we expect to be |
| // notified when a retroactive pairing is found even if the user is opted out. |
| feature_list.InitWithFeatures( |
| /*enabled_features=*/{}, |
| /*disabled_features=*/{features::kFastPairSavedDevices, |
| features::kFastPairSavedDevicesStrictOptIn}); |
| fast_pair_repository_->SetOptInStatus( |
| nearby::fastpair::OptInStatus::STATUS_OPTED_OUT); |
| base::RunLoop().RunUntilIdle(); |
| CreateRetroactivePairingDetector(); |
| |
| EXPECT_FALSE(retroactive_pair_found_); |
| |
| fake_socket_->SetIOBufferFromBytes(kModelIdBleAddressBytes); |
| PairFastPairDeviceWithClassicBluetooth( |
| /*new_paired_status=*/true, kTestDeviceAddress); |
| base::RunLoop().RunUntilIdle(); |
| |
| NotifyMessageStreamConnected(kTestDeviceAddress); |
| base::RunLoop().RunUntilIdle(); |
| |
| fake_socket_->TriggerReceiveCallback(); |
| base::RunLoop().RunUntilIdle(); |
| |
| EXPECT_TRUE(retroactive_pair_found_); |
| } |
| |
| TEST_F(RetroactivePairingDetectorTest, Notify_OptedOut_StrictFlagDisabled) { |
| Login(user_manager::UserType::kRegular); |
| base::test::ScopedFeatureList feature_list; |
| |
| // If the SavedDevices flag is enabled but the StrictOptin flag is disabled, |
| // then we expect to be notified even if the user is opted out of saving |
| // devices to their account. |
| feature_list.InitWithFeatures( |
| /*enabled_features=*/{features::kFastPairSavedDevices}, |
| /*disabled_features=*/{features::kFastPairSavedDevicesStrictOptIn}); |
| fast_pair_repository_->SetOptInStatus( |
| nearby::fastpair::OptInStatus::STATUS_OPTED_OUT); |
| base::RunLoop().RunUntilIdle(); |
| CreateRetroactivePairingDetector(); |
| |
| EXPECT_FALSE(retroactive_pair_found_); |
| |
| fake_socket_->SetIOBufferFromBytes(kModelIdBleAddressBytes); |
| PairFastPairDeviceWithClassicBluetooth( |
| /*new_paired_status=*/true, kTestDeviceAddress); |
| base::RunLoop().RunUntilIdle(); |
| |
| NotifyMessageStreamConnected(kTestDeviceAddress); |
| base::RunLoop().RunUntilIdle(); |
| |
| fake_socket_->TriggerReceiveCallback(); |
| base::RunLoop().RunUntilIdle(); |
| |
| EXPECT_TRUE(retroactive_pair_found_); |
| } |
| |
| TEST_F(RetroactivePairingDetectorTest, Notify_OptedOut_SavedFlagDisabled) { |
| Login(user_manager::UserType::kRegular); |
| base::test::ScopedFeatureList feature_list; |
| |
| // If the SavedDevices flag is disabled but the StrictOptin flag is enabled, |
| // then we expect to be notified even if the user is opted out of saving |
| // devices to their account. |
| feature_list.InitWithFeatures( |
| /*enabled_features=*/{features::kFastPairSavedDevicesStrictOptIn}, |
| /*disabled_features=*/{features::kFastPairSavedDevices}); |
| fast_pair_repository_->SetOptInStatus( |
| nearby::fastpair::OptInStatus::STATUS_OPTED_OUT); |
| base::RunLoop().RunUntilIdle(); |
| CreateRetroactivePairingDetector(); |
| |
| EXPECT_FALSE(retroactive_pair_found_); |
| |
| fake_socket_->SetIOBufferFromBytes(kModelIdBleAddressBytes); |
| PairFastPairDeviceWithClassicBluetooth( |
| /*new_paired_status=*/true, kTestDeviceAddress); |
| base::RunLoop().RunUntilIdle(); |
| |
| NotifyMessageStreamConnected(kTestDeviceAddress); |
| base::RunLoop().RunUntilIdle(); |
| |
| fake_socket_->TriggerReceiveCallback(); |
| base::RunLoop().RunUntilIdle(); |
| |
| EXPECT_TRUE(retroactive_pair_found_); |
| } |
| |
| TEST_F(RetroactivePairingDetectorTest, Notify_OptedIn_FlagDisabled) { |
| Login(user_manager::UserType::kRegular); |
| base::test::ScopedFeatureList feature_list; |
| feature_list.InitWithFeatures( |
| /*enabled_features=*/{}, |
| /*disabled_features=*/{features::kFastPairSavedDevices, |
| features::kFastPairSavedDevicesStrictOptIn}); |
| fast_pair_repository_->SetOptInStatus( |
| nearby::fastpair::OptInStatus::STATUS_OPTED_IN); |
| base::RunLoop().RunUntilIdle(); |
| CreateRetroactivePairingDetector(); |
| |
| EXPECT_FALSE(retroactive_pair_found_); |
| |
| fake_socket_->SetIOBufferFromBytes(kModelIdBleAddressBytes); |
| PairFastPairDeviceWithClassicBluetooth( |
| /*new_paired_status=*/true, kTestDeviceAddress); |
| base::RunLoop().RunUntilIdle(); |
| |
| NotifyMessageStreamConnected(kTestDeviceAddress); |
| base::RunLoop().RunUntilIdle(); |
| |
| fake_socket_->TriggerReceiveCallback(); |
| base::RunLoop().RunUntilIdle(); |
| |
| EXPECT_TRUE(retroactive_pair_found_); |
| } |
| |
| TEST_F(RetroactivePairingDetectorTest, Notify_OptedIn_StrictFlagDisabled) { |
| Login(user_manager::UserType::kRegular); |
| base::test::ScopedFeatureList feature_list; |
| |
| // When the strict interpretation is disabled, we expect to be notified about |
| // a retroactive pairing regardless of opt-in status. |
| feature_list.InitWithFeatures( |
| /*enabled_features=*/{features::kFastPairSavedDevices}, |
| /*disabled_features=*/{features::kFastPairSavedDevicesStrictOptIn}); |
| fast_pair_repository_->SetOptInStatus( |
| nearby::fastpair::OptInStatus::STATUS_OPTED_IN); |
| base::RunLoop().RunUntilIdle(); |
| CreateRetroactivePairingDetector(); |
| |
| EXPECT_FALSE(retroactive_pair_found_); |
| |
| fake_socket_->SetIOBufferFromBytes(kModelIdBleAddressBytes); |
| PairFastPairDeviceWithClassicBluetooth( |
| /*new_paired_status=*/true, kTestDeviceAddress); |
| base::RunLoop().RunUntilIdle(); |
| |
| NotifyMessageStreamConnected(kTestDeviceAddress); |
| base::RunLoop().RunUntilIdle(); |
| |
| fake_socket_->TriggerReceiveCallback(); |
| base::RunLoop().RunUntilIdle(); |
| |
| EXPECT_TRUE(retroactive_pair_found_); |
| } |
| |
| TEST_F(RetroactivePairingDetectorTest, Notify_OptedIn_SavedFlagDisabled) { |
| Login(user_manager::UserType::kRegular); |
| base::test::ScopedFeatureList feature_list; |
| |
| // When only the SavedDevices flag is disabled, we expect to be notified about |
| // a retroactive pairing regardless of opt-in status. |
| feature_list.InitWithFeatures( |
| /*enabled_features=*/{features::kFastPairSavedDevicesStrictOptIn}, |
| /*disabled_features=*/{features::kFastPairSavedDevices}); |
| fast_pair_repository_->SetOptInStatus( |
| nearby::fastpair::OptInStatus::STATUS_OPTED_IN); |
| base::RunLoop().RunUntilIdle(); |
| CreateRetroactivePairingDetector(); |
| |
| EXPECT_FALSE(retroactive_pair_found_); |
| |
| fake_socket_->SetIOBufferFromBytes(kModelIdBleAddressBytes); |
| PairFastPairDeviceWithClassicBluetooth( |
| /*new_paired_status=*/true, kTestDeviceAddress); |
| base::RunLoop().RunUntilIdle(); |
| |
| NotifyMessageStreamConnected(kTestDeviceAddress); |
| base::RunLoop().RunUntilIdle(); |
| |
| fake_socket_->TriggerReceiveCallback(); |
| base::RunLoop().RunUntilIdle(); |
| |
| EXPECT_TRUE(retroactive_pair_found_); |
| } |
| |
| TEST_F(RetroactivePairingDetectorTest, |
| DontNotify_OptedOut_OptedIn_FlagEnabled) { |
| Login(user_manager::UserType::kRegular); |
| base::test::ScopedFeatureList feature_list; |
| feature_list.InitWithFeatures( |
| /*enabled_features=*/{features::kFastPairSavedDevices, |
| features::kFastPairSavedDevicesStrictOptIn}, |
| /*disabled_features=*/{}); |
| |
| // Simulate user is opted out. |
| fast_pair_repository_->SetOptInStatus( |
| nearby::fastpair::OptInStatus::STATUS_OPTED_OUT); |
| base::RunLoop().RunUntilIdle(); |
| CreateRetroactivePairingDetector(); |
| |
| EXPECT_FALSE(retroactive_pair_found_); |
| |
| fake_socket_->SetIOBufferFromBytes(kModelIdBleAddressBytes); |
| PairFastPairDeviceWithClassicBluetooth( |
| /*new_paired_status=*/true, kTestDeviceAddress); |
| base::RunLoop().RunUntilIdle(); |
| |
| NotifyMessageStreamConnected(kTestDeviceAddress); |
| base::RunLoop().RunUntilIdle(); |
| |
| fake_socket_->TriggerReceiveCallback(); |
| base::RunLoop().RunUntilIdle(); |
| |
| EXPECT_FALSE(retroactive_pair_found_); |
| |
| // Simulate user is opted in. Now we would expect to be notified of a |
| // retroactive pairing scenario when the flags are enabled for a |
| // strict interpretation of the opt in status. |
| fast_pair_repository_->SetOptInStatus( |
| nearby::fastpair::OptInStatus::STATUS_OPTED_IN); |
| |
| fake_socket_->SetIOBufferFromBytes(kModelIdBleAddressBytes); |
| PairFastPairDeviceWithClassicBluetooth( |
| /*new_paired_status=*/true, kTestDeviceAddress); |
| base::RunLoop().RunUntilIdle(); |
| |
| NotifyMessageStreamConnected(kTestDeviceAddress); |
| base::RunLoop().RunUntilIdle(); |
| |
| fake_socket_->TriggerReceiveCallback(); |
| base::RunLoop().RunUntilIdle(); |
| |
| EXPECT_TRUE(retroactive_pair_found_); |
| EXPECT_EQ(retroactive_device_->ble_address(), kBleAddress); |
| EXPECT_EQ(retroactive_device_->metadata_id(), kModelId); |
| } |
| |
| TEST_F(RetroactivePairingDetectorTest, DontNotifyIfAlreadySavedToAcount) { |
| Login(user_manager::UserType::kRegular); |
| base::test::ScopedFeatureList feature_list; |
| fast_pair_repository_->SaveMacAddressToAccount(kTestDeviceAddress); |
| |
| // If the SavedDevices and StrictOptIn flags are disabled, we may expect to be |
| // notified when a retroactive pairing is found even if the user is opted out. |
| // However, since the device is already saved the account, we expect to not |
| // be notified. |
| feature_list.InitWithFeatures( |
| /*enabled_features=*/{}, |
| /*disabled_features=*/{features::kFastPairSavedDevices, |
| features::kFastPairSavedDevicesStrictOptIn}); |
| fast_pair_repository_->SetOptInStatus( |
| nearby::fastpair::OptInStatus::STATUS_OPTED_OUT); |
| base::RunLoop().RunUntilIdle(); |
| CreateRetroactivePairingDetector(); |
| |
| EXPECT_FALSE(retroactive_pair_found_); |
| |
| fake_socket_->SetIOBufferFromBytes(kModelIdBleAddressBytes); |
| PairFastPairDeviceWithClassicBluetooth( |
| /*new_paired_status=*/true, kTestDeviceAddress); |
| base::RunLoop().RunUntilIdle(); |
| |
| NotifyMessageStreamConnected(kTestDeviceAddress); |
| base::RunLoop().RunUntilIdle(); |
| |
| fake_socket_->TriggerReceiveCallback(); |
| base::RunLoop().RunUntilIdle(); |
| |
| EXPECT_FALSE(retroactive_pair_found_); |
| } |
| |
| // There are two ways to get to `CheckAndRemoveIfDeviceExpired `. One is by |
| // `GetModelIdAndAddressFromMessageStream` which is triggered when the |
| // MessageStream already has the model id and BLE address messages on |
| // connection. The second way is through `CheckPairingInformation` which is |
| // triggered when the MessageStream does not have the model id and BLE |
| // address on connection, and the model id and BLE address are observed later |
| // on. |
| TEST_F(RetroactivePairingDetectorTest, |
| DontNotify_ExpiryTimeoutReached_GetModelIdAndAddressFromMessageStream) { |
| Login(user_manager::UserType::kRegular); |
| base::test::ScopedFeatureList feature_list; |
| feature_list.InitWithFeatures( |
| /*enabled_features=*/{features::kFastPairSavedDevices}, |
| /*disabled_features=*/{features::kFastPairSavedDevicesStrictOptIn}); |
| fast_pair_repository_->SetOptInStatus( |
| nearby::fastpair::OptInStatus::STATUS_OPTED_OUT); |
| base::RunLoop().RunUntilIdle(); |
| CreateRetroactivePairingDetector(); |
| |
| EXPECT_FALSE(retroactive_pair_found_); |
| |
| // Pair a device with classic Bluetooth pairing and set the MessageStream |
| // with model id and BLE address bytes to successfully detect the scenario. |
| // At this point, the device is in the `device_pairing_information_` map with |
| // an expiry timestamp. |
| SetMessageStream(kModelIdBleAddressBytes); |
| PairFastPairDeviceWithClassicBluetooth( |
| /*new_paired_status=*/true, kTestDeviceAddress); |
| |
| // Fast forward by |kRetroactiveDevicePairingTimeout| in order to simulate |
| // that the device's |expiry_timestamp| has been reached. Because the |
| // timeout has been reached, we expect that the retroactive pairing |
| // scenario to not be triggered. |
| task_environment()->FastForwardBy(kRetroactiveDevicePairingTimeout); |
| fake_socket_->TriggerReceiveCallback(); |
| NotifyMessageStreamConnected(kTestDeviceAddress); |
| base::RunLoop().RunUntilIdle(); |
| |
| EXPECT_FALSE(retroactive_pair_found_); |
| } |
| |
| TEST_F(RetroactivePairingDetectorTest, |
| DontNotify_ExpiryTimeoutReached_CheckPairingInformation) { |
| Login(user_manager::UserType::kRegular); |
| base::test::ScopedFeatureList feature_list; |
| feature_list.InitWithFeatures( |
| /*enabled_features=*/{features::kFastPairSavedDevices}, |
| /*disabled_features=*/{features::kFastPairSavedDevicesStrictOptIn}); |
| fast_pair_repository_->SetOptInStatus( |
| nearby::fastpair::OptInStatus::STATUS_OPTED_OUT); |
| base::RunLoop().RunUntilIdle(); |
| CreateRetroactivePairingDetector(); |
| |
| EXPECT_FALSE(retroactive_pair_found_); |
| |
| // Pair a device with classic Bluetooth pairing and set the MessageStream |
| // with no bytes to successfully detect the scenario. |
| // At this point, the device is in the `device_pairing_information_` map with |
| // an expiry timestamp. Because there are no BLE address bytes or model id |
| // bytes in the connected MessageStream, the RetroactivePairingDetector adds |
| // itself as an observer to wait for these messages. |
| PairFastPairDeviceWithClassicBluetooth( |
| /*new_paired_status=*/true, kTestDeviceAddress); |
| NotifyMessageStreamConnected(kTestDeviceAddress); |
| |
| // Fast forward by |kRetroactiveDevicePairingTimeout| in order to simulate |
| // that the device's |expiry_timestamp| has been reached. Because the |
| // timeout has been reached, we expect that the retroactive pairing |
| // scenario to not be triggered. |
| task_environment()->FastForwardBy(kRetroactiveDevicePairingTimeout); |
| |
| // Set up the socket with the model id bytes and BLE address bytes to |
| // successfully detect the scenario, and trigger the bytes being received |
| // after the timeout to trigger the check in `CheckPairingInformation` |
| // which happens in the overridden observed red functions for |
| // `OnModelIdMessage` and `OnBleAddressUpdateMessage`. |
| fake_socket_->SetIOBufferFromBytes(kModelIdBleAddressBytes); |
| |
| // TODO(b/263391358): Refactor `TriggerReceiveCallback` to take a |
| // base::RunLoop parameter and remove `base::RunLoop().RunUntilIdle()`. |
| fake_socket_->TriggerReceiveCallback(); |
| base::RunLoop().RunUntilIdle(); |
| |
| EXPECT_FALSE(retroactive_pair_found_); |
| } |
| |
| TEST_F( |
| RetroactivePairingDetectorTest, |
| DontNotify_ExpiryTimeoutReached_DifferentDeviceTriggerRemoval_DeviceToBeRemovedHashesToFirstPosition) { |
| Login(user_manager::UserType::kRegular); |
| base::test::ScopedFeatureList feature_list; |
| feature_list.InitWithFeatures( |
| /*enabled_features=*/{features::kFastPairSavedDevices}, |
| /*disabled_features=*/{features::kFastPairSavedDevicesStrictOptIn}); |
| fast_pair_repository_->SetOptInStatus( |
| nearby::fastpair::OptInStatus::STATUS_OPTED_OUT); |
| base::RunLoop().RunUntilIdle(); |
| CreateRetroactivePairingDetector(); |
| |
| EXPECT_FALSE(retroactive_pair_found_); |
| |
| // Simulate a first device being found with classic Bluetooth pairing. |
| // At this point, the device is in the `device_pairing_information_` map with |
| // an expiry timestamp. This device does not have a MessageStream associated, |
| // so `CheckPairingInformation` will never be fired because it doesn't have |
| // a model id or BLE event, and thus alone, its expiry event will never be |
| // triggered. |
| // |
| // |kTestDeviceAddress| hashes to the first position in the map, and we |
| // expect the removing it from the map of devices will not cause a crash |
| // from an invalid iterator when we increment to continue iterating. |
| PairFastPairDeviceWithClassicBluetooth( |
| /*new_paired_status=*/true, kTestDeviceAddress); |
| |
| // Fast forward by |kRetroactiveDevicePairingTimeout| in order to simulate |
| // that the device's |expiry_timestamp| has been reached. |
| task_environment()->FastForwardBy(kRetroactiveDevicePairingTimeout); |
| |
| // Simulate another device being found for retroactive pairing. This device |
| // will also be added to `device_pairing_information_` map with an expiry |
| // timeout, and its addition will trigger |
| // `RemoveExpiredDevicesFromStoredDeviceData`, which will remove the |
| // first device since it has expired. |
| PairFastPairDeviceWithClassicBluetooth( |
| /*new_paired_status=*/true, kTestDeviceAddress2); |
| |
| // Trigger a Message Stream event for the first device with the model id and |
| // BLE address. Although there is a check in `CheckPairingInformation`, |
| // the device was already removed in |
| // `RemoveExpiredDevicesFromStoredDeviceData`. |
| SetMessageStream(kModelIdBleAddressBytes); |
| fake_socket_->TriggerReceiveCallback(); |
| NotifyMessageStreamConnected(kTestDeviceAddress); |
| base::RunLoop().RunUntilIdle(); |
| |
| EXPECT_FALSE(retroactive_pair_found_); |
| } |
| |
| TEST_F( |
| RetroactivePairingDetectorTest, |
| DontNotify_ExpiryTimeoutReached_DifferentDeviceTriggerRemoval_DeviceToBeRemovedHashesToSecondPosition) { |
| Login(user_manager::UserType::kRegular); |
| base::test::ScopedFeatureList feature_list; |
| feature_list.InitWithFeatures( |
| /*enabled_features=*/{features::kFastPairSavedDevices}, |
| /*disabled_features=*/{features::kFastPairSavedDevicesStrictOptIn}); |
| fast_pair_repository_->SetOptInStatus( |
| nearby::fastpair::OptInStatus::STATUS_OPTED_OUT); |
| base::RunLoop().RunUntilIdle(); |
| CreateRetroactivePairingDetector(); |
| |
| EXPECT_FALSE(retroactive_pair_found_); |
| |
| // Simulate a first device being found with classic Bluetooth pairing. |
| // At this point, the device is in the `device_pairing_information_` map with |
| // an expiry timestamp. This device does not have a MessageStream associated, |
| // so `CheckPairingInformation` will never be fired because it doesn't have |
| // a model id or BLE event, and thus alone, its expiry event will never be |
| // triggered. |
| // |
| // |kTestDeviceAddress3| hashes to the second position in the map, and we |
| // expect the removing it from the map of devices will not cause a crash |
| // from an invalid iterator when we increment to continue iterating. |
| PairFastPairDeviceWithClassicBluetooth( |
| /*new_paired_status=*/true, kTestDeviceAddress3); |
| |
| // Fast forward by |kRetroactiveDevicePairingTimeout| in order to simulate |
| // that the device's |expiry_timestamp| has been reached. |
| task_environment()->FastForwardBy(kRetroactiveDevicePairingTimeout); |
| |
| // Simulate another device being found for retroactive pairing. This device |
| // will also be added to `device_pairing_information_` map with an expiry |
| // timeout, and its addition will trigger |
| // `RemoveExpiredDevicesFromStoredDeviceData`, which will remove the |
| // first device since it has expired. |
| PairFastPairDeviceWithClassicBluetooth( |
| /*new_paired_status=*/true, kTestDeviceAddress2); |
| |
| // Trigger a Message Stream event for the first device with the model id and |
| // BLE address. Although there is a check in `CheckPairingInformation`, |
| // the device was already removed in |
| // `RemoveExpiredDevicesFromStoredDeviceData`. |
| SetMessageStream(kModelIdBleAddressBytes); |
| fake_socket_->TriggerReceiveCallback(); |
| NotifyMessageStreamConnected(kTestDeviceAddress3); |
| base::RunLoop().RunUntilIdle(); |
| |
| EXPECT_FALSE(retroactive_pair_found_); |
| } |
| |
| TEST_F( |
| RetroactivePairingDetectorTest, |
| DontNotify_ExpiryTimeoutReached_DifferentDeviceTriggerRemoval_MultipleDevicesPaired) { |
| Login(user_manager::UserType::kRegular); |
| base::test::ScopedFeatureList feature_list; |
| feature_list.InitWithFeatures( |
| /*enabled_features=*/{features::kFastPairSavedDevices}, |
| /*disabled_features=*/{features::kFastPairSavedDevicesStrictOptIn}); |
| fast_pair_repository_->SetOptInStatus( |
| nearby::fastpair::OptInStatus::STATUS_OPTED_OUT); |
| base::RunLoop().RunUntilIdle(); |
| CreateRetroactivePairingDetector(); |
| |
| EXPECT_FALSE(retroactive_pair_found_); |
| |
| // Simulate devices being found with classic Bluetooth pairing. |
| // At this point, the devices are in the `device_pairing_information_` map |
| // with an expiry timestamp. This device does not have a MessageStream |
| // associated, so `CheckPairingInformation` will never be fired because it |
| // doesn't have a model id or BLE event, and thus alone, its expiry event will |
| // never be triggered. |
| PairFastPairDeviceWithClassicBluetooth( |
| /*new_paired_status=*/true, kTestDeviceAddress); |
| PairFastPairDeviceWithClassicBluetooth( |
| /*new_paired_status=*/true, kTestDeviceAddress3); |
| |
| // Fast forward by |kRetroactiveDevicePairingTimeout| in order to simulate |
| // that the device's |expiry_timestamp| has been reached. |
| task_environment()->FastForwardBy(kRetroactiveDevicePairingTimeout); |
| |
| // Simulate another device being found for retroactive pairing. This device |
| // will also be added to `device_pairing_information_` map with an expiry |
| // timeout, and its addition will trigger |
| // `RemoveExpiredDevicesFromStoredDeviceData`, which will remove the |
| // first device since it has expired. |
| PairFastPairDeviceWithClassicBluetooth( |
| /*new_paired_status=*/true, kTestDeviceAddress2); |
| |
| // Trigger a Message Stream event for the first device with the model id and |
| // BLE address. Although there is a check in `CheckPairingInformation`, |
| // the device was already removed in |
| // `RemoveExpiredDevicesFromStoredDeviceData`. |
| SetMessageStream(kModelIdBleAddressBytes); |
| fake_socket_->TriggerReceiveCallback(); |
| NotifyMessageStreamConnected(kTestDeviceAddress); |
| base::RunLoop().RunUntilIdle(); |
| |
| EXPECT_FALSE(retroactive_pair_found_); |
| } |
| |
| TEST_F(RetroactivePairingDetectorTest, NotifyAfterDeviceRepairs) { |
| Login(user_manager::UserType::kRegular); |
| base::test::ScopedFeatureList feature_list; |
| feature_list.InitWithFeatures( |
| /*enabled_features=*/{features::kFastPairSavedDevices}, |
| /*disabled_features=*/{features::kFastPairSavedDevicesStrictOptIn}); |
| fast_pair_repository_->SetOptInStatus( |
| nearby::fastpair::OptInStatus::STATUS_OPTED_OUT); |
| CreateRetroactivePairingDetector(); |
| |
| EXPECT_FALSE(retroactive_pair_found_); |
| |
| // Pair a device with classic Bluetooth pairing and set the MessageStream |
| // with model id and BLE address bytes to successfully detect the scenario. |
| // At this point, the device is in the `device_pairing_information_` map with |
| // an expiry timestamp. |
| SetMessageStream(kModelIdBleAddressBytes); |
| PairFastPairDeviceWithClassicBluetooth( |
| /*new_paired_status=*/true, kTestDeviceAddress); |
| |
| // Simulate the device being unpaired, and paired again. |
| PairFastPairDeviceWithClassicBluetooth( |
| /*new_paired_status=*/false, kTestDeviceAddress); |
| PairFastPairDeviceWithClassicBluetooth( |
| /*new_paired_status=*/true, kTestDeviceAddress); |
| |
| // When the model id and BLE address fire, we expect the retroactive pairing |
| // event to still be detected, even if the device was unpaired and repeated. |
| fake_socket_->TriggerReceiveCallback(); |
| NotifyMessageStreamConnected(kTestDeviceAddress); |
| base::RunLoop().RunUntilIdle(); |
| |
| EXPECT_TRUE(retroactive_pair_found_); |
| } |
| |
| TEST_F(RetroactivePairingDetectorTest, NoCrashWhenFootprintsResponseIsSlow) { |
| Login(user_manager::UserType::kRegular); |
| base::test::ScopedFeatureList feature_list; |
| feature_list.InitWithFeatures( |
| /*enabled_features=*/{}, |
| /*disabled_features=*/{features::kFastPairSavedDevices, |
| features::kFastPairSavedDevicesStrictOptIn}); |
| fast_pair_repository_->SetOptInStatus( |
| nearby::fastpair::OptInStatus::STATUS_OPTED_OUT); |
| base::RunLoop().RunUntilIdle(); |
| CreateRetroactivePairingDetector(); |
| EXPECT_FALSE(retroactive_pair_found_); |
| |
| // Delay the response so we can trigger it after OnDevicePaired. |
| fast_pair_repository_->SetIsDeviceSavedToAccountCallbackDelayed( |
| /*is_delayed=*/true); |
| |
| // The naming for these are confusing. |
| // This calls DevicePairedChanged. |
| PairFastPairDeviceWithClassicBluetooth(true, kTestDeviceAddress); |
| |
| // This calls OnDevicePaired. |
| PairFastPairDeviceWithFastPair(kTestDeviceAddress); |
| |
| fake_socket_->TriggerReceiveCallback(); |
| base::RunLoop().RunUntilIdle(); |
| |
| // Add a real message stream so the check passes. |
| AddMessageStream(kModelIdBleAddressBytes); |
| NotifyMessageStreamConnected(kTestDeviceAddress); |
| base::RunLoop().RunUntilIdle(); |
| |
| // Trigger the response. |
| fast_pair_repository_->TriggerIsDeviceSavedToAccountCallback(); |
| } |
| |
| TEST_F(RetroactivePairingDetectorTest, FastPairHID_Success) { |
| Login(user_manager::UserType::kRegular); |
| base::test::ScopedFeatureList feature_list; |
| feature_list.InitWithFeatures( |
| /*enabled_features=*/{features::kFastPairSavedDevices, |
| features::kFastPairSavedDevicesStrictOptIn, |
| features::kFastPairHID, |
| floss::features::kFlossEnabled}, |
| /*disabled_features=*/{}); |
| fast_pair_repository_->SetOptInStatus( |
| nearby::fastpair::OptInStatus::STATUS_OPTED_IN); |
| base::RunLoop().RunUntilIdle(); |
| CreateRetroactivePairingDetector(); |
| |
| EXPECT_FALSE(retroactive_pair_found_); |
| |
| // Test the normal retroactive pair flow of a BLE HID |
| PairFastPairDeviceWithClassicBluetooth( |
| /*new_paired_status=*/true, kBleAddress); |
| SetGattServiceClientConnected(true); |
| RunGattClientInitializedCallback(/*pair_failure=*/std::nullopt); |
| RunReadModelIdCallback(/*error_code=*/std::nullopt, kModelIdBytesNoMetadata); |
| |
| EXPECT_TRUE(retroactive_pair_found_); |
| EXPECT_EQ(retroactive_device_->ble_address(), kBleAddress); |
| EXPECT_EQ(retroactive_device_->metadata_id(), kModelId); |
| } |
| |
| TEST_F(RetroactivePairingDetectorTest, FastPairHID_GattConnectionOpen_Success) { |
| Login(user_manager::UserType::kRegular); |
| base::test::ScopedFeatureList feature_list; |
| feature_list.InitWithFeatures( |
| /*enabled_features=*/{features::kFastPairSavedDevices, |
| features::kFastPairSavedDevicesStrictOptIn, |
| features::kFastPairHID, |
| floss::features::kFlossEnabled}, |
| /*disabled_features=*/{}); |
| fast_pair_repository_->SetOptInStatus( |
| nearby::fastpair::OptInStatus::STATUS_OPTED_IN); |
| base::RunLoop().RunUntilIdle(); |
| CreateRetroactivePairingDetector(); |
| |
| EXPECT_FALSE(retroactive_pair_found_); |
| |
| // If GATT connection already open, we expect a read to Model ID |
| // immediately after. |
| PairFastPairDeviceWithClassicBluetooth( |
| /*new_paired_status=*/true, kBleAddress, |
| /*test_hid_already_connected=*/true); |
| RunReadModelIdCallback(/*error_code*/ std::nullopt, kModelIdBytesNoMetadata); |
| |
| EXPECT_TRUE(retroactive_pair_found_); |
| EXPECT_EQ(retroactive_device_->ble_address(), kBleAddress); |
| EXPECT_EQ(retroactive_device_->metadata_id(), kModelId); |
| } |
| |
| TEST_F(RetroactivePairingDetectorTest, FastPairHID_GattConnectionFailure) { |
| Login(user_manager::UserType::kRegular); |
| base::test::ScopedFeatureList feature_list; |
| feature_list.InitWithFeatures( |
| /*enabled_features=*/{features::kFastPairSavedDevices, |
| features::kFastPairSavedDevicesStrictOptIn, |
| features::kFastPairHID, |
| floss::features::kFlossEnabled}, |
| /*disabled_features=*/{}); |
| fast_pair_repository_->SetOptInStatus( |
| nearby::fastpair::OptInStatus::STATUS_OPTED_IN); |
| base::RunLoop().RunUntilIdle(); |
| CreateRetroactivePairingDetector(); |
| |
| EXPECT_FALSE(retroactive_pair_found_); |
| |
| PairFastPairDeviceWithClassicBluetooth( |
| /*new_paired_status=*/true, kBleAddress); |
| SetGattServiceClientConnected(true); |
| |
| // If we get an error while create the GATT connection, we shouldn't |
| // expect a retroactive pairable device to be found. |
| RunGattClientInitializedCallback(PairFailure::kCreateGattConnection); |
| EXPECT_FALSE(retroactive_pair_found_); |
| } |
| |
| TEST_F(RetroactivePairingDetectorTest, FastPairHID_ReadModelIdFailure) { |
| Login(user_manager::UserType::kRegular); |
| base::test::ScopedFeatureList feature_list; |
| feature_list.InitWithFeatures( |
| /*enabled_features=*/{features::kFastPairSavedDevices, |
| features::kFastPairSavedDevicesStrictOptIn, |
| features::kFastPairHID, |
| floss::features::kFlossEnabled}, |
| /*disabled_features=*/{}); |
| fast_pair_repository_->SetOptInStatus( |
| nearby::fastpair::OptInStatus::STATUS_OPTED_IN); |
| base::RunLoop().RunUntilIdle(); |
| CreateRetroactivePairingDetector(); |
| |
| EXPECT_FALSE(retroactive_pair_found_); |
| |
| PairFastPairDeviceWithClassicBluetooth( |
| /*new_paired_status=*/true, kBleAddress); |
| SetGattServiceClientConnected(true); |
| RunGattClientInitializedCallback(/*pair_failure=*/std::nullopt); |
| |
| // If we get an error while reading model ID, we shouldn't expect a |
| // retroactive pairable device to be found. |
| RunReadModelIdCallback( |
| /*error_code=*/device::BluetoothGattService::GattErrorCode::kNotSupported, |
| kModelIdBytesNoMetadata); |
| EXPECT_FALSE(retroactive_pair_found_); |
| } |
| |
| } // namespace quick_pair |
| } // namespace ash |