Skip to content

Commit

Permalink
[Fast Pair] Add API to repository to get saved devices and opt in status
Browse files Browse the repository at this point in the history
Adds an API to the FastPairRepository to get a list of saved devices and
the user's opt in status from Footprints. This differs from the API
added in earlier CL's to get just the opt in status since this will be
used by the Saved Devices page to populate the settings page, whereas
the call that just checks the opt in status is used before we write
an account key.

TEST=unit tests

Change-Id: Ib4c45fcdd508e377412c4a7c01a1ef3b86c1f83b
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3532824
Reviewed-by: Shane Fitzpatrick <shanefitz@google.com>
Commit-Queue: Juliet Lévesque <julietlevesque@google.com>
Cr-Commit-Position: refs/heads/main@{#983502}
  • Loading branch information
julietlevesque authored and Chromium LUCI CQ committed Mar 21, 2022
1 parent 5fe7855 commit d015c4b
Show file tree
Hide file tree
Showing 9 changed files with 138 additions and 2 deletions.
5 changes: 5 additions & 0 deletions ash/quick_pair/repository/fake_fast_pair_repository.cc
Expand Up @@ -111,5 +111,10 @@ FakeFastPairRepository::GetImagesForDevice(const std::string& device_id) {
return absl::nullopt;
}

// Unimplemented.
void FakeFastPairRepository::GetSavedDevices(GetSavedDevicesCallback callback) {

}

} // namespace quick_pair
} // namespace ash
1 change: 1 addition & 0 deletions ash/quick_pair/repository/fake_fast_pair_repository.h
Expand Up @@ -68,6 +68,7 @@ class FakeFastPairRepository : public FastPairRepository {
void DeleteAssociatedDeviceByAccountKey(
const std::vector<uint8_t>& account_key,
DeleteAssociatedDeviceByAccountKeyCallback callback) override;
void GetSavedDevices(GetSavedDevicesCallback callback) override;

private:
static void SetInstance(FastPairRepository* instance);
Expand Down
Expand Up @@ -16,7 +16,7 @@ FakeFootprintsFetcher::FakeFootprintsFetcher() = default;
FakeFootprintsFetcher::~FakeFootprintsFetcher() = default;

void FakeFootprintsFetcher::GetUserDevices(UserReadDevicesCallback callback) {
if (response_.has_value()) {
if (response_set_) {
std::move(callback).Run(std::move(response_));
return;
}
Expand All @@ -33,6 +33,7 @@ void FakeFootprintsFetcher::GetUserDevices(UserReadDevicesCallback callback) {

void FakeFootprintsFetcher::SetGetUserDevicesResponse(
absl::optional<nearby::fastpair::UserReadDevicesResponse> response) {
response_set_ = true;
response_ = response;
}

Expand Down
Expand Up @@ -37,6 +37,7 @@ class FakeFootprintsFetcher : public FootprintsFetcher {

private:
bool add_user_result_ = true;
bool response_set_ = false;
absl::optional<nearby::fastpair::UserReadDevicesResponse> response_;
nearby::fastpair::FastPairInfo opt_in_status_info_;
base::flat_map<std::string, nearby::fastpair::FastPairInfo>
Expand Down
7 changes: 7 additions & 0 deletions ash/quick_pair/repository/fast_pair_repository.h
Expand Up @@ -38,6 +38,9 @@ using CheckOptInStatusCallback =
using UpdateOptInStatusCallback = base::OnceCallback<void(bool)>;
using DeleteAssociatedDeviceByAccountKeyCallback =
base::OnceCallback<void(bool)>;
using GetSavedDevicesCallback = base::OnceCallback<void(
nearby::fastpair::OptInStatus,
std::vector<nearby::fastpair::StoredDiscoveryItem>)>;

// The entry point for the Repository component in the Quick Pair system,
// responsible for connecting to back-end services.
Expand Down Expand Up @@ -105,6 +108,10 @@ class FastPairRepository {
virtual void UpdateOptInStatus(nearby::fastpair::OptInStatus opt_in_status,
UpdateOptInStatusCallback callback) = 0;

// Gets a list of devices saved to the user's account and the user's opt in
// status for saving future devices to their account.
virtual void GetSavedDevices(GetSavedDevicesCallback callback) = 0;

protected:
static void SetInstance(FastPairRepository* instance);
};
Expand Down
40 changes: 40 additions & 0 deletions ash/quick_pair/repository/fast_pair_repository_impl.cc
Expand Up @@ -283,6 +283,46 @@ void FastPairRepositoryImpl::OnUpdateOptInStatusComplete(
std::move(callback).Run(success);
}

void FastPairRepositoryImpl::GetSavedDevices(GetSavedDevicesCallback callback) {
footprints_fetcher_->GetUserDevices(
base::BindOnce(&FastPairRepositoryImpl::OnGetSavedDevices,
weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
}

void FastPairRepositoryImpl::OnGetSavedDevices(
GetSavedDevicesCallback callback,
absl::optional<nearby::fastpair::UserReadDevicesResponse> user_devices) {
QP_LOG(INFO) << __func__;
if (!user_devices) {
QP_LOG(WARNING)
<< __func__
<< ": Missing UserReadDevicesResponse from call to Footprints";
std::move(callback).Run(nearby::fastpair::OptInStatus::STATUS_UNKNOWN, {});
return;
}

nearby::fastpair::OptInStatus opt_in_status =
nearby::fastpair::OptInStatus::STATUS_UNKNOWN;
std::vector<nearby::fastpair::StoredDiscoveryItem> saved_devices;
for (const auto& info : user_devices->fast_pair_info()) {
if (info.has_opt_in_status()) {
opt_in_status = info.opt_in_status();
}

nearby::fastpair::StoredDiscoveryItem device;
if (info.has_device() &&
device.ParseFromString(info.device().discovery_item_bytes())) {
saved_devices.push_back(device);
}
}

// If the opt in status is `STATUS_OPTED_OUT`, then we can expect the list of
// saved devices to be empty, since an opted out status removes all saved
// devices from the list, although there still might be saved devices, if
// an Android or Chromebook writes to the user's account against their wishes.
std::move(callback).Run(opt_in_status, std::move(saved_devices));
}

bool FastPairRepositoryImpl::DeleteAssociatedDevice(
const device::BluetoothDevice* device) {
absl::optional<const std::vector<uint8_t>> account_key =
Expand Down
4 changes: 4 additions & 0 deletions ash/quick_pair/repository/fast_pair_repository_impl.h
Expand Up @@ -74,6 +74,7 @@ class FastPairRepositoryImpl : public FastPairRepository {
void CheckOptInStatus(CheckOptInStatusCallback callback) override;
void UpdateOptInStatus(nearby::fastpair::OptInStatus opt_in_status,
UpdateOptInStatusCallback callback) override;
void GetSavedDevices(GetSavedDevicesCallback callback) override;

private:
void CheckAccountKeysImpl(const AccountKeyFilter& account_key_filter,
Expand Down Expand Up @@ -119,6 +120,9 @@ class FastPairRepositoryImpl : public FastPairRepository {
void OnDeleteAssociatedDeviceByAccountKey(
DeleteAssociatedDeviceByAccountKeyCallback callback,
bool success);
void OnGetSavedDevices(
GetSavedDevicesCallback callback,
absl::optional<nearby::fastpair::UserReadDevicesResponse> user_devices);

std::unique_ptr<DeviceMetadataFetcher> device_metadata_fetcher_;
std::unique_ptr<FootprintsFetcher> footprints_fetcher_;
Expand Down
75 changes: 74 additions & 1 deletion ash/quick_pair/repository/fast_pair_repository_impl_unittest.cc
Expand Up @@ -21,6 +21,7 @@
#include "ash/test/ash_test_base.h"
#include "base/callback_helpers.h"
#include "base/memory/scoped_refptr.h"
#include "base/memory/weak_ptr.h"
#include "base/strings/string_number_conversions.h"
#include "base/test/gmock_callback_support.h"
#include "base/test/mock_callback.h"
Expand Down Expand Up @@ -154,9 +155,17 @@ class FastPairRepositoryImplTest : public AshTestBase {
std::move(on_complete).Run();
}

void GetSavedDevicesCallback(
nearby::fastpair::OptInStatus status,
std::vector<nearby::fastpair::StoredDiscoveryItem> devices) {
status_ = status;
devices_ = devices;
}

protected:
std::unique_ptr<FastPairRepositoryImpl> fast_pair_repository_;

nearby::fastpair::OptInStatus status_;
std::vector<nearby::fastpair::StoredDiscoveryItem> devices_;
scoped_refptr<testing::NiceMock<device::MockBluetoothAdapter>> adapter_;
testing::NiceMock<device::MockBluetoothDevice> ble_bluetooth_device_;
testing::NiceMock<device::MockBluetoothDevice> classic_bluetooth_device_;
Expand All @@ -172,6 +181,8 @@ class FastPairRepositoryImplTest : public AshTestBase {
DeviceIdMap* device_id_map_;
DeviceImageStore* device_image_store_;
SavedDeviceRegistry* saved_device_registry_;

base::WeakPtrFactory<FastPairRepositoryImplTest> weak_ptr_factory_{this};
};

TEST_F(FastPairRepositoryImplTest, GetDeviceMetadata) {
Expand Down Expand Up @@ -439,5 +450,67 @@ TEST_F(FastPairRepositoryImplTest, UpdateOptInStatus_OptedInUpdateFailed) {
fast_pair_repository_->CheckOptInStatus(callback2.Get());
}

TEST_F(FastPairRepositoryImplTest, GetSavedDevices_OptedIn) {
fast_pair_repository_->UpdateOptInStatus(
nearby::fastpair::OptInStatus::STATUS_OPTED_IN, base::DoNothing());
base::RunLoop().RunUntilIdle();
AccountKeyFilter filter(kFilterBytes1, {salt});
nearby::fastpair::GetObservedDeviceResponse response;
DeviceMetadata metadata(response, gfx::Image());

auto device = base::MakeRefCounted<Device>(kValidModelId, kTestBLEAddress,
Protocol::kFastPairInitial);
device->set_classic_address(kTestClassicAddress);
fast_pair_repository_->AssociateAccountKey(device, kAccountKey1);
base::RunLoop().RunUntilIdle();
ASSERT_TRUE(footprints_fetcher_->ContainsKey(kAccountKey1));
base::RunLoop().RunUntilIdle();

fast_pair_repository_->GetSavedDevices(
base::BindOnce(&FastPairRepositoryImplTest::GetSavedDevicesCallback,
weak_ptr_factory_.GetWeakPtr()));
base::RunLoop().RunUntilIdle();

EXPECT_EQ(nearby::fastpair::OptInStatus::STATUS_OPTED_IN, status_);
EXPECT_EQ(1u, devices_.size());
}

TEST_F(FastPairRepositoryImplTest, GetSavedDevices_OptedOut) {
fast_pair_repository_->UpdateOptInStatus(
nearby::fastpair::OptInStatus::STATUS_OPTED_OUT, base::DoNothing());
base::RunLoop().RunUntilIdle();
fast_pair_repository_->GetSavedDevices(
base::BindOnce(&FastPairRepositoryImplTest::GetSavedDevicesCallback,
weak_ptr_factory_.GetWeakPtr()));
base::RunLoop().RunUntilIdle();

EXPECT_EQ(nearby::fastpair::OptInStatus::STATUS_OPTED_OUT, status_);
EXPECT_EQ(0u, devices_.size());
}

TEST_F(FastPairRepositoryImplTest, GetSavedDevices_OptStatusUnknown) {
fast_pair_repository_->UpdateOptInStatus(
nearby::fastpair::OptInStatus::STATUS_UNKNOWN, base::DoNothing());
base::RunLoop().RunUntilIdle();
fast_pair_repository_->GetSavedDevices(
base::BindOnce(&FastPairRepositoryImplTest::GetSavedDevicesCallback,
weak_ptr_factory_.GetWeakPtr()));
base::RunLoop().RunUntilIdle();

EXPECT_EQ(nearby::fastpair::OptInStatus::STATUS_UNKNOWN, status_);
EXPECT_EQ(0u, devices_.size());
}

TEST_F(FastPairRepositoryImplTest, GetSavedDevices_MissingResponse) {
footprints_fetcher_->SetGetUserDevicesResponse(absl::nullopt);
fast_pair_repository_->GetSavedDevices(
base::BindOnce(&FastPairRepositoryImplTest::GetSavedDevicesCallback,
weak_ptr_factory_.GetWeakPtr()));
base::RunLoop().RunUntilIdle();

EXPECT_EQ(nearby::fastpair::OptInStatus::STATUS_UNKNOWN, status_);
EXPECT_EQ(0u, devices_.size());
}

} // namespace quick_pair
} // namespace ash
4 changes: 4 additions & 0 deletions ash/quick_pair/repository/mock_fast_pair_repository.h
Expand Up @@ -69,6 +69,10 @@ class MockFastPairRepository : public FastPairRepository {
(const std::vector<uint8_t>& account_key,
DeleteAssociatedDeviceByAccountKeyCallback callback),
(override));
MOCK_METHOD(void,
GetSavedDevices,
(GetSavedDevicesCallback callback),
(override));
};

} // namespace quick_pair
Expand Down

0 comments on commit d015c4b

Please sign in to comment.