chromium/ash/quick_pair/keyed_service/battery_update_message_handler.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/battery_update_message_handler.h"

#include "base/containers/adapters.h"
#include "base/containers/contains.h"
#include "base/functional/bind.h"
#include "base/functional/callback.h"
#include "components/cross_device/logging/logging.h"
#include "device/bluetooth/bluetooth_adapter.h"
#include "device/bluetooth/bluetooth_adapter_factory.h"
#include "device/bluetooth/bluetooth_device.h"

namespace {

device::BluetoothDevice::BatteryInfo GetBatteryInfo(
    const ash::quick_pair::mojom::BatteryInfoPtr& battery_info,
    const device::BluetoothDevice::BatteryType& battery_type) {
  if (battery_info->percentage == -1) {
    return device::BluetoothDevice::BatteryInfo(
        battery_type,
        /*percentage=*/std::nullopt,
        battery_info->is_charging
            ? device::BluetoothDevice::BatteryInfo::ChargeState::kCharging
            : device::BluetoothDevice::BatteryInfo::ChargeState::kDischarging);
  }

  return device::BluetoothDevice::BatteryInfo(
      battery_type, battery_info->percentage,
      battery_info->is_charging
          ? device::BluetoothDevice::BatteryInfo::ChargeState::kCharging
          : device::BluetoothDevice::BatteryInfo::ChargeState::kDischarging);
}

}  // namespace

namespace ash {
namespace quick_pair {

BatteryUpdateMessageHandler::BatteryUpdateMessageHandler(
    MessageStreamLookup* message_stream_lookup) {
  device::BluetoothAdapterFactory::Get()->GetAdapter(
      base::BindOnce(&BatteryUpdateMessageHandler::OnGetAdapter,
                     weak_ptr_factory_.GetWeakPtr()));
  message_stream_lookup_observation_.Observe(message_stream_lookup);
}

void BatteryUpdateMessageHandler::OnGetAdapter(
    scoped_refptr<device::BluetoothAdapter> adapter) {
  adapter_ = adapter;
}

BatteryUpdateMessageHandler::~BatteryUpdateMessageHandler() {
  // Remove any observation of remaining MessageStreams.
  for (auto it = message_streams_.begin(); it != message_streams_.end(); it++) {
    it->second->RemoveObserver(this);
  }
}

void BatteryUpdateMessageHandler::OnMessageStreamConnected(
    const std::string& device_address,
    MessageStream* message_stream) {
  if (!message_stream)
    return;

  message_stream->AddObserver(this);
  message_streams_[device_address] = message_stream;
  GetBatteryUpdateFromMessageStream(device_address, message_stream);
}

void BatteryUpdateMessageHandler::GetBatteryUpdateFromMessageStream(
    const std::string& device_address,
    MessageStream* message_stream) {
  DCHECK(message_stream);

  // Iterate over messages for battery update if it already exists.
  for (const auto& message : base::Reversed(message_stream->messages())) {
    if (message->is_battery_update()) {
      SetBatteryInfo(device_address, message->get_battery_update());
      return;
    }
  }
}

void BatteryUpdateMessageHandler::OnBatteryUpdateMessage(
    const std::string& device_address,
    const mojom::BatteryUpdatePtr& battery_update) {
  SetBatteryInfo(device_address, battery_update);
}

void BatteryUpdateMessageHandler::OnDisconnected(
    const std::string& device_address) {
  CleanUpMessageStream(device_address);
}

void BatteryUpdateMessageHandler::OnMessageStreamDestroyed(
    const std::string& device_address) {
  CleanUpMessageStream(device_address);
}

void BatteryUpdateMessageHandler::SetBatteryInfo(
    const std::string& device_address,
    const mojom::BatteryUpdatePtr& battery_update) {
  device::BluetoothDevice* device = adapter_->GetDevice(device_address);
  if (!device) {
    CD_LOG(INFO, Feature::FP)
        << "Device lost from adapter before battery info was set.";
    CleanUpMessageStream(device_address);
    return;
  }

  device::BluetoothDevice::BatteryInfo left_bud_info =
      GetBatteryInfo(/*battery_info=*/battery_update->left_bud_info,
                     /*battery_type=*/device::BluetoothDevice::BatteryType::
                         kLeftBudTrueWireless);
  device->SetBatteryInfo(left_bud_info);

  device::BluetoothDevice::BatteryInfo right_bud_info =
      GetBatteryInfo(/*battery_info=*/battery_update->right_bud_info,
                     /*battery_type=*/device::BluetoothDevice::BatteryType::
                         kRightBudTrueWireless);
  device->SetBatteryInfo(right_bud_info);

  device::BluetoothDevice::BatteryInfo case_info = GetBatteryInfo(
      /*battery_info=*/battery_update->case_info,
      /*battery_type=*/device::BluetoothDevice::BatteryType::kCaseTrueWireless);
  device->SetBatteryInfo(case_info);
}

void BatteryUpdateMessageHandler::CleanUpMessageStream(
    const std::string& device_address) {
  if (!base::Contains(message_streams_, device_address)) {
    return;
  }

  message_streams_[device_address]->RemoveObserver(this);
  message_streams_.erase(device_address);
}

}  // namespace quick_pair
}  // namespace ash