// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/performance_manager/power/battery_level_provider_chromeos.h"
#include <optional>
#include "chromeos/dbus/power/power_manager_client.h"
#include "chromeos/dbus/power_manager/power_supply_properties.pb.h"
namespace performance_manager::power {
const double kmAhPerAh = 1000.0;
BatteryLevelProviderChromeOS::BatteryLevelProviderChromeOS(
chromeos::PowerManagerClient* power_manager_client)
: power_manager_client_(power_manager_client) {
DCHECK(power_manager_client_);
}
BatteryLevelProviderChromeOS::~BatteryLevelProviderChromeOS() = default;
// static
std::unique_ptr<base::BatteryLevelProvider>
BatteryLevelProviderChromeOS::Create() {
return std::make_unique<
performance_manager::power::BatteryLevelProviderChromeOS>(
chromeos::PowerManagerClient::Get());
}
void BatteryLevelProviderChromeOS::GetBatteryState(
base::OnceCallback<
void(const std::optional<base::BatteryLevelProvider::BatteryState>&)>
callback) {
DCHECK(power_manager_client_);
const std::optional<power_manager::PowerSupplyProperties>& power_status =
power_manager_client_->GetLastStatus();
if (!power_status) {
std::move(callback).Run(std::nullopt);
return;
}
base::BatteryLevelProvider::BatteryState state;
if (power_status->battery_state() ==
power_manager::PowerSupplyProperties::NOT_PRESENT) {
state = {
.battery_count = 0,
.is_external_power_connected = true,
.current_capacity = std::nullopt,
.full_charged_capacity = std::nullopt,
.charge_unit = std::nullopt,
// TODO(anthonyvd): This should be the time that the state was last
// sampled from the system, but PowerManagerClient doesn't yet provide
// this information.
.capture_time = base::TimeTicks::Now(),
};
} else {
bool has_charge_in_ah = power_status->has_battery_charge() &&
power_status->has_battery_charge_full();
bool has_charge_in_percent = power_status->has_battery_percent();
std::optional<uint64_t> charge;
std::optional<uint64_t> charge_full;
std::optional<base::BatteryLevelProvider::BatteryLevelUnit> charge_unit =
std::nullopt;
// There are 3 ways the power manager could report the battery capacity,
// affecting how the battery state will be constructed. In order of
// preference:
//
// 1- Power Manager reports the charge in Ah, and reports voltage. We report
// the capacity in mWh.
//
// 2- Power Manager reports the charge in Ah, and does not report voltage.
// We report the capacity in mAh.
//
// 3- Power Manager reports the charge as a percentage. We report the charge
// as relative (percentage).
if (has_charge_in_ah) {
if (power_status->has_battery_voltage()) {
charge = power_status->battery_charge() * kmAhPerAh *
power_status->battery_voltage();
charge_full = power_status->battery_charge_full() * kmAhPerAh *
power_status->battery_voltage();
charge_unit = base::BatteryLevelProvider::BatteryLevelUnit::kMWh;
} else {
charge = power_status->battery_charge() * kmAhPerAh;
charge_full = power_status->battery_charge_full() * kmAhPerAh;
charge_unit = base::BatteryLevelProvider::BatteryLevelUnit::kMAh;
}
} else if (has_charge_in_percent) {
charge = power_status->battery_percent();
charge_full = 100;
charge_unit = base::BatteryLevelProvider::BatteryLevelUnit::kRelative;
}
state = {
.battery_count = 1,
.is_external_power_connected =
power_status->external_power() !=
power_manager::PowerSupplyProperties::DISCONNECTED,
.current_capacity = charge,
.full_charged_capacity = charge_full,
.charge_unit = charge_unit,
// TODO(anthonyvd): This should be the time that the state was last
// sampled from the system, but PowerManagerClient doesn't yet provide
// this information.
.capture_time = base::TimeTicks::Now(),
};
}
std::move(callback).Run(state);
}
} // namespace performance_manager::power