chromium/ash/quick_pair/keyed_service/fast_pair_bluetooth_config_delegate.cc

// 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/keyed_service/fast_pair_bluetooth_config_delegate.h"

#include "ash/quick_pair/common/device.h"
#include "ash/quick_pair/repository/fast_pair_repository.h"
#include "ash/quick_pair/repository/fast_pair_repository_impl.h"
#include "base/functional/callback_helpers.h"
#include "chromeos/ash/services/bluetooth_config/device_name_manager.h"
#include "chromeos/ash/services/bluetooth_config/fast_pair_delegate.h"
#include "chromeos/ash/services/bluetooth_config/public/cpp/device_image_info.h"
#include "url/gurl.h"

namespace ash {
namespace quick_pair {

FastPairBluetoothConfigDelegate::FastPairBluetoothConfigDelegate() = default;

FastPairBluetoothConfigDelegate::FastPairBluetoothConfigDelegate(
    Delegate* delegate)
    : delegate_(delegate) {}

FastPairBluetoothConfigDelegate::~FastPairBluetoothConfigDelegate() = default;

std::optional<bluetooth_config::DeviceImageInfo>
FastPairBluetoothConfigDelegate::GetDeviceImageInfo(
    const std::string& mac_address) {
  return FastPairRepository::Get()->GetImagesForDevice(mac_address);
}

void FastPairBluetoothConfigDelegate::ForgetDevice(
    const std::string& mac_address) {
  FastPairRepository::Get()->DeleteAssociatedDevice(mac_address,
                                                    base::DoNothing());
  FastPairRepository::Get()->EvictDeviceImages(mac_address);
}

void FastPairBluetoothConfigDelegate::UpdateDeviceNickname(
    const std::string& mac_address,
    const std::string& nickname) {
  FastPairRepository::Get()->UpdateAssociatedDeviceFootprintsName(
      mac_address, nickname, /*cache_may_be_stale=*/true);
}

void FastPairBluetoothConfigDelegate::SetAdapterStateController(
    bluetooth_config::AdapterStateController* adapter_state_controller) {
  adapter_state_controller_ = adapter_state_controller;
  delegate_->OnAdapterStateControllerChanged(adapter_state_controller_);
}

void FastPairBluetoothConfigDelegate::SetDeviceNameManager(
    bluetooth_config::DeviceNameManager* device_name_manager) {
  device_name_manager_ = device_name_manager;
}

std::vector<bluetooth_config::mojom::PairedBluetoothDevicePropertiesPtr>
FastPairBluetoothConfigDelegate::GetFastPairableDeviceProperties() {
  std::vector<bluetooth_config::mojom::PairedBluetoothDevicePropertiesPtr>
      fast_pairable_device_properties;
  for (const auto& paired_device : fast_pairable_device_properties_) {
    fast_pairable_device_properties.push_back(paired_device.Clone());
  }
  return fast_pairable_device_properties;
}

void FastPairBluetoothConfigDelegate::AddFastPairDevice(
    scoped_refptr<Device> device) {
  // TODO(b/291626339): Make this list alphabetical order.
  fast_pairable_devices_.push_back(device);
  fast_pairable_device_properties_.push_back(ConvertDeviceToProperties(
      device, bluetooth_config::mojom::FastPairableDevicePairingState::kReady));

  // The two lists should always be in sync.
  CHECK_EQ(fast_pairable_devices_.size(),
           fast_pairable_device_properties_.size());

  NotifyFastPairableDevicesChanged(fast_pairable_device_properties_);
}

void FastPairBluetoothConfigDelegate::RemoveFastPairDevice(
    scoped_refptr<Device> device) {
  auto it1 = fast_pairable_devices_.begin();
  auto it2 = fast_pairable_device_properties_.begin();
  while (it1 != fast_pairable_devices_.end()) {
    if (device->metadata_id() == (*it1)->metadata_id()) {
      // The two lists (fast_pairable_devices_ and
      // fast_pairable_device_properties_) are always in sync
      fast_pairable_devices_.erase(it1);
      fast_pairable_device_properties_.erase(it2);
      break;
    }
    ++it1;
    ++it2;
  }

  // The two lists should always be in sync.
  CHECK_EQ(fast_pairable_devices_.size(),
           fast_pairable_device_properties_.size());

  NotifyFastPairableDevicesChanged(fast_pairable_device_properties_);
}

void FastPairBluetoothConfigDelegate::UpdateFastPairableDevicePairingState(
    scoped_refptr<Device> device,
    bluetooth_config::mojom::FastPairableDevicePairingState pairing_state) {
  auto it = fast_pairable_device_properties_.begin();
  while (it != fast_pairable_device_properties_.end()) {
    if (device->ble_address() == (*it)->device_properties->address) {
      (*it)->fast_pairable_device_pairing_state = pairing_state;
      break;
    }
    ++it;
  }

  // The two lists should always be in sync.
  CHECK_EQ(fast_pairable_devices_.size(),
           fast_pairable_device_properties_.size());

  NotifyFastPairableDevicesChanged(fast_pairable_device_properties_);
}

void FastPairBluetoothConfigDelegate::ClearFastPairableDevices() {
  fast_pairable_devices_.clear();
  fast_pairable_device_properties_.clear();

  // The two lists should always be in sync.
  CHECK_EQ(fast_pairable_devices_.size(),
           fast_pairable_device_properties_.size());

  NotifyFastPairableDevicesChanged(fast_pairable_device_properties_);
}

bluetooth_config::mojom::PairedBluetoothDevicePropertiesPtr
FastPairBluetoothConfigDelegate::ConvertDeviceToProperties(
    scoped_refptr<Device> device,
    bluetooth_config::mojom::FastPairableDevicePairingState pairing_state) {
  auto bluetooth_device_properties =
      bluetooth_config::mojom::BluetoothDeviceProperties::New();

  // Using the ble_address since Subsequent Pair Devices don't have a classic
  // address until pairing begins.
  bluetooth_device_properties->address = device->ble_address();

  auto images = GetDeviceImageInfo(device->ble_address());

  bluetooth_config::mojom::DeviceImageInfoPtr device_image_info =
      bluetooth_config::mojom::DeviceImageInfo::New();
  if (!images.has_value()) {
    bluetooth_device_properties->image_info = nullptr;
  } else if (!images->default_image().empty()) {
    GURL default_image_url = GURL(images->default_image());
    DCHECK(default_image_url.is_valid() &&
           default_image_url.SchemeIs(url::kDataScheme));
    device_image_info->default_image_url = default_image_url;
    bluetooth_device_properties->image_info = std::move(device_image_info);
  } else {
    bluetooth_device_properties->image_info = nullptr;
  }

  auto properties =
      bluetooth_config::mojom::PairedBluetoothDeviceProperties::New();
  if (device->display_name().has_value()) {
    properties->nickname = device->display_name();
  }
  properties->fast_pairable_device_pairing_state = pairing_state;
  properties->device_properties = std::move(bluetooth_device_properties);

  return properties;
}

}  // namespace quick_pair
}  // namespace ash