chromium/chromeos/ash/services/quick_pair/public/cpp/battery_notification.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 "chromeos/ash/services/quick_pair/public/cpp/battery_notification.h"

#include <cstdint>
#include <optional>
#include <vector>

#include "base/logging.h"

namespace ash {
namespace quick_pair {

constexpr int kBatteryChargingMask = 0b10000000;
constexpr int kBatteryPercentageMask = 0b01111111;

BatteryInfo::BatteryInfo() = default;

BatteryInfo::BatteryInfo(bool is_charging)
    : is_charging(is_charging), percentage(std::nullopt) {}

BatteryInfo::BatteryInfo(bool is_charging, int8_t percentage)
    : is_charging(is_charging), percentage(percentage) {}

BatteryInfo::BatteryInfo(const BatteryInfo&) = default;

BatteryInfo::BatteryInfo(BatteryInfo&&) = default;

BatteryInfo& BatteryInfo::operator=(const BatteryInfo&) = default;

BatteryInfo& BatteryInfo::operator=(BatteryInfo&&) = default;

BatteryInfo::~BatteryInfo() = default;

// static
BatteryInfo BatteryInfo::FromByte(uint8_t byte) {
  // Battery value is in the form 0bSVVVVVVV.
  // S = charinging (0b1) or not (0b0).
  // V = value, Ranges from 0-100, or 0bS1111111 if unknown.
  bool is_charging = byte & kBatteryChargingMask;
  uint8_t percentage = byte & kBatteryPercentageMask;
  int8_t percentage_signed = static_cast<int8_t>(percentage);

  if (percentage == kBatteryPercentageMask || percentage_signed < 0 ||
      percentage_signed > 100) {
    LOG(WARNING) << "Invalid battery percentage.";
    return BatteryInfo(is_charging);
  } else {
    return BatteryInfo(is_charging, percentage_signed);
  }
}

uint8_t BatteryInfo::ToByte() const {
  // Battery value is in the form 0bSVVVVVVV.
  // S = charinging (0b1) or not (0b0).
  // V = value, Ranges from 0-100, or 1111111 if unknown.
  if (!percentage) {
    return is_charging ? 0b11111111 : 0b01111111;
  } else {
    return percentage.value() | (is_charging ? 0b10000000 : 0);
  }
}

BatteryNotification::BatteryNotification() = default;

BatteryNotification::BatteryNotification(bool show_ui,
                                         BatteryInfo left_bud_info,
                                         BatteryInfo right_bud_info,
                                         BatteryInfo case_info)
    : show_ui(show_ui),
      left_bud_info(std::move(left_bud_info)),
      right_bud_info(std::move(right_bud_info)),
      case_info(std::move(case_info)) {}

BatteryNotification::BatteryNotification(const BatteryNotification&) = default;

BatteryNotification::BatteryNotification(BatteryNotification&&) = default;

BatteryNotification& BatteryNotification::operator=(
    const BatteryNotification&) = default;

BatteryNotification& BatteryNotification::operator=(BatteryNotification&&) =
    default;

BatteryNotification::~BatteryNotification() = default;

// static
std::optional<BatteryNotification> BatteryNotification::FromBytes(
    const std::vector<uint8_t>& bytes,
    bool show_ui) {
  // Expecting 3 bytes - Left bud, Right bud and case.
  if (bytes.size() != 3) {
    LOG(WARNING) << __func__
                 << ": Invalid bytes length. Expected 3, got: " << bytes.size();
    return std::nullopt;
  }

  BatteryInfo left_bud_info = BatteryInfo::FromByte(bytes[0]);
  BatteryInfo right_bud_info = BatteryInfo::FromByte(bytes[1]);
  BatteryInfo case_info = BatteryInfo::FromByte(bytes[2]);

  return std::make_optional<BatteryNotification>(show_ui, left_bud_info,
                                                 right_bud_info, case_info);
}

}  // namespace quick_pair
}  // namespace ash